mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-22 16:36:15 -04:00
Merge branch 'release/1.2.91'
This commit is contained in:
commit
069319fda1
68 changed files with 1392 additions and 674 deletions
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -1,3 +1,27 @@
|
||||||
|
# 1.2.91
|
||||||
|
* NEW: Authors can now send custom object messages to other Authors making 3 way conversations possible. This introduces WebRTC plugin support.
|
||||||
|
* NEW: Hook for Chat Messages Allows for Desktop Notification support
|
||||||
|
* NEW: FreeBSD installation docs
|
||||||
|
* NEW: Ctrl S for save revision makes the Icon glow for a few sconds.
|
||||||
|
* NEW: Various hooks and expose the document ACE object
|
||||||
|
* NEW: Plugin page revamp makes finding and installing plugins more sane.
|
||||||
|
* NEW: Icon to enable sticky chat from the Chat box
|
||||||
|
* Fix: Cookies inside of plugins
|
||||||
|
* Fix: Don't leak event emitters when accessing admin/plugins
|
||||||
|
* Fix: Don't allow user to send messages after they have been "kicked" from a pad
|
||||||
|
* Fix: Refactor Caret navigation with Arrow and Pageup/down keys stops cursor being lost
|
||||||
|
* Fix: Long lines in Firefox now wrap properly
|
||||||
|
* Fix: Session Disconnect limit is increased from 10 to 20 to support slower restarts
|
||||||
|
* Fix: Support Node 0.10
|
||||||
|
* Fix: Log HTTP on DEBUG log level
|
||||||
|
* Fix: Server wont crash on import fails on 0 file import.
|
||||||
|
* Fix: Import no longer fails consistantly
|
||||||
|
* Fix: Language support for non existing languages
|
||||||
|
* Fix: Mobile support for chat notifications are now usable
|
||||||
|
* Fix: Re-Enable Editbar buttons on reconnect
|
||||||
|
* Fix: Clearing authorship colors no longer disconnects all clients
|
||||||
|
* Other: New debug information for sessions
|
||||||
|
|
||||||
# 1.2.9
|
# 1.2.9
|
||||||
* Fix: MAJOR Security issue, where a hacker could submit content as another user
|
* Fix: MAJOR Security issue, where a hacker could submit content as another user
|
||||||
* Fix: security issue due to unescaped user input
|
* Fix: security issue due to unescaped user input
|
||||||
|
@ -6,7 +30,7 @@
|
||||||
* Fix: PadUsers API endpoint
|
* Fix: PadUsers API endpoint
|
||||||
* NEW: A script to import data to all dbms
|
* NEW: A script to import data to all dbms
|
||||||
* NEW: Add authorId to chat and userlist as a data attribute
|
* NEW: Add authorId to chat and userlist as a data attribute
|
||||||
* NEW Refactor and fix our frontend tests
|
* NEW: Refactor and fix our frontend tests
|
||||||
* NEW: Localisation updates
|
* NEW: Localisation updates
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ To make sure everybody is going in the same direction:
|
||||||
* easy to install for admins and easy to use for people
|
* easy to install for admins and easy to use for people
|
||||||
* easy to integrate into other apps, but also usable as standalone
|
* easy to integrate into other apps, but also usable as standalone
|
||||||
* using less resources on server side
|
* using less resources on server side
|
||||||
* extensible, as much functionality should be extendable with plugins so changes don't have to be done in core
|
* extensible, as much functionality should be extendable with plugins so changes don't have to be done in core.
|
||||||
Also, keep it maintainable. We don't wanna end ob as the monster Etherpad was!
|
Also, keep it maintainable. We don't wanna end up as the monster Etherpad was!
|
||||||
|
|
||||||
## How to work with git?
|
## How to work with git?
|
||||||
* Don't work in your master branch.
|
* Don't work in your master branch.
|
||||||
|
|
54
README.md
54
README.md
|
@ -1,36 +1,19 @@
|
||||||
# Making collaborative editing the standard on the web
|
# A really-real time collaborative word processor for the web
|
||||||
|

|
||||||
|
|
||||||
# About
|
# About
|
||||||
Etherpad lite is a really-real time collaborative editor spawned from the Hell fire of Etherpad.
|
Etherpad is a really-real time collaborative editor maintained by the Etherpad Community.
|
||||||
We're reusing the well tested Etherpad easysync library to make it really realtime. Etherpad Lite
|
|
||||||
is based on node.js ergo is much lighter and more stable than the original Etherpad. Our hope
|
|
||||||
is that this will encourage more users to use and install a realtime collaborative editor. A smaller, manageable and well
|
|
||||||
documented codebase makes it easier for developers to improve the code and contribute towards the project.
|
|
||||||
|
|
||||||
**Etherpad vs Etherpad lite**
|
Etherpad is written in Javascript(99.9%) on both the server and client so it's easy for developers to maintain and add new features. Because of this Etherpad has tons of customizations that you can leverage.
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td> </td><td><b>Etherpad</b></td><td><b>Etherpad Lite</b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="right">Size of the folder (without git history)</td><td>30 MB</td><td>1.5 MB</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="right">Languages used server side</td><td>Javascript (Rhino), Java, Scala</td><td>Javascript (node.js)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="right">Lines of server side Javascript code</td><td>~101k</td><td>~9k</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="right">RAM Usage immediately after start</td><td>257 MB (grows to ~1GB)</td><td>16 MB (grows to ~30MB)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
Etherpad is designed to be easily embeddable and provides a [HTTP API](https://github.com/ether/etherpad-lite/wiki/HTTP-API)
|
||||||
|
that allows your web application to manage pads, users and groups. It is recommended to use the [available client implementations](https://github.com/ether/etherpad-lite/wiki/HTTP-API-client-libraries) in order to interact with this API.
|
||||||
|
|
||||||
Etherpad Lite is designed to be easily embeddable and provides a [HTTP API](https://github.com/ether/etherpad-lite/wiki/HTTP-API)
|
There is also a [jQuery plugin](https://github.com/ether/etherpad-lite-jquery-plugin) that helps you to embed Pads into your website.
|
||||||
that allows your web application to manage pads, users and groups. It is recommended to use the [available client implementations](https://github.com/ether/etherpad-lite/wiki/HTTP-API-client-libraries) in order to interact with this API. There is also a [jQuery plugin](https://github.com/ether/etherpad-lite-jquery-plugin) that helps you to embed Pads into your website.
|
|
||||||
There's also a full-featured plugin framework, allowing you to easily add your own features.
|
There's also a full-featured plugin framework, allowing you to easily add your own features. By default your Etherpad is rather sparce and because Etherpad takes a lot of it's inspiration from Wordpress plugins are really easy to install and update. Once you have Etherpad installed you should visit the plugin page and take control.
|
||||||
Finally, Etherpad Lite comes with translations into tons of different languages!
|
|
||||||
|
Finally, Etherpad comes with translations into most languages! Users are automatically delivered the correct language for their local settings.
|
||||||
|
|
||||||
**Visit [beta.etherpad.org](http://beta.etherpad.org) to test it live**
|
**Visit [beta.etherpad.org](http://beta.etherpad.org) to test it live**
|
||||||
|
|
||||||
|
@ -38,6 +21,8 @@ Also, check out the **[FAQ](https://github.com/ether/etherpad-lite/wiki/FAQ)**,
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
|
Etherpad works with node v0.8 and v0.10, only. (We don't suppot v0.6)
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|
||||||
### Prebuilt windows package
|
### Prebuilt windows package
|
||||||
|
@ -62,10 +47,11 @@ Update to the latest version with `git pull origin`, then run `bin\installOnWind
|
||||||
|
|
||||||
[Next steps](#next-steps).
|
[Next steps](#next-steps).
|
||||||
|
|
||||||
## Linux
|
## GNU/Linux and other UNIX-like systems
|
||||||
You'll need gzip, git, curl, libssl develop libraries, python and gcc.
|
You'll need gzip, git, curl, libssl develop libraries, python and gcc.
|
||||||
*For Debian/Ubuntu*: `apt-get install gzip git-core curl python libssl-dev pkg-config build-essential`
|
*For Debian/Ubuntu*: `apt-get install gzip git-core curl python libssl-dev pkg-config build-essential`
|
||||||
*For Fedora/CentOS*: `yum install gzip git-core curl python openssl-devel && yum groupinstall "Development Tools"`
|
*For Fedora/CentOS*: `yum install gzip git-core curl python openssl-devel && yum groupinstall "Development Tools"`
|
||||||
|
*For FreeBSD*: `portinstall node node, npm and git (optional)`
|
||||||
|
|
||||||
Additionally, you'll need [node.js](http://nodejs.org) installed, Ideally the latest stable version, be careful of installing nodejs from apt.
|
Additionally, you'll need [node.js](http://nodejs.org) installed, Ideally the latest stable version, be careful of installing nodejs from apt.
|
||||||
|
|
||||||
|
@ -83,9 +69,9 @@ You like it? [Next steps](#next-steps).
|
||||||
# Next Steps
|
# Next Steps
|
||||||
|
|
||||||
## Tweak the settings
|
## Tweak the settings
|
||||||
You can modify the settings in `settings.json`. (If you need to handle multiple settings files, you can pass the path to a settings file to `bin/run.sh` using the `-s|--settings` option. This allows you to run multiple Etherpad Lite instances from the same installation.)
|
You can initially modify the settings in `settings.json`. (If you need to handle multiple settings files, you can pass the path to a settings file to `bin/run.sh` using the `-s|--settings` option. This allows you to run multiple Etherpad instances from the same installation.) Once you have access to your /admin section settings can be modified through the web browser.
|
||||||
|
|
||||||
You should use a dedicated database such as "mysql", if you are planning on using etherpad-lite in a production environment, since the "dirtyDB" database driver is only for testing and/or development purposes.
|
You should use a dedicated database such as "mysql", if you are planning on using etherpad-in a production environment, since the "dirtyDB" database driver is only for testing and/or development purposes.
|
||||||
|
|
||||||
## Helpful resources
|
## Helpful resources
|
||||||
The [wiki](https://github.com/ether/etherpad-lite/wiki) is your one-stop resource for Tutorials and How-to's, really check it out! Also, feel free to improve these wiki pages.
|
The [wiki](https://github.com/ether/etherpad-lite/wiki) is your one-stop resource for Tutorials and How-to's, really check it out! Also, feel free to improve these wiki pages.
|
||||||
|
@ -95,11 +81,11 @@ Documentation can be found in `docs/`.
|
||||||
# Development
|
# Development
|
||||||
|
|
||||||
## Things you should know
|
## Things you should know
|
||||||
Read this [git guide](http://learn.github.com/p/intro.html) and watch this [video on getting started with Etherpad Lite Development](http://youtu.be/67-Q26YH97E).
|
Read this [git guide](http://learn.github.com/p/intro.html) and watch this [video on getting started with Etherpad Development](http://youtu.be/67-Q26YH97E).
|
||||||
|
|
||||||
If you're new to node.js, start with Ryan Dahl's [Introduction to Node.js](http://youtu.be/jo_B4LTHi3I).
|
If you're new to node.js, start with Ryan Dahl's [Introduction to Node.js](http://youtu.be/jo_B4LTHi3I).
|
||||||
|
|
||||||
You can debug Etherpad lite using `bin/debugRun.sh`.
|
You can debug Etherpad using `bin/debugRun.sh`.
|
||||||
|
|
||||||
If you want to find out how Etherpad's `Easysync` works (the library that makes it really realtime), start with this [PDF](https://github.com/ether/etherpad-lite/raw/master/doc/easysync/easysync-full-description.pdf) (complex, but worth reading).
|
If you want to find out how Etherpad's `Easysync` works (the library that makes it really realtime), start with this [PDF](https://github.com/ether/etherpad-lite/raw/master/doc/easysync/easysync-full-description.pdf) (complex, but worth reading).
|
||||||
|
|
||||||
|
@ -111,7 +97,7 @@ Look at the [TODO list](https://github.com/ether/etherpad-lite/wiki/TODO) and ou
|
||||||
Also, and most importantly, read our [**Developer Guidelines**](https://github.com/ether/etherpad-lite/blob/master/CONTRIBUTING.md), really!
|
Also, and most importantly, read our [**Developer Guidelines**](https://github.com/ether/etherpad-lite/blob/master/CONTRIBUTING.md), really!
|
||||||
|
|
||||||
# Get in touch
|
# Get in touch
|
||||||
Join the [mailinglist](http://groups.google.com/group/etherpad-lite-dev) and make some noise on our freenode irc channel [#etherpad-lite-dev](http://webchat.freenode.net?channels=#etherpad-lite-dev)!
|
Join the [mailinglist](http://groups.google.com/group/etherpad-lite-dev) and make some noise on our busy freenode irc channel [#etherpad-lite-dev](http://webchat.freenode.net?channels=#etherpad-lite-dev)!
|
||||||
|
|
||||||
# Modules created for this project
|
# Modules created for this project
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,8 @@ fi
|
||||||
#check node version
|
#check node version
|
||||||
NODE_VERSION=$(node --version)
|
NODE_VERSION=$(node --version)
|
||||||
NODE_V_MINOR=$(echo $NODE_VERSION | cut -d "." -f 1-2)
|
NODE_V_MINOR=$(echo $NODE_VERSION | cut -d "." -f 1-2)
|
||||||
if [ ! $NODE_V_MINOR = "v0.8" ] && [ ! $NODE_V_MINOR = "v0.6" ]; then
|
if [ ! $NODE_V_MINOR = "v0.8" ] && [ ! $NODE_V_MINOR = "v0.10" ]; then
|
||||||
echo "You're running a wrong version of node, you're using $NODE_VERSION, we need v0.6.x or v0.8.x" >&2
|
echo "You're running a wrong version of node, you're using $NODE_VERSION, we need v0.8.x or v0.10.x" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ cmd /C node -e "" || ( echo "Please install node.js ( http://nodejs.org )" && ex
|
||||||
|
|
||||||
echo _
|
echo _
|
||||||
echo Checking node version...
|
echo Checking node version...
|
||||||
set check_version="if(['6','8'].indexOf(process.version.split('.')[1].toString()) === -1) { console.log('You are running a wrong version of Node. Etherpad Lite requires v0.6.x or v0.8.x'); process.exit(1) }"
|
set check_version="if(['8','10'].indexOf(process.version.split('.')[1].toString()) === -1) { console.log('You are running a wrong version of Node. Etherpad Lite requires v0.8.x or v0.10.x'); process.exit(1) }"
|
||||||
cmd /C node -e %check_version% || exit /B 1
|
cmd /C node -e %check_version% || exit /B 1
|
||||||
|
|
||||||
echo _
|
echo _
|
||||||
|
|
|
@ -143,6 +143,20 @@ Things in context:
|
||||||
|
|
||||||
This hook is called on the client side whenever a user joins or changes. This can be used to create notifications or an alternate user list.
|
This hook is called on the client side whenever a user joins or changes. This can be used to create notifications or an alternate user list.
|
||||||
|
|
||||||
|
## chatNewMessage
|
||||||
|
Called from: src/static/js/chat.js
|
||||||
|
|
||||||
|
Things in context:
|
||||||
|
|
||||||
|
1. authorName - The user that wrote this message
|
||||||
|
2. author - The authorID of the user that wrote the message
|
||||||
|
2. text - the message text
|
||||||
|
3. sticky (boolean) - if you want the gritter notification bubble to fade out on its own or just sit there
|
||||||
|
3. timestamp - the timestamp of the chat message
|
||||||
|
4. timeStr - the timestamp as a formatted string
|
||||||
|
|
||||||
|
This hook is called on the client side whenever a chat message is received from the server. It can be used to create different notifications for chat messages.
|
||||||
|
|
||||||
## collectContentPre
|
## collectContentPre
|
||||||
Called from: src/static/js/contentcollector.js
|
Called from: src/static/js/contentcollector.js
|
||||||
|
|
||||||
|
|
|
@ -458,4 +458,4 @@ returns ok when the current api token is valid
|
||||||
lists all pads on this epl instance
|
lists all pads on this epl instance
|
||||||
|
|
||||||
*Example returns:*
|
*Example returns:*
|
||||||
* `{code: 0, message:"ok", data: ["testPad", "thePadsOfTheOthers"]}`
|
* `{code: 0, message:"ok", data: {padIDs: ["testPad", "thePadsOfTheOthers"]}}`
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Llimpiar los colores d'autor\u00eda",
|
"pad.toolbar.clearAuthorship.title": "Llimpiar los colores d'autor\u00eda",
|
||||||
"pad.toolbar.import_export.title": "Importar\/Esportar ente distintos formatos de ficheru",
|
"pad.toolbar.import_export.title": "Importar\/Esportar ente distintos formatos de ficheru",
|
||||||
"pad.toolbar.timeslider.title": "Eslizador de tiempu",
|
"pad.toolbar.timeslider.title": "Eslizador de tiempu",
|
||||||
"pad.toolbar.savedRevision.title": "Revisiones guardaes",
|
"pad.toolbar.savedRevision.title": "Guardar revisi\u00f3n",
|
||||||
"pad.toolbar.settings.title": "Configuraci\u00f3n",
|
"pad.toolbar.settings.title": "Configuraci\u00f3n",
|
||||||
"pad.toolbar.embed.title": "Incrustar esti bloc",
|
"pad.toolbar.embed.title": "Incrustar esti bloc",
|
||||||
"pad.toolbar.showusers.title": "Amosar los usuarios d'esti bloc",
|
"pad.toolbar.showusers.title": "Amosar los usuarios d'esti bloc",
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "Alderique en pantalla siempres",
|
"pad.settings.stickychat": "Alderique en pantalla siempres",
|
||||||
"pad.settings.colorcheck": "Colores d'autor\u00eda",
|
"pad.settings.colorcheck": "Colores d'autor\u00eda",
|
||||||
"pad.settings.linenocheck": "N\u00famberos de llinia",
|
"pad.settings.linenocheck": "N\u00famberos de llinia",
|
||||||
|
"pad.settings.rtlcheck": "\u00bfLleer el conten\u00edu de drecha a izquierda?",
|
||||||
"pad.settings.fontType": "Tipograf\u00eda:",
|
"pad.settings.fontType": "Tipograf\u00eda:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Monoespaciada",
|
"pad.settings.fontType.monospaced": "Monoespaciada",
|
||||||
|
|
61
src/locales/be-tarask.json
Normal file
61
src/locales/be-tarask.json
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Jim-by",
|
||||||
|
"Wizardist"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"index.newPad": "\u0421\u0442\u0432\u0430\u0440\u044b\u0446\u044c",
|
||||||
|
"index.createOpenPad": "\u0446\u0456 \u0442\u0432\u0430\u0440\u044b\u0446\u044c\/\u0430\u0434\u043a\u0440\u044b\u0446\u044c \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442 \u0437 \u043d\u0430\u0437\u0432\u0430\u0439:",
|
||||||
|
"pad.toolbar.bold.title": "\u0422\u043e\u045e\u0441\u0442\u044b (Ctrl-B)",
|
||||||
|
"pad.toolbar.italic.title": "\u041a\u0443\u0440\u0441\u0456\u045e (Ctrl-I)",
|
||||||
|
"pad.toolbar.underline.title": "\u041f\u0430\u0434\u043a\u0440\u044d\u0441\u044c\u043b\u0456\u0432\u0430\u043d\u044c\u043d\u0435 (Ctrl-U)",
|
||||||
|
"pad.toolbar.strikethrough.title": "\u0417\u0430\u043a\u0440\u044d\u0441\u044c\u043b\u0456\u0432\u0430\u043d\u044c\u043d\u0435",
|
||||||
|
"pad.toolbar.ol.title": "\u0423\u043f\u0430\u0440\u0430\u0434\u043a\u0430\u0432\u0430\u043d\u044b \u0441\u044c\u043f\u0456\u0441",
|
||||||
|
"pad.toolbar.ul.title": "\u041d\u0435\u045e\u043f\u0430\u0440\u0430\u0434\u043a\u0430\u0432\u0430\u043d\u044b \u0441\u044c\u043f\u0456\u0441",
|
||||||
|
"pad.toolbar.indent.title": "\u0412\u043e\u0434\u0441\u0442\u0443\u043f",
|
||||||
|
"pad.toolbar.unindent.title": "\u0412\u044b\u0441\u0442\u0443\u043f",
|
||||||
|
"pad.toolbar.undo.title": "\u0421\u043a\u0430\u0441\u0430\u0432\u0430\u0446\u044c(Ctrl-Z)",
|
||||||
|
"pad.toolbar.redo.title": "\u0412\u044f\u0440\u043d\u0443\u0446\u044c (Ctrl-Y)",
|
||||||
|
"pad.toolbar.clearAuthorship.title": "\u041f\u0440\u044b\u0431\u0440\u0430\u0446\u044c \u043a\u043e\u043b\u0435\u0440 \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442\u0443",
|
||||||
|
"pad.toolbar.import_export.title": "\u0406\u043c\u043f\u0430\u0440\u0442\/\u042d\u043a\u0441\u043f\u0430\u0440\u0442 \u0437 \u0432\u044b\u043a\u0430\u0440\u044b\u0441\u0442\u0430\u043d\u044c\u043d\u0435 \u0440\u043e\u0437\u043d\u044b\u0445 \u0444\u0430\u0440\u043c\u0430\u0442\u0430\u045e \u0444\u0430\u0439\u043b\u0430\u045e",
|
||||||
|
"pad.toolbar.timeslider.title": "\u0428\u043a\u0430\u043b\u0430 \u0447\u0430\u0441\u0443",
|
||||||
|
"pad.toolbar.savedRevision.title": "\u0417\u0430\u0445\u0430\u0432\u0430\u0446\u044c \u0432\u044d\u0440\u0441\u0456\u044e",
|
||||||
|
"pad.toolbar.settings.title": "\u041d\u0430\u043b\u0430\u0434\u044b",
|
||||||
|
"pad.toolbar.embed.title": "\u0423\u0431\u0443\u0434\u0430\u0432\u0430\u0446\u044c \u0433\u044d\u0442\u044b \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442",
|
||||||
|
"pad.toolbar.showusers.title": "\u041f\u0430\u043a\u0430\u0437\u0430\u0446\u044c \u043a\u0430\u0440\u044b\u0441\u0442\u0430\u043b\u044c\u043d\u0456\u043a\u0430\u045e \u0443 \u0433\u044d\u0442\u044b\u043c \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0446\u0435",
|
||||||
|
"pad.colorpicker.save": "\u0417\u0430\u0445\u0430\u0432\u0430\u0446\u044c",
|
||||||
|
"pad.colorpicker.cancel": "\u0421\u043a\u0430\u0441\u0430\u0432\u0430\u0446\u044c",
|
||||||
|
"pad.loading": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430...",
|
||||||
|
"pad.passwordRequired": "\u0414\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0443 \u0434\u0430 \u0433\u044d\u0442\u0430\u0433\u0430 \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442\u0430 \u043f\u0430\u0442\u0440\u044d\u0431\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044c",
|
||||||
|
"pad.permissionDenied": "\u0412\u044b \u043d\u044f \u043c\u0430\u0435\u0446\u0435 \u0434\u0430\u0437\u0432\u043e\u043b\u0443 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u0430 \u0433\u044d\u0442\u0430\u0433\u0430 \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442\u0430",
|
||||||
|
"pad.wrongPassword": "\u0412\u044b \u045e\u0432\u044f\u043b\u0456 \u043d\u044f\u0441\u043b\u0443\u0448\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044c",
|
||||||
|
"pad.settings.padSettings": "\u041d\u0430\u043b\u0430\u0434\u044b \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442\u0430",
|
||||||
|
"pad.settings.myView": "\u041c\u043e\u0439 \u0432\u044b\u0433\u043b\u044f\u0434",
|
||||||
|
"pad.settings.stickychat": "\u0417\u0430\u045e\u0441\u0451\u0434\u044b \u043f\u0430\u043a\u0430\u0437\u0432\u0430\u0446\u044c \u0447\u0430\u0442",
|
||||||
|
"pad.settings.colorcheck": "\u041a\u043e\u043b\u0435\u0440\u044b \u0430\u045e\u0442\u0430\u0440\u0441\u0442\u0432\u0430",
|
||||||
|
"pad.settings.linenocheck": "\u041d\u0443\u043c\u0430\u0440\u044b \u0440\u0430\u0434\u043a\u043e\u045e",
|
||||||
|
"pad.settings.rtlcheck": "\u0422\u044d\u043a\u0441\u0442 \u0441\u043f\u0440\u0430\u0432\u0430-\u043d\u0430\u043b\u0435\u0432\u0430",
|
||||||
|
"pad.settings.fontType": "\u0422\u044b\u043f \u0448\u0440\u044b\u0444\u0442\u0443:",
|
||||||
|
"pad.settings.fontType.normal": "\u0417\u0432\u044b\u0447\u0430\u0439\u043d\u044b",
|
||||||
|
"pad.settings.fontType.monospaced": "\u041c\u043e\u043d\u0430\u0448\u044b\u0440\u044b\u043d\u043d\u044b",
|
||||||
|
"pad.settings.globalView": "\u0410\u0433\u0443\u043b\u044c\u043d\u044b \u0432\u044b\u0433\u043b\u044f\u0434",
|
||||||
|
"pad.settings.language": "\u041c\u043e\u0432\u0430:",
|
||||||
|
"pad.importExport.import_export": "\u0406\u043c\u043f\u0430\u0440\u0442\/\u042d\u043a\u0441\u043f\u0430\u0440\u0442",
|
||||||
|
"pad.importExport.import": "\u0417\u0430\u0433\u0440\u0443\u0437\u0456\u0436\u0430\u0439\u0446\u0435 \u043b\u044e\u0431\u044b\u044f \u0442\u044d\u043a\u0441\u0442\u0430\u0432\u044b\u044f \u0444\u0430\u0439\u043b\u044b \u0430\u0431\u043e \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442\u044b",
|
||||||
|
"pad.importExport.importSuccessful": "\u041f\u0430\u0441\u044c\u043f\u044f\u0445\u043e\u0432\u0430!",
|
||||||
|
"pad.importExport.export": "\u042d\u043a\u0441\u043f\u0430\u0440\u0442\u0430\u0432\u0430\u0446\u044c \u0431\u044f\u0433\u0443\u0447\u044b \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442 \u044f\u043a:",
|
||||||
|
"pad.importExport.exporthtml": "HTML",
|
||||||
|
"pad.importExport.exportplain": "\u041f\u0440\u043e\u0441\u0442\u044b \u0442\u044d\u043a\u0441\u0442",
|
||||||
|
"pad.importExport.exportword": "Microsoft Word",
|
||||||
|
"pad.importExport.exportpdf": "PDF",
|
||||||
|
"pad.importExport.exportopen": "ODF (Open Document Format)",
|
||||||
|
"pad.importExport.exportdokuwiki": "DokuWiki",
|
||||||
|
"pad.modals.connected": "\u041f\u0430\u0434\u043b\u0443\u0447\u044b\u043b\u0456\u0441\u044f.",
|
||||||
|
"pad.modals.reconnecting": "\u041f\u0435\u0440\u0430\u043f\u0430\u0434\u043b\u0443\u0447\u044d\u043d\u044c\u043d\u0435 \u0434\u0430 \u0432\u0430\u0448\u0430\u0433\u0430 \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442\u0430...",
|
||||||
|
"pad.modals.forcereconnect": "\u041f\u0440\u044b\u043c\u0443\u0441\u043e\u0432\u0430\u0435 \u043f\u0435\u0440\u0430\u043f\u0430\u0434\u043b\u0443\u0447\u044d\u043d\u044c\u043d\u0435",
|
||||||
|
"pad.share": "\u041f\u0430\u0434\u0437\u044f\u043b\u0456\u0446\u0446\u0430 \u0434\u0430\u043a\u0443\u043c\u044d\u043d\u0442\u0430\u043c",
|
||||||
|
"pad.share.readonly": "\u0422\u043e\u043b\u044c\u043a\u0456 \u0434\u043b\u044f \u0447\u044b\u0442\u0430\u043d\u044c\u043d\u044f",
|
||||||
|
"pad.share.link": "\u0421\u043f\u0430\u0441\u044b\u043b\u043a\u0430",
|
||||||
|
"pad.chat": "\u0427\u0430\u0442"
|
||||||
|
}
|
|
@ -37,6 +37,7 @@
|
||||||
"pad.settings.stickychat": "Diskwel ar flap bepred",
|
"pad.settings.stickychat": "Diskwel ar flap bepred",
|
||||||
"pad.settings.colorcheck": "Livio\u00f9 anaout",
|
"pad.settings.colorcheck": "Livio\u00f9 anaout",
|
||||||
"pad.settings.linenocheck": "Niverenno\u00f9 linenno\u00f9",
|
"pad.settings.linenocheck": "Niverenno\u00f9 linenno\u00f9",
|
||||||
|
"pad.settings.rtlcheck": "Lenn an danvez a-zehou da gleiz ?",
|
||||||
"pad.settings.fontType": "Seurt font :",
|
"pad.settings.fontType": "Seurt font :",
|
||||||
"pad.settings.fontType.normal": "Reizh",
|
"pad.settings.fontType.normal": "Reizh",
|
||||||
"pad.settings.fontType.monospaced": "Monospas",
|
"pad.settings.fontType.monospaced": "Monospas",
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"pad.settings.stickychat": "Xateja sempre a la pantalla",
|
"pad.settings.stickychat": "Xateja sempre a la pantalla",
|
||||||
"pad.settings.colorcheck": "Colors d'autoria",
|
"pad.settings.colorcheck": "Colors d'autoria",
|
||||||
"pad.settings.linenocheck": "N\u00fameros de l\u00ednia",
|
"pad.settings.linenocheck": "N\u00fameros de l\u00ednia",
|
||||||
|
"pad.settings.rtlcheck": "Llegir el contingut de dreta a esquerra?",
|
||||||
"pad.settings.fontType": "Tipus de lletra:",
|
"pad.settings.fontType": "Tipus de lletra:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "D'amplada fixa",
|
"pad.settings.fontType.monospaced": "D'amplada fixa",
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{
|
{
|
||||||
"@metadata": {
|
"@metadata": {
|
||||||
"authors": [
|
"authors": {
|
||||||
"Christian List",
|
"0": "Christian List",
|
||||||
"Peter Alberti"
|
"1": "Peter Alberti",
|
||||||
]
|
"3": "Steenth"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"index.newPad": "Ny Pad",
|
"index.newPad": "Ny Pad",
|
||||||
"index.createOpenPad": "eller opret\/\u00e5bn en Pad med navnet:",
|
"index.createOpenPad": "eller opret\/\u00e5bn en Pad med navnet:",
|
||||||
|
@ -20,7 +21,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Fjern farver for forfatterskab",
|
"pad.toolbar.clearAuthorship.title": "Fjern farver for forfatterskab",
|
||||||
"pad.toolbar.import_export.title": "Import\/eksport fra\/til forskellige filformater",
|
"pad.toolbar.import_export.title": "Import\/eksport fra\/til forskellige filformater",
|
||||||
"pad.toolbar.timeslider.title": "Timeslider",
|
"pad.toolbar.timeslider.title": "Timeslider",
|
||||||
"pad.toolbar.savedRevision.title": "Gemte revisioner",
|
"pad.toolbar.savedRevision.title": "Gem Revision",
|
||||||
"pad.toolbar.settings.title": "Indstillinger",
|
"pad.toolbar.settings.title": "Indstillinger",
|
||||||
"pad.toolbar.embed.title": "Integrer denne pad",
|
"pad.toolbar.embed.title": "Integrer denne pad",
|
||||||
"pad.toolbar.showusers.title": "Vis brugere p\u00e5 denne pad",
|
"pad.toolbar.showusers.title": "Vis brugere p\u00e5 denne pad",
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
"pad.settings.stickychat": "Chat altid p\u00e5 sk\u00e6rmen",
|
"pad.settings.stickychat": "Chat altid p\u00e5 sk\u00e6rmen",
|
||||||
"pad.settings.colorcheck": "Forfatterskabsfarver",
|
"pad.settings.colorcheck": "Forfatterskabsfarver",
|
||||||
"pad.settings.linenocheck": "Linjenumre",
|
"pad.settings.linenocheck": "Linjenumre",
|
||||||
|
"pad.settings.rtlcheck": "L\u00e6se indhold fra h\u00f8jre mod venstre?",
|
||||||
"pad.settings.fontType": "Skrifttype:",
|
"pad.settings.fontType": "Skrifttype:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Fastbredde",
|
"pad.settings.fontType.monospaced": "Fastbredde",
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
"pad.settings.stickychat": "Chat immer anzeigen",
|
"pad.settings.stickychat": "Chat immer anzeigen",
|
||||||
"pad.settings.colorcheck": "Autorenfarben anzeigen",
|
"pad.settings.colorcheck": "Autorenfarben anzeigen",
|
||||||
"pad.settings.linenocheck": "Zeilennummern",
|
"pad.settings.linenocheck": "Zeilennummern",
|
||||||
|
"pad.settings.rtlcheck": "Inhalt von rechts nach links lesen?",
|
||||||
"pad.settings.fontType": "Schriftart:",
|
"pad.settings.fontType": "Schriftart:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Monospace",
|
"pad.settings.fontType.monospaced": "Monospace",
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "\u039a\u03b1\u03b8\u03b1\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2 \u03a7\u03c1\u03c9\u03bc\u03ac\u03c4\u03c9\u03bd \u03a3\u03c5\u03bd\u03c4\u03b1\u03ba\u03c4\u03ce\u03bd",
|
"pad.toolbar.clearAuthorship.title": "\u039a\u03b1\u03b8\u03b1\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2 \u03a7\u03c1\u03c9\u03bc\u03ac\u03c4\u03c9\u03bd \u03a3\u03c5\u03bd\u03c4\u03b1\u03ba\u03c4\u03ce\u03bd",
|
||||||
"pad.toolbar.import_export.title": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae\/\u0395\u03be\u03b1\u03b3\u03c9\u03b3\u03ae \u03b1\u03c0\u03cc\/\u03c3\u03b5 \u03b4\u03b9\u03b1\u03c6\u03bf\u03c1\u03b5\u03c4\u03b9\u03ba\u03bf\u03cd\u03c2 \u03c4\u03cd\u03c0\u03bf\u03c5\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd",
|
"pad.toolbar.import_export.title": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae\/\u0395\u03be\u03b1\u03b3\u03c9\u03b3\u03ae \u03b1\u03c0\u03cc\/\u03c3\u03b5 \u03b4\u03b9\u03b1\u03c6\u03bf\u03c1\u03b5\u03c4\u03b9\u03ba\u03bf\u03cd\u03c2 \u03c4\u03cd\u03c0\u03bf\u03c5\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd",
|
||||||
"pad.toolbar.timeslider.title": "\u03a7\u03c1\u03bf\u03bd\u03bf\u03b4\u03b9\u03ac\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1",
|
"pad.toolbar.timeslider.title": "\u03a7\u03c1\u03bf\u03bd\u03bf\u03b4\u03b9\u03ac\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1",
|
||||||
"pad.toolbar.savedRevision.title": "\u0391\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03bc\u03ad\u03bd\u03b5\u03c2 \u0391\u03bd\u03b1\u03b8\u03b5\u03c9\u03c1\u03ae\u03c3\u03b5\u03b9\u03c2",
|
"pad.toolbar.savedRevision.title": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7 \u0391\u03bd\u03b1\u03b8\u03b5\u03ce\u03c1\u03b7\u03c3\u03b7\u03c2",
|
||||||
"pad.toolbar.settings.title": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2",
|
"pad.toolbar.settings.title": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2",
|
||||||
"pad.toolbar.embed.title": "\u0395\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5 pad",
|
"pad.toolbar.embed.title": "\u0395\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5 pad",
|
||||||
"pad.toolbar.showusers.title": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c4\u03c9\u03bd \u03c7\u03c1\u03b7\u03c3\u03c4\u03ce\u03bd \u03b1\u03c5\u03c4\u03bf\u03cd \u03c4\u03bf\u03c5 pad",
|
"pad.toolbar.showusers.title": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c4\u03c9\u03bd \u03c7\u03c1\u03b7\u03c3\u03c4\u03ce\u03bd \u03b1\u03c5\u03c4\u03bf\u03cd \u03c4\u03bf\u03c5 pad",
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
"pad.settings.stickychat": "\u0397 \u03a3\u03c5\u03bd\u03bf\u03bc\u03b9\u03bb\u03af\u03b1 \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c0\u03ac\u03bd\u03c4\u03b1 \u03bf\u03c1\u03b1\u03c4\u03ae",
|
"pad.settings.stickychat": "\u0397 \u03a3\u03c5\u03bd\u03bf\u03bc\u03b9\u03bb\u03af\u03b1 \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c0\u03ac\u03bd\u03c4\u03b1 \u03bf\u03c1\u03b1\u03c4\u03ae",
|
||||||
"pad.settings.colorcheck": "\u03a7\u03c1\u03ce\u03bc\u03b1\u03c4\u03b1 \u03c3\u03c5\u03bd\u03c4\u03ac\u03ba\u03c4\u03b7",
|
"pad.settings.colorcheck": "\u03a7\u03c1\u03ce\u03bc\u03b1\u03c4\u03b1 \u03c3\u03c5\u03bd\u03c4\u03ac\u03ba\u03c4\u03b7",
|
||||||
"pad.settings.linenocheck": "\u0391\u03c1\u03b9\u03b8\u03bc\u03bf\u03af \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",
|
"pad.settings.linenocheck": "\u0391\u03c1\u03b9\u03b8\u03bc\u03bf\u03af \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",
|
||||||
|
"pad.settings.rtlcheck": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b2\u03ac\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf \u03b1\u03c0\u03cc \u03b4\u03b5\u03be\u03b9\u03ac \u03c0\u03c1\u03bf\u03c2 \u03c4\u03b1 \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac;",
|
||||||
"pad.settings.fontType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03bf\u03c3\u03b5\u03b9\u03c1\u03ac\u03c2:",
|
"pad.settings.fontType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03bf\u03c3\u03b5\u03b9\u03c1\u03ac\u03c2:",
|
||||||
"pad.settings.fontType.normal": "\u039a\u03b1\u03bd\u03bf\u03bd\u03b9\u03ba\u03ae",
|
"pad.settings.fontType.normal": "\u039a\u03b1\u03bd\u03bf\u03bd\u03b9\u03ba\u03ae",
|
||||||
"pad.settings.fontType.monospaced": "\u039a\u03b1\u03b8\u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c0\u03bb\u03ac\u03c4\u03bf\u03c5\u03c2",
|
"pad.settings.fontType.monospaced": "\u039a\u03b1\u03b8\u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c0\u03bb\u03ac\u03c4\u03bf\u03c5\u03c2",
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"pad.toolbar.timeslider.title": "Timeslider",
|
"pad.toolbar.timeslider.title": "Timeslider",
|
||||||
"pad.toolbar.savedRevision.title": "Save Revision",
|
"pad.toolbar.savedRevision.title": "Save Revision",
|
||||||
"pad.toolbar.settings.title": "Settings",
|
"pad.toolbar.settings.title": "Settings",
|
||||||
"pad.toolbar.embed.title": "Embed this pad",
|
"pad.toolbar.embed.title": "Share and Embed this pad",
|
||||||
"pad.toolbar.showusers.title": "Show the users on this pad",
|
"pad.toolbar.showusers.title": "Show the users on this pad",
|
||||||
"pad.colorpicker.save": "Save",
|
"pad.colorpicker.save": "Save",
|
||||||
"pad.colorpicker.cancel": "Cancel",
|
"pad.colorpicker.cancel": "Cancel",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
"authors": {
|
"authors": {
|
||||||
"0": "BMRG14",
|
"0": "BMRG14",
|
||||||
"1": "Dalba",
|
"1": "Dalba",
|
||||||
"3": "ZxxZxxZ"
|
"3": "ZxxZxxZ",
|
||||||
|
"4": "\u0627\u0644\u0646\u0627\u0632"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"index.newPad": "\u062f\u0641\u062a\u0631\u0686\u0647 \u06cc\u0627\u062f\u062f\u0627\u0634\u062a \u062a\u0627\u0632\u0647",
|
"index.newPad": "\u062f\u0641\u062a\u0631\u0686\u0647 \u06cc\u0627\u062f\u062f\u0627\u0634\u062a \u062a\u0627\u0632\u0647",
|
||||||
|
@ -21,7 +22,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0631\u0646\u06af\u200c\u0647\u0627\u06cc \u0646\u0648\u06cc\u0633\u0646\u062f\u06af\u06cc",
|
"pad.toolbar.clearAuthorship.title": "\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0631\u0646\u06af\u200c\u0647\u0627\u06cc \u0646\u0648\u06cc\u0633\u0646\u062f\u06af\u06cc",
|
||||||
"pad.toolbar.import_export.title": "\u062f\u0631\u0648\u0646\u200c\u0631\u06cc\u0632\u06cc\/\u0628\u0631\u0648\u0646\u200c\u0631\u06cc\u0632\u06cc \u0627\u0632\/\u0628\u0647 \u0642\u0627\u0644\u0628\u200c\u0647\u0627\u06cc \u0645\u062e\u062a\u0644\u0641",
|
"pad.toolbar.import_export.title": "\u062f\u0631\u0648\u0646\u200c\u0631\u06cc\u0632\u06cc\/\u0628\u0631\u0648\u0646\u200c\u0631\u06cc\u0632\u06cc \u0627\u0632\/\u0628\u0647 \u0642\u0627\u0644\u0628\u200c\u0647\u0627\u06cc \u0645\u062e\u062a\u0644\u0641",
|
||||||
"pad.toolbar.timeslider.title": "\u0627\u0633\u0644\u0627\u06cc\u062f\u0631 \u0632\u0645\u0627\u0646",
|
"pad.toolbar.timeslider.title": "\u0627\u0633\u0644\u0627\u06cc\u062f\u0631 \u0632\u0645\u0627\u0646",
|
||||||
"pad.toolbar.savedRevision.title": "\u0630\u062e\u06cc\u0631\u0647\u200c\u0633\u0627\u0632\u06cc \u0646\u0633\u062e\u0647",
|
"pad.toolbar.savedRevision.title": "\u0630\u062e\u06cc\u0631\u0647\u200c\u06cc \u0628\u0627\u0632\u0646\u0648\u06cc\u0633\u06cc",
|
||||||
"pad.toolbar.settings.title": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a",
|
"pad.toolbar.settings.title": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a",
|
||||||
"pad.toolbar.embed.title": "\u062c\u0627\u0633\u0627\u0632\u06cc \u0627\u06cc\u0646 \u062f\u0641\u062a\u0631\u0686\u0647 \u06cc\u0627\u062f\u062f\u0627\u0634\u062a",
|
"pad.toolbar.embed.title": "\u062c\u0627\u0633\u0627\u0632\u06cc \u0627\u06cc\u0646 \u062f\u0641\u062a\u0631\u0686\u0647 \u06cc\u0627\u062f\u062f\u0627\u0634\u062a",
|
||||||
"pad.toolbar.showusers.title": "\u0646\u0645\u0627\u06cc\u0634 \u06a9\u0627\u0631\u0628\u0631\u0627\u0646 \u062f\u0631 \u0627\u06cc\u0646 \u062f\u0641\u062a\u0631\u0686\u0647 \u06cc\u0627\u062f\u062f\u0627\u0634\u062a",
|
"pad.toolbar.showusers.title": "\u0646\u0645\u0627\u06cc\u0634 \u06a9\u0627\u0631\u0628\u0631\u0627\u0646 \u062f\u0631 \u0627\u06cc\u0646 \u062f\u0641\u062a\u0631\u0686\u0647 \u06cc\u0627\u062f\u062f\u0627\u0634\u062a",
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
"pad.settings.stickychat": "\u06af\u0641\u062a\u06af\u0648 \u0647\u0645\u06cc\u0634\u0647 \u0631\u0648\u06cc \u0635\u0641\u062d\u0647 \u0646\u0645\u0627\u06cc\u0634 \u0628\u0627\u0634\u062f",
|
"pad.settings.stickychat": "\u06af\u0641\u062a\u06af\u0648 \u0647\u0645\u06cc\u0634\u0647 \u0631\u0648\u06cc \u0635\u0641\u062d\u0647 \u0646\u0645\u0627\u06cc\u0634 \u0628\u0627\u0634\u062f",
|
||||||
"pad.settings.colorcheck": "\u0631\u0646\u06af\u200c\u0647\u0627\u06cc \u0646\u0648\u06cc\u0633\u0646\u062f\u06af\u06cc",
|
"pad.settings.colorcheck": "\u0631\u0646\u06af\u200c\u0647\u0627\u06cc \u0646\u0648\u06cc\u0633\u0646\u062f\u06af\u06cc",
|
||||||
"pad.settings.linenocheck": "\u0634\u0645\u0627\u0631\u0647\u200c\u06cc \u062e\u0637\u0648\u0637",
|
"pad.settings.linenocheck": "\u0634\u0645\u0627\u0631\u0647\u200c\u06cc \u062e\u0637\u0648\u0637",
|
||||||
|
"pad.settings.rtlcheck": "\u062e\u0648\u0627\u0646\u062f\u0646 \u0645\u062d\u062a\u0648\u0627 \u0627\u0632 \u0631\u0627\u0633\u062a \u0628\u0647 \u0686\u067e\u061f",
|
||||||
"pad.settings.fontType": "\u0646\u0648\u0639 \u0642\u0644\u0645:",
|
"pad.settings.fontType": "\u0646\u0648\u0639 \u0642\u0644\u0645:",
|
||||||
"pad.settings.fontType.normal": "\u0633\u0627\u062f\u0647",
|
"pad.settings.fontType.normal": "\u0633\u0627\u062f\u0647",
|
||||||
"pad.settings.fontType.monospaced": "Monospace",
|
"pad.settings.fontType.monospaced": "Monospace",
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
"pad.settings.stickychat": "Keskustelu aina n\u00e4kyviss\u00e4",
|
"pad.settings.stickychat": "Keskustelu aina n\u00e4kyviss\u00e4",
|
||||||
"pad.settings.colorcheck": "Kirjoittajav\u00e4rit",
|
"pad.settings.colorcheck": "Kirjoittajav\u00e4rit",
|
||||||
"pad.settings.linenocheck": "Rivinumerot",
|
"pad.settings.linenocheck": "Rivinumerot",
|
||||||
|
"pad.settings.rtlcheck": "Luetaanko sis\u00e4lt\u00f6 oikealta vasemmalle?",
|
||||||
"pad.settings.fontType": "Kirjasintyyppi:",
|
"pad.settings.fontType": "Kirjasintyyppi:",
|
||||||
"pad.settings.fontType.normal": "normaali",
|
"pad.settings.fontType.normal": "normaali",
|
||||||
"pad.settings.fontType.monospaced": "tasalevyinen",
|
"pad.settings.fontType.monospaced": "tasalevyinen",
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Effacer les couleurs identifiant les auteurs",
|
"pad.toolbar.clearAuthorship.title": "Effacer les couleurs identifiant les auteurs",
|
||||||
"pad.toolbar.import_export.title": "Importer\/Exporter de\/vers un format de fichier diff\u00e9rent",
|
"pad.toolbar.import_export.title": "Importer\/Exporter de\/vers un format de fichier diff\u00e9rent",
|
||||||
"pad.toolbar.timeslider.title": "Historique dynamique",
|
"pad.toolbar.timeslider.title": "Historique dynamique",
|
||||||
"pad.toolbar.savedRevision.title": "Versions enregistr\u00e9es",
|
"pad.toolbar.savedRevision.title": "Enregistrer la r\u00e9vision",
|
||||||
"pad.toolbar.settings.title": "Param\u00e8tres",
|
"pad.toolbar.settings.title": "Param\u00e8tres",
|
||||||
"pad.toolbar.embed.title": "Int\u00e9grer ce Pad",
|
"pad.toolbar.embed.title": "Int\u00e9grer ce Pad",
|
||||||
"pad.toolbar.showusers.title": "Afficher les utilisateurs du Pad",
|
"pad.toolbar.showusers.title": "Afficher les utilisateurs du Pad",
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
"pad.settings.stickychat": "Toujours afficher le chat",
|
"pad.settings.stickychat": "Toujours afficher le chat",
|
||||||
"pad.settings.colorcheck": "Couleurs d\u2019identification",
|
"pad.settings.colorcheck": "Couleurs d\u2019identification",
|
||||||
"pad.settings.linenocheck": "Num\u00e9ros de lignes",
|
"pad.settings.linenocheck": "Num\u00e9ros de lignes",
|
||||||
|
"pad.settings.rtlcheck": "Lire le contenu de la droite vers la gauche?",
|
||||||
"pad.settings.fontType": "Type de police :",
|
"pad.settings.fontType": "Type de police :",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Monospace",
|
"pad.settings.fontType.monospaced": "Monospace",
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Limpar as cores de identificaci\u00f3n dos autores",
|
"pad.toolbar.clearAuthorship.title": "Limpar as cores de identificaci\u00f3n dos autores",
|
||||||
"pad.toolbar.import_export.title": "Importar\/Exportar desde\/a diferentes formatos de ficheiro",
|
"pad.toolbar.import_export.title": "Importar\/Exportar desde\/a diferentes formatos de ficheiro",
|
||||||
"pad.toolbar.timeslider.title": "Li\u00f1a do tempo",
|
"pad.toolbar.timeslider.title": "Li\u00f1a do tempo",
|
||||||
"pad.toolbar.savedRevision.title": "Revisi\u00f3ns gardadas",
|
"pad.toolbar.savedRevision.title": "Gardar a revisi\u00f3n",
|
||||||
"pad.toolbar.settings.title": "Configuraci\u00f3ns",
|
"pad.toolbar.settings.title": "Configuraci\u00f3ns",
|
||||||
"pad.toolbar.embed.title": "Incorporar este documento",
|
"pad.toolbar.embed.title": "Incorporar este documento",
|
||||||
"pad.toolbar.showusers.title": "Mostrar os usuarios deste documento",
|
"pad.toolbar.showusers.title": "Mostrar os usuarios deste documento",
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "Chat sempre visible",
|
"pad.settings.stickychat": "Chat sempre visible",
|
||||||
"pad.settings.colorcheck": "Cores de identificaci\u00f3n",
|
"pad.settings.colorcheck": "Cores de identificaci\u00f3n",
|
||||||
"pad.settings.linenocheck": "N\u00fameros de li\u00f1a",
|
"pad.settings.linenocheck": "N\u00fameros de li\u00f1a",
|
||||||
|
"pad.settings.rtlcheck": "Quere ler o contido da dereita \u00e1 esquerda?",
|
||||||
"pad.settings.fontType": "Tipo de letra:",
|
"pad.settings.fontType": "Tipo de letra:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Monoespazada",
|
"pad.settings.fontType.monospaced": "Monoespazada",
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "\u05e0\u05d9\u05e7\u05d5\u05d9 \u05e6\u05d1\u05e2\u05d9\u05dd",
|
"pad.toolbar.clearAuthorship.title": "\u05e0\u05d9\u05e7\u05d5\u05d9 \u05e6\u05d1\u05e2\u05d9\u05dd",
|
||||||
"pad.toolbar.import_export.title": "\u05d9\u05d9\u05d1\u05d5\u05d0\/\u05d9\u05d9\u05e6\u05d0 \u05d1\u05ea\u05e1\u05d3\u05d9\u05e8\u05d9 \u05e7\u05d1\u05e6\u05d9\u05dd \u05e9\u05d5\u05e0\u05d9\u05dd",
|
"pad.toolbar.import_export.title": "\u05d9\u05d9\u05d1\u05d5\u05d0\/\u05d9\u05d9\u05e6\u05d0 \u05d1\u05ea\u05e1\u05d3\u05d9\u05e8\u05d9 \u05e7\u05d1\u05e6\u05d9\u05dd \u05e9\u05d5\u05e0\u05d9\u05dd",
|
||||||
"pad.toolbar.timeslider.title": "\u05d2\u05d5\u05dc\u05dc \u05d6\u05de\u05df",
|
"pad.toolbar.timeslider.title": "\u05d2\u05d5\u05dc\u05dc \u05d6\u05de\u05df",
|
||||||
"pad.toolbar.savedRevision.title": "\u05d2\u05e8\u05e1\u05d0\u05d5\u05ea \u05e9\u05de\u05d5\u05e8\u05d5\u05ea",
|
"pad.toolbar.savedRevision.title": "\u05e9\u05de\u05d9\u05e8\u05ea \u05d2\u05e8\u05e1\u05d4",
|
||||||
"pad.toolbar.settings.title": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea",
|
"pad.toolbar.settings.title": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea",
|
||||||
"pad.toolbar.embed.title": "\u05d4\u05d8\u05de\u05e2\u05ea \u05d4\u05e4\u05e0\u05e7\u05e1 \u05d4\u05d6\u05d4",
|
"pad.toolbar.embed.title": "\u05d4\u05d8\u05de\u05e2\u05ea \u05d4\u05e4\u05e0\u05e7\u05e1 \u05d4\u05d6\u05d4",
|
||||||
"pad.toolbar.showusers.title": "\u05d4\u05e6\u05d2\u05ea \u05d4\u05de\u05e9\u05ea\u05de\u05e9\u05d9\u05dd \u05d1\u05e4\u05e0\u05e7\u05e1 \u05d4\u05d6\u05d4",
|
"pad.toolbar.showusers.title": "\u05d4\u05e6\u05d2\u05ea \u05d4\u05de\u05e9\u05ea\u05de\u05e9\u05d9\u05dd \u05d1\u05e4\u05e0\u05e7\u05e1 \u05d4\u05d6\u05d4",
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
"pad.settings.stickychat": "\u05d4\u05e9\u05d9\u05d7\u05d4 \u05ea\u05de\u05d9\u05d3 \u05e2\u05dc \u05d4\u05de\u05e1\u05da",
|
"pad.settings.stickychat": "\u05d4\u05e9\u05d9\u05d7\u05d4 \u05ea\u05de\u05d9\u05d3 \u05e2\u05dc \u05d4\u05de\u05e1\u05da",
|
||||||
"pad.settings.colorcheck": "\u05e6\u05d1\u05d9\u05e2\u05d4 \u05dc\u05e4\u05d9 \u05de\u05d7\u05d1\u05e8",
|
"pad.settings.colorcheck": "\u05e6\u05d1\u05d9\u05e2\u05d4 \u05dc\u05e4\u05d9 \u05de\u05d7\u05d1\u05e8",
|
||||||
"pad.settings.linenocheck": "\u05de\u05e1\u05e4\u05e8\u05d9 \u05e9\u05d5\u05e8\u05d5\u05ea",
|
"pad.settings.linenocheck": "\u05de\u05e1\u05e4\u05e8\u05d9 \u05e9\u05d5\u05e8\u05d5\u05ea",
|
||||||
|
"pad.settings.rtlcheck": "\u05dc\u05e7\u05e8\u05d5\u05d0 \u05d0\u05ea \u05d4\u05ea\u05d5\u05db\u05df \u05de\u05d9\u05de\u05d9\u05df \u05dc\u05e9\u05de\u05d0\u05dc?",
|
||||||
"pad.settings.fontType": "\u05e1\u05d5\u05d2 \u05d2\u05d5\u05e4\u05df:",
|
"pad.settings.fontType": "\u05e1\u05d5\u05d2 \u05d2\u05d5\u05e4\u05df:",
|
||||||
"pad.settings.fontType.normal": "\u05e8\u05d2\u05d9\u05dc",
|
"pad.settings.fontType.normal": "\u05e8\u05d2\u05d9\u05dc",
|
||||||
"pad.settings.fontType.monospaced": "\u05d1\u05e8\u05d5\u05d7\u05d1 \u05e7\u05d1\u05d5\u05e2",
|
"pad.settings.fontType.monospaced": "\u05d1\u05e8\u05d5\u05d7\u05d1 \u05e7\u05d1\u05d5\u05e2",
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "Chat sempre visibile",
|
"pad.settings.stickychat": "Chat sempre visibile",
|
||||||
"pad.settings.colorcheck": "Colores de autor",
|
"pad.settings.colorcheck": "Colores de autor",
|
||||||
"pad.settings.linenocheck": "Numeros de linea",
|
"pad.settings.linenocheck": "Numeros de linea",
|
||||||
|
"pad.settings.rtlcheck": "Leger le contento de dextra a sinistra?",
|
||||||
"pad.settings.fontType": "Typo de litteras:",
|
"pad.settings.fontType": "Typo de litteras:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Monospatial",
|
"pad.settings.fontType.monospaced": "Monospatial",
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Elimina i colori che indicano gli autori",
|
"pad.toolbar.clearAuthorship.title": "Elimina i colori che indicano gli autori",
|
||||||
"pad.toolbar.import_export.title": "Importa\/esporta da\/a diversi formati di file",
|
"pad.toolbar.import_export.title": "Importa\/esporta da\/a diversi formati di file",
|
||||||
"pad.toolbar.timeslider.title": "Presentazione cronologia",
|
"pad.toolbar.timeslider.title": "Presentazione cronologia",
|
||||||
"pad.toolbar.savedRevision.title": "Revisioni salvate",
|
"pad.toolbar.savedRevision.title": "Versione salvata",
|
||||||
"pad.toolbar.settings.title": "Impostazioni",
|
"pad.toolbar.settings.title": "Impostazioni",
|
||||||
"pad.toolbar.embed.title": "Incorpora questo Pad",
|
"pad.toolbar.embed.title": "Incorpora questo Pad",
|
||||||
"pad.toolbar.showusers.title": "Visualizza gli utenti su questo Pad",
|
"pad.toolbar.showusers.title": "Visualizza gli utenti su questo Pad",
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
"pad.settings.stickychat": "Chat sempre sullo schermo",
|
"pad.settings.stickychat": "Chat sempre sullo schermo",
|
||||||
"pad.settings.colorcheck": "Colori che indicano gli autori",
|
"pad.settings.colorcheck": "Colori che indicano gli autori",
|
||||||
"pad.settings.linenocheck": "Numeri di riga",
|
"pad.settings.linenocheck": "Numeri di riga",
|
||||||
|
"pad.settings.rtlcheck": "Leggere il contenuto da destra a sinistra?",
|
||||||
"pad.settings.fontType": "Tipo di carattere:",
|
"pad.settings.fontType": "Tipo di carattere:",
|
||||||
"pad.settings.fontType.normal": "Normale",
|
"pad.settings.fontType.normal": "Normale",
|
||||||
"pad.settings.fontType.monospaced": "A larghezza fissa",
|
"pad.settings.fontType.monospaced": "A larghezza fissa",
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "\u753b\u9762\u306b\u30c1\u30e3\u30c3\u30c8\u3092\u5e38\u306b\u8868\u793a",
|
"pad.settings.stickychat": "\u753b\u9762\u306b\u30c1\u30e3\u30c3\u30c8\u3092\u5e38\u306b\u8868\u793a",
|
||||||
"pad.settings.colorcheck": "\u4f5c\u8005\u306e\u8272\u5206\u3051",
|
"pad.settings.colorcheck": "\u4f5c\u8005\u306e\u8272\u5206\u3051",
|
||||||
"pad.settings.linenocheck": "\u884c\u756a\u53f7",
|
"pad.settings.linenocheck": "\u884c\u756a\u53f7",
|
||||||
|
"pad.settings.rtlcheck": "\u53f3\u6a2a\u66f8\u304d\u306b\u3059\u308b",
|
||||||
"pad.settings.fontType": "\u30d5\u30a9\u30f3\u30c8\u306e\u7a2e\u985e:",
|
"pad.settings.fontType": "\u30d5\u30a9\u30f3\u30c8\u306e\u7a2e\u985e:",
|
||||||
"pad.settings.fontType.normal": "\u901a\u5e38",
|
"pad.settings.fontType.normal": "\u901a\u5e38",
|
||||||
"pad.settings.fontType.monospaced": "\u56fa\u5b9a\u5e45",
|
"pad.settings.fontType.monospaced": "\u56fa\u5b9a\u5e45",
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "\uc800\uc790\uc758 \uc0c9 \uc9c0\uc6b0\uae30",
|
"pad.toolbar.clearAuthorship.title": "\uc800\uc790\uc758 \uc0c9 \uc9c0\uc6b0\uae30",
|
||||||
"pad.toolbar.import_export.title": "\ub2e4\ub978 \ud30c\uc77c \ud615\uc2dd\uc73c\ub85c \uac00\uc838\uc624\uae30\/\ub0b4\ubcf4\ub0b4\uae30",
|
"pad.toolbar.import_export.title": "\ub2e4\ub978 \ud30c\uc77c \ud615\uc2dd\uc73c\ub85c \uac00\uc838\uc624\uae30\/\ub0b4\ubcf4\ub0b4\uae30",
|
||||||
"pad.toolbar.timeslider.title": "\uc2dc\uac04\uc2ac\ub77c\uc774\ub354",
|
"pad.toolbar.timeslider.title": "\uc2dc\uac04\uc2ac\ub77c\uc774\ub354",
|
||||||
"pad.toolbar.savedRevision.title": "\uc800\uc7a5\ud55c \ud310",
|
"pad.toolbar.savedRevision.title": "\ud310 \uc800\uc7a5",
|
||||||
"pad.toolbar.settings.title": "\uc124\uc815",
|
"pad.toolbar.settings.title": "\uc124\uc815",
|
||||||
"pad.toolbar.embed.title": "\uc774 \ud328\ub4dc \ud3ec\ud568\ud558\uae30",
|
"pad.toolbar.embed.title": "\uc774 \ud328\ub4dc \ud3ec\ud568\ud558\uae30",
|
||||||
"pad.toolbar.showusers.title": "\uc774 \ud328\ub4dc\uc5d0 \uc0ac\uc6a9\uc790 \ubcf4\uae30",
|
"pad.toolbar.showusers.title": "\uc774 \ud328\ub4dc\uc5d0 \uc0ac\uc6a9\uc790 \ubcf4\uae30",
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "\ud654\uba74\uc5d0 \ud56d\uc0c1 \ub300\ud654 \ubcf4\uae30",
|
"pad.settings.stickychat": "\ud654\uba74\uc5d0 \ud56d\uc0c1 \ub300\ud654 \ubcf4\uae30",
|
||||||
"pad.settings.colorcheck": "\uc800\uc790 \uc0c9",
|
"pad.settings.colorcheck": "\uc800\uc790 \uc0c9",
|
||||||
"pad.settings.linenocheck": "\uc904 \ubc88\ud638",
|
"pad.settings.linenocheck": "\uc904 \ubc88\ud638",
|
||||||
|
"pad.settings.rtlcheck": "\uc6b0\ud6a1\uc11c(\uc624\ub978\ucabd\uc5d0\uc11c \uc67c\ucabd\uc73c\ub85c)\uc785\ub2c8\uae4c?",
|
||||||
"pad.settings.fontType": "\uae00\uaf34 \uc885\ub958:",
|
"pad.settings.fontType": "\uae00\uaf34 \uc885\ub958:",
|
||||||
"pad.settings.fontType.normal": "\ubcf4\ud1b5",
|
"pad.settings.fontType.normal": "\ubcf4\ud1b5",
|
||||||
"pad.settings.fontType.monospaced": "\uace0\uc815 \ud3ed",
|
"pad.settings.fontType.monospaced": "\uace0\uc815 \ud3ed",
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "\u041f\u043e\u043d\u0438\u0448\u0442\u0438 \u0433\u0438 \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0442\u0435 \u0431\u043e\u0438",
|
"pad.toolbar.clearAuthorship.title": "\u041f\u043e\u043d\u0438\u0448\u0442\u0438 \u0433\u0438 \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0442\u0435 \u0431\u043e\u0438",
|
||||||
"pad.toolbar.import_export.title": "\u0423\u0432\u043e\u0437\/\u0418\u0437\u0432\u043e\u0437 \u043e\u0434\/\u0432\u043e \u0440\u0430\u0437\u043d\u0438 \u043f\u043e\u0434\u0430\u0442\u043e\u0442\u0435\u0447\u043d\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438",
|
"pad.toolbar.import_export.title": "\u0423\u0432\u043e\u0437\/\u0418\u0437\u0432\u043e\u0437 \u043e\u0434\/\u0432\u043e \u0440\u0430\u0437\u043d\u0438 \u043f\u043e\u0434\u0430\u0442\u043e\u0442\u0435\u0447\u043d\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438",
|
||||||
"pad.toolbar.timeslider.title": "\u0418\u0441\u0442\u043e\u0440\u0438\u0441\u043a\u0438 \u043f\u0440\u0435\u0433\u043b\u0435\u0434",
|
"pad.toolbar.timeslider.title": "\u0418\u0441\u0442\u043e\u0440\u0438\u0441\u043a\u0438 \u043f\u0440\u0435\u0433\u043b\u0435\u0434",
|
||||||
"pad.toolbar.savedRevision.title": "\u0417\u0430\u0447\u0443\u0432\u0430\u043d\u0438 \u0440\u0435\u0432\u0438\u0437\u0438\u0438",
|
"pad.toolbar.savedRevision.title": "\u0417\u0430\u0447\u0443\u0432\u0430\u0458 \u0440\u0435\u0432\u0438\u0437\u0438\u0458\u0430",
|
||||||
"pad.toolbar.settings.title": "\u041f\u043e\u0441\u0442\u0430\u0432\u043a\u0438",
|
"pad.toolbar.settings.title": "\u041f\u043e\u0441\u0442\u0430\u0432\u043a\u0438",
|
||||||
"pad.toolbar.embed.title": "\u0412\u043c\u0435\u0442\u043d\u0438 \u0458\u0430 \u0442\u0435\u0442\u0440\u0430\u0442\u043a\u0430\u0432\u0430",
|
"pad.toolbar.embed.title": "\u0412\u043c\u0435\u0442\u043d\u0438 \u0458\u0430 \u0442\u0435\u0442\u0440\u0430\u0442\u043a\u0430\u0432\u0430",
|
||||||
"pad.toolbar.showusers.title": "\u041f\u0440\u0438\u043a\u0430\u0436. \u043a\u043e\u0440\u0438\u0441\u043d\u0438\u0446\u0438\u0442\u0435 \u043d\u0430 \u0442\u0435\u0442\u0440\u0430\u0442\u043a\u0430\u0432\u0430",
|
"pad.toolbar.showusers.title": "\u041f\u0440\u0438\u043a\u0430\u0436. \u043a\u043e\u0440\u0438\u0441\u043d\u0438\u0446\u0438\u0442\u0435 \u043d\u0430 \u0442\u0435\u0442\u0440\u0430\u0442\u043a\u0430\u0432\u0430",
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
"pad.settings.stickychat": "\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0435 \u0441\u0435\u043a\u043e\u0433\u0430\u0448 \u043d\u0430 \u0435\u043a\u0440\u0430\u043d\u043e\u0442",
|
"pad.settings.stickychat": "\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0435 \u0441\u0435\u043a\u043e\u0433\u0430\u0448 \u043d\u0430 \u0435\u043a\u0440\u0430\u043d\u043e\u0442",
|
||||||
"pad.settings.colorcheck": "\u0410\u0432\u0442\u043e\u0440\u0441\u043a\u0438 \u0431\u043e\u0438",
|
"pad.settings.colorcheck": "\u0410\u0432\u0442\u043e\u0440\u0441\u043a\u0438 \u0431\u043e\u0438",
|
||||||
"pad.settings.linenocheck": "\u0411\u0440\u043e\u0435\u0432\u0438 \u043d\u0430 \u0440\u0435\u0434\u043e\u0432\u0438\u0442\u0435",
|
"pad.settings.linenocheck": "\u0411\u0440\u043e\u0435\u0432\u0438 \u043d\u0430 \u0440\u0435\u0434\u043e\u0432\u0438\u0442\u0435",
|
||||||
|
"pad.settings.rtlcheck": "\u0421\u043e\u0434\u0440\u0436\u0438\u043d\u0438\u0442\u0435 \u0434\u0430 \u0441\u0435 \u0447\u0438\u0442\u0430\u0430\u0442 \u043e\u0434 \u0434\u0435\u0441\u043d\u043e \u043d\u0430 \u043b\u0435\u0432\u043e?",
|
||||||
"pad.settings.fontType": "\u0422\u0438\u043f \u043d\u0430 \u0444\u043e\u043d\u0442:",
|
"pad.settings.fontType": "\u0422\u0438\u043f \u043d\u0430 \u0444\u043e\u043d\u0442:",
|
||||||
"pad.settings.fontType.normal": "\u041d\u043e\u0440\u043c\u0430\u043b\u0435\u043d",
|
"pad.settings.fontType.normal": "\u041d\u043e\u0440\u043c\u0430\u043b\u0435\u043d",
|
||||||
"pad.settings.fontType.monospaced": "\u041d\u0435\u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u043e\u043d\u0430\u043b\u0435\u043d",
|
"pad.settings.fontType.monospaced": "\u041d\u0435\u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u043e\u043d\u0430\u043b\u0435\u043d",
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "\u0d30\u0d1a\u0d2f\u0d3f\u0d24\u0d3e\u0d15\u0d4d\u0d15\u0d7e\u0d15\u0d4d\u0d15\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3f\u0d31\u0d02 \u0d15\u0d33\u0d2f\u0d41\u0d15",
|
"pad.toolbar.clearAuthorship.title": "\u0d30\u0d1a\u0d2f\u0d3f\u0d24\u0d3e\u0d15\u0d4d\u0d15\u0d7e\u0d15\u0d4d\u0d15\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3f\u0d31\u0d02 \u0d15\u0d33\u0d2f\u0d41\u0d15",
|
||||||
"pad.toolbar.import_export.title": "\u0d35\u0d4d\u0d2f\u0d24\u0d4d\u0d2f\u0d38\u0d4d\u0d24 \u0d2b\u0d2f\u0d7d \u0d24\u0d30\u0d19\u0d4d\u0d19\u0d33\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d\/\u0d24\u0d30\u0d19\u0d4d\u0d19\u0d33\u0d3f\u0d7d \u0d28\u0d3f\u0d28\u0d4d\u0d28\u0d4d \u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f\/\u0d15\u0d2f\u0d31\u0d4d\u0d31\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
|
"pad.toolbar.import_export.title": "\u0d35\u0d4d\u0d2f\u0d24\u0d4d\u0d2f\u0d38\u0d4d\u0d24 \u0d2b\u0d2f\u0d7d \u0d24\u0d30\u0d19\u0d4d\u0d19\u0d33\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d\/\u0d24\u0d30\u0d19\u0d4d\u0d19\u0d33\u0d3f\u0d7d \u0d28\u0d3f\u0d28\u0d4d\u0d28\u0d4d \u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f\/\u0d15\u0d2f\u0d31\u0d4d\u0d31\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
|
||||||
"pad.toolbar.timeslider.title": "\u0d38\u0d2e\u0d2f\u0d30\u0d47\u0d16",
|
"pad.toolbar.timeslider.title": "\u0d38\u0d2e\u0d2f\u0d30\u0d47\u0d16",
|
||||||
"pad.toolbar.savedRevision.title": "\u0d38\u0d47\u0d35\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d3f\u0d1f\u0d4d\u0d1f\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d41\u0d15\u0d7e",
|
"pad.toolbar.savedRevision.title": "\u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d4d \u0d38\u0d47\u0d35\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
|
||||||
"pad.toolbar.settings.title": "\u0d38\u0d1c\u0d4d\u0d1c\u0d40\u0d15\u0d30\u0d23\u0d19\u0d4d\u0d19\u0d7e",
|
"pad.toolbar.settings.title": "\u0d38\u0d1c\u0d4d\u0d1c\u0d40\u0d15\u0d30\u0d23\u0d19\u0d4d\u0d19\u0d7e",
|
||||||
"pad.toolbar.embed.title": "\u0d08 \u0d2a\u0d3e\u0d21\u0d4d \u0d0e\u0d02\u0d2c\u0d46\u0d21\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
|
"pad.toolbar.embed.title": "\u0d08 \u0d2a\u0d3e\u0d21\u0d4d \u0d0e\u0d02\u0d2c\u0d46\u0d21\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
|
||||||
"pad.toolbar.showusers.title": "\u0d08 \u0d2a\u0d3e\u0d21\u0d3f\u0d32\u0d41\u0d33\u0d4d\u0d33 \u0d09\u0d2a\u0d2f\u0d4b\u0d15\u0d4d\u0d24\u0d3e\u0d15\u0d4d\u0d15\u0d33\u0d46 \u0d2a\u0d4d\u0d30\u0d26\u0d7c\u0d36\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
|
"pad.toolbar.showusers.title": "\u0d08 \u0d2a\u0d3e\u0d21\u0d3f\u0d32\u0d41\u0d33\u0d4d\u0d33 \u0d09\u0d2a\u0d2f\u0d4b\u0d15\u0d4d\u0d24\u0d3e\u0d15\u0d4d\u0d15\u0d33\u0d46 \u0d2a\u0d4d\u0d30\u0d26\u0d7c\u0d36\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
|
||||||
|
@ -36,6 +36,7 @@
|
||||||
"pad.settings.stickychat": "\u0d24\u0d24\u0d4d\u0d38\u0d2e\u0d2f\u0d02 \u0d38\u0d02\u0d35\u0d3e\u0d26\u0d02 \u0d0e\u0d2a\u0d4d\u0d2a\u0d4b\u0d34\u0d41\u0d02 \u0d38\u0d4d\u0d15\u0d4d\u0d30\u0d40\u0d28\u0d3f\u0d7d \u0d15\u0d3e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
|
"pad.settings.stickychat": "\u0d24\u0d24\u0d4d\u0d38\u0d2e\u0d2f\u0d02 \u0d38\u0d02\u0d35\u0d3e\u0d26\u0d02 \u0d0e\u0d2a\u0d4d\u0d2a\u0d4b\u0d34\u0d41\u0d02 \u0d38\u0d4d\u0d15\u0d4d\u0d30\u0d40\u0d28\u0d3f\u0d7d \u0d15\u0d3e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
|
||||||
"pad.settings.colorcheck": "\u0d0e\u0d34\u0d41\u0d24\u0d4d\u0d24\u0d41\u0d15\u0d3e\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3f\u0d31\u0d19\u0d4d\u0d19\u0d7e",
|
"pad.settings.colorcheck": "\u0d0e\u0d34\u0d41\u0d24\u0d4d\u0d24\u0d41\u0d15\u0d3e\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3f\u0d31\u0d19\u0d4d\u0d19\u0d7e",
|
||||||
"pad.settings.linenocheck": "\u0d35\u0d30\u0d3f\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d15\u0d4d\u0d30\u0d2e\u0d38\u0d02\u0d16\u0d4d\u0d2f",
|
"pad.settings.linenocheck": "\u0d35\u0d30\u0d3f\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d15\u0d4d\u0d30\u0d2e\u0d38\u0d02\u0d16\u0d4d\u0d2f",
|
||||||
|
"pad.settings.rtlcheck": "\u0d09\u0d33\u0d4d\u0d33\u0d1f\u0d15\u0d4d\u0d15\u0d02 \u0d35\u0d32\u0d24\u0d4d\u0d24\u0d41\u0d28\u0d3f\u0d28\u0d4d\u0d28\u0d4d \u0d07\u0d1f\u0d24\u0d4d\u0d24\u0d4b\u0d1f\u0d4d\u0d1f\u0d3e\u0d23\u0d4b \u0d35\u0d3e\u0d2f\u0d3f\u0d15\u0d4d\u0d15\u0d47\u0d23\u0d4d\u0d1f\u0d24\u0d4d?",
|
||||||
"pad.settings.fontType": "\u0d2b\u0d4b\u0d23\u0d4d\u0d1f\u0d4d \u0d24\u0d30\u0d02:",
|
"pad.settings.fontType": "\u0d2b\u0d4b\u0d23\u0d4d\u0d1f\u0d4d \u0d24\u0d30\u0d02:",
|
||||||
"pad.settings.fontType.normal": "\u0d38\u0d3e\u0d27\u0d3e\u0d30\u0d23\u0d02",
|
"pad.settings.fontType.normal": "\u0d38\u0d3e\u0d27\u0d3e\u0d30\u0d23\u0d02",
|
||||||
"pad.settings.fontType.monospaced": "\u0d2e\u0d4b\u0d23\u0d4b\u0d38\u0d4d\u0d2a\u0d47\u0d38\u0d4d",
|
"pad.settings.fontType.monospaced": "\u0d2e\u0d4b\u0d23\u0d4b\u0d38\u0d4d\u0d2a\u0d47\u0d38\u0d4d",
|
||||||
|
@ -51,6 +52,7 @@
|
||||||
"pad.importExport.exportpdf": "\u0d2a\u0d3f.\u0d21\u0d3f.\u0d0e\u0d2b\u0d4d.",
|
"pad.importExport.exportpdf": "\u0d2a\u0d3f.\u0d21\u0d3f.\u0d0e\u0d2b\u0d4d.",
|
||||||
"pad.importExport.exportopen": "\u0d12.\u0d21\u0d3f.\u0d0e\u0d2b\u0d4d. (\u0d13\u0d2a\u0d4d\u0d2a\u0d7a \u0d21\u0d4b\u0d15\u0d4d\u0d2f\u0d41\u0d2e\u0d46\u0d28\u0d4d\u0d31\u0d4d \u0d2b\u0d4b\u0d7c\u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d4d)",
|
"pad.importExport.exportopen": "\u0d12.\u0d21\u0d3f.\u0d0e\u0d2b\u0d4d. (\u0d13\u0d2a\u0d4d\u0d2a\u0d7a \u0d21\u0d4b\u0d15\u0d4d\u0d2f\u0d41\u0d2e\u0d46\u0d28\u0d4d\u0d31\u0d4d \u0d2b\u0d4b\u0d7c\u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d4d)",
|
||||||
"pad.importExport.exportdokuwiki": "\u0d21\u0d4b\u0d15\u0d41\u0d35\u0d3f\u0d15\u0d4d\u0d15\u0d3f",
|
"pad.importExport.exportdokuwiki": "\u0d21\u0d4b\u0d15\u0d41\u0d35\u0d3f\u0d15\u0d4d\u0d15\u0d3f",
|
||||||
|
"pad.importExport.abiword.innerHTML": "\u0d2a\u0d4d\u0d32\u0d46\u0d2f\u0d3f\u0d7b \u0d1f\u0d46\u0d15\u0d4d\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4b \u0d0e\u0d1a\u0d4d\u0d1a\u0d4d.\u0d31\u0d4d\u0d31\u0d3f.\u0d0e\u0d02.\u0d0e\u0d7d. \u0d24\u0d30\u0d2e\u0d4b \u0d2e\u0d3e\u0d24\u0d4d\u0d30\u0d2e\u0d47 \u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d7e\u0d15\u0d4d\u0d15\u0d4d \u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d28\u0d3e\u0d35\u0d42. \u0d15\u0d42\u0d1f\u0d41\u0d24\u0d7d \u0d35\u0d3f\u0d2a\u0d41\u0d32\u0d40\u0d15\u0d43\u0d24 \u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d38\u0d57\u0d15\u0d30\u0d4d\u0d2f\u0d19\u0d4d\u0d19\u0d7e\u0d15\u0d4d\u0d15\u0d3e\u0d2f\u0d3f \u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f <a href=\"https:\/\/github.com\/ether\/etherpad-lite\/wiki\/How-to-enable-importing-and-exporting-different-file-formats-in-Ubuntu-or-OpenSuse-or-SLES-with-AbiWord\">\u0d05\u0d2c\u0d3f\u0d35\u0d47\u0d21\u0d4d \u0d07\u0d7b\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4b\u0d7e \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15<\/a>.",
|
||||||
"pad.modals.connected": "\u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d1a\u0d4d\u0d1a\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41.",
|
"pad.modals.connected": "\u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d1a\u0d4d\u0d1a\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41.",
|
||||||
"pad.modals.reconnecting": "\u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d2a\u0d3e\u0d21\u0d3f\u0d32\u0d47\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d4d \u0d35\u0d40\u0d23\u0d4d\u0d1f\u0d41\u0d02 \u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41...",
|
"pad.modals.reconnecting": "\u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d2a\u0d3e\u0d21\u0d3f\u0d32\u0d47\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d4d \u0d35\u0d40\u0d23\u0d4d\u0d1f\u0d41\u0d02 \u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41...",
|
||||||
"pad.modals.forcereconnect": "\u0d0e\u0d28\u0d4d\u0d24\u0d3e\u0d2f\u0d3e\u0d32\u0d41\u0d02 \u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
|
"pad.modals.forcereconnect": "\u0d0e\u0d28\u0d4d\u0d24\u0d3e\u0d2f\u0d3e\u0d32\u0d41\u0d02 \u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
|
||||||
|
@ -101,6 +103,8 @@
|
||||||
"timeslider.month.october": "\u0d12\u0d15\u0d4d\u0d1f\u0d4b\u0d2c\u0d7c",
|
"timeslider.month.october": "\u0d12\u0d15\u0d4d\u0d1f\u0d4b\u0d2c\u0d7c",
|
||||||
"timeslider.month.november": "\u0d28\u0d35\u0d02\u0d2c\u0d7c",
|
"timeslider.month.november": "\u0d28\u0d35\u0d02\u0d2c\u0d7c",
|
||||||
"timeslider.month.december": "\u0d21\u0d3f\u0d38\u0d02\u0d2c\u0d7c",
|
"timeslider.month.december": "\u0d21\u0d3f\u0d38\u0d02\u0d2c\u0d7c",
|
||||||
|
"timeslider.unnamedauthor": "{{num}} \u0d2a\u0d47\u0d30\u0d3f\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24 \u0d30\u0d1a\u0d2f\u0d3f\u0d24\u0d3e\u0d35\u0d4d",
|
||||||
|
"timeslider.unnamedauthors": "{{num}} \u0d2a\u0d47\u0d30\u0d3f\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24 \u0d30\u0d1a\u0d2f\u0d3f\u0d24\u0d3e\u0d15\u0d4d\u0d15\u0d7e",
|
||||||
"pad.savedrevs.marked": "\u0d08 \u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d4d \u0d38\u0d47\u0d35\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d3f\u0d1f\u0d4d\u0d1f\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d3e\u0d2f\u0d3f \u0d05\u0d1f\u0d2f\u0d3e\u0d33\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d24\u0d4d\u0d24\u0d3f\u0d2f\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41",
|
"pad.savedrevs.marked": "\u0d08 \u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d4d \u0d38\u0d47\u0d35\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d3f\u0d1f\u0d4d\u0d1f\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d3e\u0d2f\u0d3f \u0d05\u0d1f\u0d2f\u0d3e\u0d33\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d24\u0d4d\u0d24\u0d3f\u0d2f\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41",
|
||||||
"pad.userlist.entername": "\u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d2a\u0d47\u0d30\u0d4d \u0d28\u0d7d\u0d15\u0d41\u0d15",
|
"pad.userlist.entername": "\u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d2a\u0d47\u0d30\u0d4d \u0d28\u0d7d\u0d15\u0d41\u0d15",
|
||||||
"pad.userlist.unnamed": "\u0d2a\u0d47\u0d30\u0d3f\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24",
|
"pad.userlist.unnamed": "\u0d2a\u0d47\u0d30\u0d3f\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24",
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Padamkan Warna Pengarang",
|
"pad.toolbar.clearAuthorship.title": "Padamkan Warna Pengarang",
|
||||||
"pad.toolbar.import_export.title": "Import\/Eksport dari\/ke format-format fail berbeza",
|
"pad.toolbar.import_export.title": "Import\/Eksport dari\/ke format-format fail berbeza",
|
||||||
"pad.toolbar.timeslider.title": "Gelangsar masa",
|
"pad.toolbar.timeslider.title": "Gelangsar masa",
|
||||||
"pad.toolbar.savedRevision.title": "Semakan Tersimpan",
|
"pad.toolbar.savedRevision.title": "Simpan Semakan",
|
||||||
"pad.toolbar.settings.title": "Tetapan",
|
"pad.toolbar.settings.title": "Tetapan",
|
||||||
"pad.toolbar.embed.title": "Benamkan pad ini",
|
"pad.toolbar.embed.title": "Benamkan pad ini",
|
||||||
"pad.toolbar.showusers.title": "Tunjukkan pengguna pada pad ini",
|
"pad.toolbar.showusers.title": "Tunjukkan pengguna pada pad ini",
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "Sentiasa bersembang pada skrin",
|
"pad.settings.stickychat": "Sentiasa bersembang pada skrin",
|
||||||
"pad.settings.colorcheck": "Warna pengarang",
|
"pad.settings.colorcheck": "Warna pengarang",
|
||||||
"pad.settings.linenocheck": "Nombor baris",
|
"pad.settings.linenocheck": "Nombor baris",
|
||||||
|
"pad.settings.rtlcheck": "Membaca dari kanan ke kiri?",
|
||||||
"pad.settings.fontType": "Jenis fon:",
|
"pad.settings.fontType": "Jenis fon:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Monospace",
|
"pad.settings.fontType.monospaced": "Monospace",
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "Chat altijd zichtbaar",
|
"pad.settings.stickychat": "Chat altijd zichtbaar",
|
||||||
"pad.settings.colorcheck": "Kleuren auteurs",
|
"pad.settings.colorcheck": "Kleuren auteurs",
|
||||||
"pad.settings.linenocheck": "Regelnummers",
|
"pad.settings.linenocheck": "Regelnummers",
|
||||||
|
"pad.settings.rtlcheck": "Inhoud van rechts naar links lezen?",
|
||||||
"pad.settings.fontType": "Lettertype:",
|
"pad.settings.fontType": "Lettertype:",
|
||||||
"pad.settings.fontType.normal": "Normaal",
|
"pad.settings.fontType.normal": "Normaal",
|
||||||
"pad.settings.fontType.monospaced": "Monospace",
|
"pad.settings.fontType.monospaced": "Monospace",
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0446\u0432\u0435\u0442\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
|
"pad.toolbar.clearAuthorship.title": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0446\u0432\u0435\u0442\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
|
||||||
"pad.toolbar.import_export.title": "\u0418\u043c\u043f\u043e\u0440\u0442\/\u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0444\u0430\u0439\u043b\u043e\u0432",
|
"pad.toolbar.import_export.title": "\u0418\u043c\u043f\u043e\u0440\u0442\/\u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0444\u0430\u0439\u043b\u043e\u0432",
|
||||||
"pad.toolbar.timeslider.title": "\u0428\u043a\u0430\u043b\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438",
|
"pad.toolbar.timeslider.title": "\u0428\u043a\u0430\u043b\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438",
|
||||||
"pad.toolbar.savedRevision.title": "\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438",
|
"pad.toolbar.savedRevision.title": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u044e",
|
||||||
"pad.toolbar.settings.title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438",
|
"pad.toolbar.settings.title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438",
|
||||||
"pad.toolbar.embed.title": "\u0412\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
|
"pad.toolbar.embed.title": "\u0412\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
|
||||||
"pad.toolbar.showusers.title": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435",
|
"pad.toolbar.showusers.title": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435",
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
"pad.settings.stickychat": "\u0412\u0441\u0435\u0433\u0434\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0447\u0430\u0442",
|
"pad.settings.stickychat": "\u0412\u0441\u0435\u0433\u0434\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0447\u0430\u0442",
|
||||||
"pad.settings.colorcheck": "\u0426\u0432\u0435\u0442\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
|
"pad.settings.colorcheck": "\u0426\u0432\u0435\u0442\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
|
||||||
"pad.settings.linenocheck": "\u041d\u043e\u043c\u0435\u0440\u0430 \u0441\u0442\u0440\u043e\u043a",
|
"pad.settings.linenocheck": "\u041d\u043e\u043c\u0435\u0440\u0430 \u0441\u0442\u0440\u043e\u043a",
|
||||||
|
"pad.settings.rtlcheck": "\u0427\u0438\u0442\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e?",
|
||||||
"pad.settings.fontType": "\u0422\u0438\u043f \u0448\u0440\u0438\u0444\u0442\u0430:",
|
"pad.settings.fontType": "\u0422\u0438\u043f \u0448\u0440\u0438\u0444\u0442\u0430:",
|
||||||
"pad.settings.fontType.normal": "\u041e\u0431\u044b\u0447\u043d\u044b\u0439",
|
"pad.settings.fontType.normal": "\u041e\u0431\u044b\u0447\u043d\u044b\u0439",
|
||||||
"pad.settings.fontType.monospaced": "\u041c\u043e\u043d\u043e\u0448\u0438\u0440\u0438\u043d\u043d\u044b\u0439",
|
"pad.settings.fontType.monospaced": "\u041c\u043e\u043d\u043e\u0448\u0438\u0440\u0438\u043d\u043d\u044b\u0439",
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Po\u010disti barvo avtorstva",
|
"pad.toolbar.clearAuthorship.title": "Po\u010disti barvo avtorstva",
|
||||||
"pad.toolbar.import_export.title": "Izvozi\/Uvozi razli\u010dne oblike zapisov",
|
"pad.toolbar.import_export.title": "Izvozi\/Uvozi razli\u010dne oblike zapisov",
|
||||||
"pad.toolbar.timeslider.title": "Drsnik zgodovine",
|
"pad.toolbar.timeslider.title": "Drsnik zgodovine",
|
||||||
"pad.toolbar.savedRevision.title": "Shranjene predelave",
|
"pad.toolbar.savedRevision.title": "Shrani predelavo",
|
||||||
"pad.toolbar.settings.title": "Nastavitve",
|
"pad.toolbar.settings.title": "Nastavitve",
|
||||||
"pad.toolbar.embed.title": "Vstavi dokument",
|
"pad.toolbar.embed.title": "Vstavi dokument",
|
||||||
"pad.toolbar.showusers.title": "Poka\u017ei uporabnike dokumenta",
|
"pad.toolbar.showusers.title": "Poka\u017ei uporabnike dokumenta",
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "Vsebina klepeta je vedno na zaslonu.",
|
"pad.settings.stickychat": "Vsebina klepeta je vedno na zaslonu.",
|
||||||
"pad.settings.colorcheck": "Barve avtorstva",
|
"pad.settings.colorcheck": "Barve avtorstva",
|
||||||
"pad.settings.linenocheck": "\u0160tevilke vrstic",
|
"pad.settings.linenocheck": "\u0160tevilke vrstic",
|
||||||
|
"pad.settings.rtlcheck": "Ali naj se vsebina prebira od desne proti levi?",
|
||||||
"pad.settings.fontType": "Vrsta pisave:",
|
"pad.settings.fontType": "Vrsta pisave:",
|
||||||
"pad.settings.fontType.normal": "Obi\u010dajno",
|
"pad.settings.fontType.normal": "Obi\u010dajno",
|
||||||
"pad.settings.fontType.monospaced": "Monospace",
|
"pad.settings.fontType.monospaced": "Monospace",
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"pad.toolbar.clearAuthorship.title": "Rensa f\u00f6rfattarf\u00e4rger",
|
"pad.toolbar.clearAuthorship.title": "Rensa f\u00f6rfattarf\u00e4rger",
|
||||||
"pad.toolbar.import_export.title": "Importera\/exportera fr\u00e5n\/till olika filformat",
|
"pad.toolbar.import_export.title": "Importera\/exportera fr\u00e5n\/till olika filformat",
|
||||||
"pad.toolbar.timeslider.title": "Tidsreglage",
|
"pad.toolbar.timeslider.title": "Tidsreglage",
|
||||||
"pad.toolbar.savedRevision.title": "Sparade revisioner",
|
"pad.toolbar.savedRevision.title": "Spara revision",
|
||||||
"pad.toolbar.settings.title": "Inst\u00e4llningar",
|
"pad.toolbar.settings.title": "Inst\u00e4llningar",
|
||||||
"pad.toolbar.embed.title": "B\u00e4dda in detta block",
|
"pad.toolbar.embed.title": "B\u00e4dda in detta block",
|
||||||
"pad.toolbar.showusers.title": "Visa anv\u00e4ndarna p\u00e5 detta block",
|
"pad.toolbar.showusers.title": "Visa anv\u00e4ndarna p\u00e5 detta block",
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
"pad.settings.stickychat": "Chatten alltid p\u00e5 sk\u00e4rmen",
|
"pad.settings.stickychat": "Chatten alltid p\u00e5 sk\u00e4rmen",
|
||||||
"pad.settings.colorcheck": "F\u00f6rfattarskapsf\u00e4rger",
|
"pad.settings.colorcheck": "F\u00f6rfattarskapsf\u00e4rger",
|
||||||
"pad.settings.linenocheck": "Radnummer",
|
"pad.settings.linenocheck": "Radnummer",
|
||||||
|
"pad.settings.rtlcheck": "Vill du l\u00e4sa inneh\u00e5llet fr\u00e5n h\u00f6ger till v\u00e4nster?",
|
||||||
"pad.settings.fontType": "Typsnitt:",
|
"pad.settings.fontType": "Typsnitt:",
|
||||||
"pad.settings.fontType.normal": "Normal",
|
"pad.settings.fontType.normal": "Normal",
|
||||||
"pad.settings.fontType.monospaced": "Fast breddsteg",
|
"pad.settings.fontType.monospaced": "Fast breddsteg",
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
"pad.colorpicker.save": "\u0c2d\u0c26\u0c4d\u0c30\u0c2a\u0c30\u0c1a\u0c41",
|
"pad.colorpicker.save": "\u0c2d\u0c26\u0c4d\u0c30\u0c2a\u0c30\u0c1a\u0c41",
|
||||||
"pad.colorpicker.cancel": "\u0c30\u0c26\u0c4d\u0c26\u0c41\u0c1a\u0c47\u0c2f\u0c3f",
|
"pad.colorpicker.cancel": "\u0c30\u0c26\u0c4d\u0c26\u0c41\u0c1a\u0c47\u0c2f\u0c3f",
|
||||||
"pad.loading": "\u0c32\u0c4b\u0c21\u0c35\u0c41\u0c24\u0c4b\u0c02\u0c26\u0c3f...",
|
"pad.loading": "\u0c32\u0c4b\u0c21\u0c35\u0c41\u0c24\u0c4b\u0c02\u0c26\u0c3f...",
|
||||||
"pad.wrongPassword": "\u0c2e\u0c40 \u0c30\u0c39\u0c38\u0c4d\u0c2f\u0c2a\u0c26\u0c02 \u0c24\u0c2a\u0c41",
|
"pad.wrongPassword": "\u0c2e\u0c40 \u0c38\u0c02\u0c15\u0c47\u0c24\u0c2a\u0c26\u0c02 \u0c24\u0c2a\u0c4d\u0c2a\u0c41",
|
||||||
"pad.settings.padSettings": "\u0c2a\u0c32\u0c15 \u0c05\u0c2e\u0c30\u0c3f\u0c15\u0c32\u0c41",
|
"pad.settings.padSettings": "\u0c2a\u0c32\u0c15 \u0c05\u0c2e\u0c30\u0c3f\u0c15\u0c32\u0c41",
|
||||||
"pad.settings.myView": "\u0c28\u0c3e \u0c09\u0c26\u0c4d\u0c26\u0c47\u0c36\u0c4d\u0c2f\u0c2e\u0c41",
|
"pad.settings.myView": "\u0c28\u0c3e \u0c09\u0c26\u0c4d\u0c26\u0c47\u0c36\u0c4d\u0c2f\u0c2e\u0c41",
|
||||||
"pad.settings.stickychat": "\u0c24\u0c46\u0c30\u0c2a\u0c48\u0c28\u0c47 \u0c2e\u0c3e\u0c1f\u0c3e\u0c2e\u0c02\u0c24\u0c3f\u0c28\u0c3f \u0c0e\u0c32\u0c4d\u0c32\u0c2a\u0c41\u0c21\u0c41 \u0c1a\u0c47\u0c2f\u0c41\u0c2e\u0c41",
|
"pad.settings.stickychat": "\u0c24\u0c46\u0c30\u0c2a\u0c48\u0c28\u0c47 \u0c2e\u0c3e\u0c1f\u0c3e\u0c2e\u0c02\u0c24\u0c3f\u0c28\u0c3f \u0c0e\u0c32\u0c4d\u0c32\u0c2a\u0c41\u0c21\u0c41 \u0c1a\u0c47\u0c2f\u0c41\u0c2e\u0c41",
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
"pad.settings.stickychat": "\u6c38\u9060\u5728\u5c4f\u5e55\u4e0a\u986f\u793a\u804a\u5929",
|
"pad.settings.stickychat": "\u6c38\u9060\u5728\u5c4f\u5e55\u4e0a\u986f\u793a\u804a\u5929",
|
||||||
"pad.settings.colorcheck": "\u4f5c\u8005\u984f\u8272",
|
"pad.settings.colorcheck": "\u4f5c\u8005\u984f\u8272",
|
||||||
"pad.settings.linenocheck": "\u884c\u865f",
|
"pad.settings.linenocheck": "\u884c\u865f",
|
||||||
|
"pad.settings.rtlcheck": "\u5f9e\u53f3\u81f3\u5de6\u8b80\u53d6\u5167\u5bb9\uff1f",
|
||||||
"pad.settings.fontType": "\u5b57\u9ad4\u985e\u578b\uff1a",
|
"pad.settings.fontType": "\u5b57\u9ad4\u985e\u578b\uff1a",
|
||||||
"pad.settings.fontType.normal": "\u6b63\u5e38",
|
"pad.settings.fontType.normal": "\u6b63\u5e38",
|
||||||
"pad.settings.fontType.monospaced": "\u7b49\u5bec",
|
"pad.settings.fontType.monospaced": "\u7b49\u5bec",
|
||||||
|
|
|
@ -27,6 +27,8 @@ var padManager = require("./PadManager");
|
||||||
var sessionManager = require("./SessionManager");
|
var sessionManager = require("./SessionManager");
|
||||||
var settings = require("../utils/Settings");
|
var settings = require("../utils/Settings");
|
||||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||||
|
var log4js = require('log4js');
|
||||||
|
var authLogger = log4js.getLogger("auth");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function controlls the access to a pad, it checks if the user can access a pad.
|
* This function controlls the access to a pad, it checks if the user can access a pad.
|
||||||
|
@ -117,29 +119,41 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
||||||
//get information about all sessions contained in this cookie
|
//get information about all sessions contained in this cookie
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
if (!sessionCookie) {
|
if (!sessionCookie)
|
||||||
|
{
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionIDs = sessionCookie.split(',');
|
var sessionIDs = sessionCookie.split(',');
|
||||||
async.forEach(sessionIDs, function(sessionID, callback) {
|
async.forEach(sessionIDs, function(sessionID, callback)
|
||||||
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo) {
|
{
|
||||||
|
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo)
|
||||||
|
{
|
||||||
//skip session if it doesn't exist
|
//skip session if it doesn't exist
|
||||||
if(err && err.message == "sessionID does not exist") return;
|
if(err && err.message == "sessionID does not exist")
|
||||||
|
{
|
||||||
|
authLogger.debug("Auth failed: unknown session");
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
var now = Math.floor(new Date().getTime()/1000);
|
var now = Math.floor(new Date().getTime()/1000);
|
||||||
|
|
||||||
//is it for this group?
|
//is it for this group?
|
||||||
if(sessionInfo.groupID != groupID) {
|
if(sessionInfo.groupID != groupID)
|
||||||
|
{
|
||||||
|
authLogger.debug("Auth failed: wrong group");
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//is validUntil still ok?
|
//is validUntil still ok?
|
||||||
if(sessionInfo.validUntil <= now){
|
if(sessionInfo.validUntil <= now)
|
||||||
|
{
|
||||||
|
authLogger.debug("Auth failed: validUntil");
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +248,11 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
||||||
//--> grant access
|
//--> grant access
|
||||||
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
||||||
//--> deny access if user isn't allowed to create the pad
|
//--> deny access if user isn't allowed to create the pad
|
||||||
if(settings.editOnly) statusObject.accessStatus = "deny";
|
if(settings.editOnly)
|
||||||
|
{
|
||||||
|
authLogger.debug("Auth failed: valid session & pad does not exist");
|
||||||
|
statusObject.accessStatus = "deny";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// there is no valid session avaiable AND pad exists
|
// there is no valid session avaiable AND pad exists
|
||||||
else if(!validSession && padExists)
|
else if(!validSession && padExists)
|
||||||
|
@ -266,6 +284,7 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
||||||
//- its not public
|
//- its not public
|
||||||
else if(!isPublic)
|
else if(!isPublic)
|
||||||
{
|
{
|
||||||
|
authLogger.debug("Auth failed: invalid session & pad is not public");
|
||||||
//--> deny access
|
//--> deny access
|
||||||
statusObject = {accessStatus: "deny"};
|
statusObject = {accessStatus: "deny"};
|
||||||
}
|
}
|
||||||
|
@ -277,6 +296,7 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
||||||
// there is no valid session avaiable AND pad doesn't exists
|
// there is no valid session avaiable AND pad doesn't exists
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
authLogger.debug("Auth failed: invalid session & pad does not exist");
|
||||||
//--> deny access
|
//--> deny access
|
||||||
statusObject = {accessStatus: "deny"};
|
statusObject = {accessStatus: "deny"};
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ SessionStore.prototype.get = function(sid, fn){
|
||||||
{
|
{
|
||||||
if (sess) {
|
if (sess) {
|
||||||
sess.cookie.expires = 'string' == typeof sess.cookie.expires ? new Date(sess.cookie.expires) : sess.cookie.expires;
|
sess.cookie.expires = 'string' == typeof sess.cookie.expires ? new Date(sess.cookie.expires) : sess.cookie.expires;
|
||||||
if (!sess.cookie.expires || new Date() < expires) {
|
if (!sess.cookie.expires || new Date() < sess.cookie.expires) {
|
||||||
fn(null, sess);
|
fn(null, sess);
|
||||||
} else {
|
} else {
|
||||||
self.destroy(sid, fn);
|
self.destroy(sid, fn);
|
||||||
|
|
|
@ -60,7 +60,7 @@ exports.doImport = function(req, res, padId)
|
||||||
form.parse(req, function(err, fields, files) {
|
form.parse(req, function(err, fields, files) {
|
||||||
//the upload failed, stop at this point
|
//the upload failed, stop at this point
|
||||||
if(err || files.file === undefined) {
|
if(err || files.file === undefined) {
|
||||||
console.warn("Uploading Error: " + err.stack);
|
if(err) console.warn("Uploading Error: " + err.stack);
|
||||||
callback("uploadFailed");
|
callback("uploadFailed");
|
||||||
}
|
}
|
||||||
//everything ok, continue
|
//everything ok, continue
|
||||||
|
@ -176,7 +176,7 @@ exports.doImport = function(req, res, padId)
|
||||||
ERR(err);
|
ERR(err);
|
||||||
|
|
||||||
//close the connection
|
//close the connection
|
||||||
res.send("<head><script type='text/javascript' src='../../static/js/jquery.js'></script></head><script>$(window).load(function(){if ( (!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf(\"1.8.\") == 0)) ){document.domain = document.domain;}var impexp = window.parent.padimpexp.handleFrameCall('" + status + "');})</script>", 200);
|
res.send("<head><script type='text/javascript' src='../../static/js/jquery.js'></script><script type='text/javascript' src='../../static/js/jquery_browser.js'></script></head><script>$(window).load(function(){if ( (!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf(\"1.8.\") == 0)) ){document.domain = document.domain;}var impexp = window.parent.padimpexp.handleFrameCall('" + status + "');})</script>", 200);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,12 +151,10 @@ exports.handleMessage = function(client, message)
|
||||||
|
|
||||||
var handleMessageHook = function(callback){
|
var handleMessageHook = function(callback){
|
||||||
var dropMessage = false;
|
var dropMessage = false;
|
||||||
|
|
||||||
// Call handleMessage hook. If a plugin returns null, the message will be dropped. Note that for all messages
|
// Call handleMessage hook. If a plugin returns null, the message will be dropped. Note that for all messages
|
||||||
// handleMessage will be called, even if the client is not authorized
|
// handleMessage will be called, even if the client is not authorized
|
||||||
hooks.aCallAll("handleMessage", { client: client, message: message }, function ( err, messages ) {
|
hooks.aCallAll("handleMessage", { client: client, message: message }, function ( err, messages ) {
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
_.each(messages, function(newMessage){
|
_.each(messages, function(newMessage){
|
||||||
if ( newMessage === null ) {
|
if ( newMessage === null ) {
|
||||||
dropMessage = true;
|
dropMessage = true;
|
||||||
|
@ -205,17 +203,29 @@ exports.handleMessage = function(client, message)
|
||||||
//check permissions
|
//check permissions
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
|
// client tried to auth for the first time (first msg from the client)
|
||||||
// If the message has a padId we assume the client is already known to the server and needs no re-authorization
|
if(message.type == "CLIENT_READY") {
|
||||||
if(!message.padId)
|
// Remember this information since we won't
|
||||||
return callback();
|
// have the cookie in further socket.io messages.
|
||||||
|
// This information will be used to check if
|
||||||
|
// the sessionId of this connection is still valid
|
||||||
|
// since it could have been deleted by the API.
|
||||||
|
sessioninfos[client.id].auth =
|
||||||
|
{
|
||||||
|
sessionID: message.sessionID,
|
||||||
|
padID: message.padId,
|
||||||
|
token : message.token,
|
||||||
|
password: message.password
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Note: message.sessionID is an entirely different kind of
|
// Note: message.sessionID is an entirely different kind of
|
||||||
// session from the sessions we use here! Beware! FIXME: Call
|
// session from the sessions we use here! Beware!
|
||||||
// our "sessions" "connections".
|
// FIXME: Call our "sessions" "connections".
|
||||||
// FIXME: Use a hook instead
|
// FIXME: Use a hook instead
|
||||||
// FIXME: Allow to override readwrite access with readonly
|
// FIXME: Allow to override readwrite access with readonly
|
||||||
securityManager.checkAccess(message.padId, message.sessionID, message.token, message.password, function(err, statusObject)
|
var auth = sessioninfos[client.id].auth;
|
||||||
|
securityManager.checkAccess(auth.padID, auth.sessionID, auth.token, auth.password, function(err, statusObject)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
|
@ -254,6 +264,25 @@ function handleSaveRevisionMessage(client, message){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a custom message, different to the function below as it handles objects not strings and you can
|
||||||
|
* direct the message to specific sessionID
|
||||||
|
*
|
||||||
|
* @param msg {Object} the message we're sending
|
||||||
|
* @param sessionID {string} the socketIO session to which we're sending this message
|
||||||
|
*/
|
||||||
|
exports.handleCustomObjectMessage = function (msg, sessionID, cb) {
|
||||||
|
if(msg.data.type === "CUSTOM"){
|
||||||
|
if(sessionID){ // If a sessionID is targeted then send directly to this sessionID
|
||||||
|
socketio.sockets.socket(sessionID).json.send(msg); // send a targeted message
|
||||||
|
}else{
|
||||||
|
socketio.sockets.in(msg.data.payload.padId).json.send(msg); // broadcast to all clients on this pad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb(null, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a custom message (sent via HTTP API request)
|
* Handles a custom message (sent via HTTP API request)
|
||||||
*
|
*
|
||||||
|
@ -1478,3 +1507,5 @@ exports.padUsers = function (padID, callback) {
|
||||||
callback(null, {padUsers: result});
|
callback(null, {padUsers: result});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.sessioninfos = sessioninfos;
|
||||||
|
|
|
@ -27,49 +27,84 @@ exports.socketio = function (hook_name, args, cb) {
|
||||||
io.on('connection', function (socket) {
|
io.on('connection', function (socket) {
|
||||||
if (!socket.handshake.session.user || !socket.handshake.session.user.is_admin) return;
|
if (!socket.handshake.session.user || !socket.handshake.session.user.is_admin) return;
|
||||||
|
|
||||||
socket.on("load", function (query) {
|
socket.on("getInstalled", function (query) {
|
||||||
// send currently installed plugins
|
// send currently installed plugins
|
||||||
socket.emit("installed-results", {results: plugins.plugins});
|
var installed = Object.keys(plugins.plugins).map(function(plugin) {
|
||||||
socket.emit("progress", {progress:1});
|
return plugins.plugins[plugin].package
|
||||||
|
})
|
||||||
|
socket.emit("results:installed", {installed: installed});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("checkUpdates", function() {
|
socket.on("checkUpdates", function() {
|
||||||
socket.emit("progress", {progress:0, message:'Checking for plugin updates...'});
|
|
||||||
// Check plugins for updates
|
// Check plugins for updates
|
||||||
installer.search({offset: 0, pattern: '', limit: 500}, /*useCache:*/true, function(data) { // hacky
|
installer.getAvailablePlugins(/*maxCacheAge:*/60*10, function(er, results) {
|
||||||
if (!data.results) return;
|
if(er) {
|
||||||
|
console.warn(er);
|
||||||
|
socket.emit("results:updatable", {updatable: {}});
|
||||||
|
return;
|
||||||
|
}
|
||||||
var updatable = _(plugins.plugins).keys().filter(function(plugin) {
|
var updatable = _(plugins.plugins).keys().filter(function(plugin) {
|
||||||
if(!data.results[plugin]) return false;
|
if(!results[plugin]) return false;
|
||||||
var latestVersion = data.results[plugin]['dist-tags'].latest
|
var latestVersion = results[plugin].version
|
||||||
var currentVersion = plugins.plugins[plugin].package.version
|
var currentVersion = plugins.plugins[plugin].package.version
|
||||||
return semver.gt(latestVersion, currentVersion)
|
return semver.gt(latestVersion, currentVersion)
|
||||||
});
|
});
|
||||||
socket.emit("updatable", {updatable: updatable});
|
socket.emit("results:updatable", {updatable: updatable});
|
||||||
socket.emit("progress", {progress:1});
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
socket.on("getAvailable", function (query) {
|
||||||
|
installer.getAvailablePlugins(/*maxCacheAge:*/false, function (er, results) {
|
||||||
|
if(er) {
|
||||||
|
console.error(er)
|
||||||
|
results = {}
|
||||||
|
}
|
||||||
|
socket.emit("results:available", results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
socket.on("search", function (query) {
|
socket.on("search", function (query) {
|
||||||
socket.emit("progress", {progress:0, message:'Fetching results...'});
|
installer.search(query.searchTerm, /*maxCacheAge:*/60*10, function (er, results) {
|
||||||
installer.search(query, true, function (progress) {
|
if(er) {
|
||||||
if (progress.results)
|
console.error(er)
|
||||||
socket.emit("search-result", progress);
|
results = {}
|
||||||
socket.emit("progress", progress);
|
}
|
||||||
|
var res = Object.keys(results)
|
||||||
|
.map(function(pluginName) {
|
||||||
|
return results[pluginName]
|
||||||
|
})
|
||||||
|
.filter(function(plugin) {
|
||||||
|
return !plugins.plugins[plugin.name]
|
||||||
|
});
|
||||||
|
res = sortPluginList(res, query.sortBy, query.sortDir)
|
||||||
|
.slice(query.offset, query.offset+query.limit);
|
||||||
|
socket.emit("results:search", {results: res, query: query});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("install", function (plugin_name) {
|
socket.on("install", function (plugin_name) {
|
||||||
socket.emit("progress", {progress:0, message:'Downloading and installing ' + plugin_name + "..."});
|
installer.install(plugin_name, function (er) {
|
||||||
installer.install(plugin_name, function (progress) {
|
if(er) console.warn(er)
|
||||||
socket.emit("progress", progress);
|
socket.emit("finished:install", {plugin: plugin_name, error: er? er.message : null});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("uninstall", function (plugin_name) {
|
socket.on("uninstall", function (plugin_name) {
|
||||||
socket.emit("progress", {progress:0, message:'Uninstalling ' + plugin_name + "..."});
|
installer.uninstall(plugin_name, function (er) {
|
||||||
installer.uninstall(plugin_name, function (progress) {
|
if(er) console.warn(er)
|
||||||
socket.emit("progress", progress);
|
socket.emit("finished:uninstall", {plugin: plugin_name, error: er? er.message : null});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortPluginList(plugins, property, /*ASC?*/dir) {
|
||||||
|
return plugins.sort(function(a, b) {
|
||||||
|
if (a[property] < b[property])
|
||||||
|
return dir? -1 : 1;
|
||||||
|
if (a[property] > b[property])
|
||||||
|
return dir? 1 : -1;
|
||||||
|
// a must be equal to b
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ exports.gracefulShutdown = function(err) {
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process.on('uncaughtException', exports.gracefulShutdown);
|
||||||
|
|
||||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
exports.app = args.app;
|
exports.app = args.app;
|
||||||
|
@ -47,6 +48,4 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
//https://github.com/joyent/node/issues/1553
|
//https://github.com/joyent/node/issues/1553
|
||||||
process.on('SIGINT', exports.gracefulShutdown);
|
process.on('SIGINT', exports.gracefulShutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.on('uncaughtException', exports.gracefulShutdown);
|
|
||||||
}
|
}
|
|
@ -354,7 +354,6 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
// Let's put this under /rest for now
|
// Let's put this under /rest for now
|
||||||
var subpath = express();
|
var subpath = express();
|
||||||
|
|
||||||
args.app.use(express.bodyParser());
|
|
||||||
args.app.use(basePath, subpath);
|
args.app.use(basePath, subpath);
|
||||||
|
|
||||||
swagger.setAppHandler(subpath);
|
swagger.setAppHandler(subpath);
|
||||||
|
|
|
@ -94,7 +94,7 @@ exports.expressConfigure = function (hook_name, args, cb) {
|
||||||
// If the log level specified in the config file is WARN or ERROR the application server never starts listening to requests as reported in issue #158.
|
// If the log level specified in the config file is WARN or ERROR the application server never starts listening to requests as reported in issue #158.
|
||||||
// Not installing the log4js connect logger when the log level has a higher severity than INFO since it would not log at that level anyway.
|
// Not installing the log4js connect logger when the log level has a higher severity than INFO since it would not log at that level anyway.
|
||||||
if (!(settings.loglevel === "WARN" || settings.loglevel == "ERROR"))
|
if (!(settings.loglevel === "WARN" || settings.loglevel == "ERROR"))
|
||||||
args.app.use(log4js.connectLogger(httpLogger, { level: log4js.levels.INFO, format: ':status, :method :url'}));
|
args.app.use(log4js.connectLogger(httpLogger, { level: log4js.levels.DEBUG, format: ':status, :method :url -- :response-timems'}));
|
||||||
|
|
||||||
/* Do not let express create the session, so that we can retain a
|
/* Do not let express create the session, so that we can retain a
|
||||||
* reference to it for socket.io to use. Also, set the key (cookie
|
* reference to it for socket.io to use. Also, set the key (cookie
|
||||||
|
|
|
@ -63,7 +63,7 @@ if(os.type().indexOf("Windows") > -1)
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.convertFile = function(srcFile, destFile, type, callback)
|
exports.convertFile = function(srcFile, destFile, type, callback)
|
||||||
{
|
{
|
||||||
|
@ -121,7 +121,7 @@ else
|
||||||
firstPrompt = false;
|
firstPrompt = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
spawnAbiword();
|
spawnAbiword();
|
||||||
|
|
||||||
doConvertTask = function(task, callback)
|
doConvertTask = function(task, callback)
|
||||||
|
@ -135,7 +135,7 @@ else
|
||||||
console.log("queue continue");
|
console.log("queue continue");
|
||||||
task.callback(err);
|
task.callback(err);
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
//Queue with the converts we have to do
|
//Queue with the converts we have to do
|
||||||
var queue = async.queue(doConvertTask, 1);
|
var queue = async.queue(doConvertTask, 1);
|
||||||
|
|
|
@ -316,7 +316,7 @@ exports.getPadDokuWikiDocument = function (padId, revNum, callback)
|
||||||
|
|
||||||
getPadDokuWiki(pad, revNum, callback);
|
getPadDokuWiki(pad, revNum, callback);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function _escapeDokuWiki(s)
|
function _escapeDokuWiki(s)
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,7 +45,7 @@ exports.getPadPlainText = function(pad, revNum){
|
||||||
}
|
}
|
||||||
|
|
||||||
return pieces.join('');
|
return pieces.join('');
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
exports._analyzeLine = function(text, aline, apool){
|
exports._analyzeLine = function(text, aline, apool){
|
||||||
|
@ -77,11 +77,11 @@ exports._analyzeLine = function(text, aline, apool){
|
||||||
line.aline = aline;
|
line.aline = aline;
|
||||||
}
|
}
|
||||||
return line;
|
return line;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
exports._encodeWhitespace = function(s){
|
exports._encodeWhitespace = function(s){
|
||||||
return s.replace(/[^\x21-\x7E\s\t\n\r]/g, function(c){
|
return s.replace(/[^\x21-\x7E\s\t\n\r]/g, function(c){
|
||||||
return "&#" +c.charCodeAt(0) + ";"
|
return "&#" +c.charCodeAt(0) + ";";
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@ var padManager = require("../db/PadManager");
|
||||||
var ERR = require("async-stacktrace");
|
var ERR = require("async-stacktrace");
|
||||||
var Security = require('ep_etherpad-lite/static/js/security');
|
var Security = require('ep_etherpad-lite/static/js/security');
|
||||||
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||||
var getPadPlainText = require('./ExportHelper').getPadPlainText
|
var getPadPlainText = require('./ExportHelper').getPadPlainText;
|
||||||
var _analyzeLine = require('./ExportHelper')._analyzeLine;
|
var _analyzeLine = require('./ExportHelper')._analyzeLine;
|
||||||
var _encodeWhitespace = require('./ExportHelper')._encodeWhitespace;
|
var _encodeWhitespace = require('./ExportHelper')._encodeWhitespace;
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ exports.getPadHTMLDocument = function (padId, revNum, noDocType, callback)
|
||||||
callback(null, head + html + foot);
|
callback(null, head + html + foot);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
// copied from ACE
|
// copied from ACE
|
||||||
|
@ -595,4 +595,3 @@ function _processSpaces(s){
|
||||||
}
|
}
|
||||||
return parts.join('');
|
return parts.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,5 +289,4 @@ exports.getPadTXTDocument = function (padId, revNum, noDocType, callback)
|
||||||
callback(null, html);
|
callback(null, html);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
|
@ -125,11 +125,11 @@ function requestURIs(locations, method, headers, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function completed() {
|
function completed() {
|
||||||
var statuss = responses.map(function (x) {return x[0]});
|
var statuss = responses.map(function (x) {return x[0];});
|
||||||
var headerss = responses.map(function (x) {return x[1]});
|
var headerss = responses.map(function (x) {return x[1];});
|
||||||
var contentss = responses.map(function (x) {return x[2]});
|
var contentss = responses.map(function (x) {return x[2];});
|
||||||
callback(statuss, headerss, contentss);
|
callback(statuss, headerss, contentss);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -263,7 +263,7 @@ function getAceFile(callback) {
|
||||||
var filename = item.match(/"([^"]*)"/)[1];
|
var filename = item.match(/"([^"]*)"/)[1];
|
||||||
var request = require('request');
|
var request = require('request');
|
||||||
|
|
||||||
var baseURI = 'http://localhost:' + settings.port
|
var baseURI = 'http://localhost:' + settings.port;
|
||||||
var resourceURI = baseURI + path.normalize(path.join('/static/', filename));
|
var resourceURI = baseURI + path.normalize(path.join('/static/', filename));
|
||||||
resourceURI = resourceURI.replace(/\\/g, '/'); // Windows (safe generally?)
|
resourceURI = resourceURI.replace(/\\/g, '/'); // Windows (safe generally?)
|
||||||
|
|
||||||
|
|
|
@ -137,12 +137,12 @@ exports.abiwordAvailable = function()
|
||||||
{
|
{
|
||||||
return "no";
|
return "no";
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.reloadSettings = function reloadSettings() {
|
exports.reloadSettings = function reloadSettings() {
|
||||||
// Discover where the settings file lives
|
// Discover where the settings file lives
|
||||||
var settingsFilename = argv.settings || "settings.json";
|
var settingsFilename = argv.settings || "settings.json";
|
||||||
settingsFilename = path.resolve(path.join(root, settingsFilename));
|
settingsFilename = path.resolve(path.join(exports.root, settingsFilename));
|
||||||
|
|
||||||
var settingsStr;
|
var settingsStr;
|
||||||
try{
|
try{
|
||||||
|
@ -157,7 +157,7 @@ exports.reloadSettings = function reloadSettings() {
|
||||||
try {
|
try {
|
||||||
if(settingsStr) {
|
if(settingsStr) {
|
||||||
settings = vm.runInContext('exports = '+settingsStr, vm.createContext(), "settings.json");
|
settings = vm.runInContext('exports = '+settingsStr, vm.createContext(), "settings.json");
|
||||||
settings = JSON.parse(JSON.stringify(settings)) // fix objects having constructors of other vm.context
|
settings = JSON.parse(JSON.stringify(settings)); // fix objects having constructors of other vm.context
|
||||||
}
|
}
|
||||||
}catch(e){
|
}catch(e){
|
||||||
console.error('There was an error processing your settings.json file: '+e.message);
|
console.error('There was an error processing your settings.json file: '+e.message);
|
||||||
|
@ -196,9 +196,9 @@ exports.reloadSettings = function reloadSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(exports.dbType === "dirty"){
|
if(exports.dbType === "dirty"){
|
||||||
console.warn("DirtyDB is used. This is fine for testing but not recommended for production.")
|
console.warn("DirtyDB is used. This is fine for testing but not recommended for production.");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// initially load settings
|
// initially load settings
|
||||||
exports.reloadSettings();
|
exports.reloadSettings();
|
||||||
|
|
|
@ -23,7 +23,7 @@ var util = require('util');
|
||||||
var settings = require('./Settings');
|
var settings = require('./Settings');
|
||||||
var semver = require('semver');
|
var semver = require('semver');
|
||||||
|
|
||||||
var existsSync = (semver.satisfies(process.version, '>=0.8.0')) ? fs.existsSync : path.existsSync
|
var existsSync = (semver.satisfies(process.version, '>=0.8.0')) ? fs.existsSync : path.existsSync;
|
||||||
|
|
||||||
var CACHE_DIR = path.normalize(path.join(settings.root, 'var/'));
|
var CACHE_DIR = path.normalize(path.join(settings.root, 'var/'));
|
||||||
CACHE_DIR = existsSync(CACHE_DIR) ? CACHE_DIR : undefined;
|
CACHE_DIR = existsSync(CACHE_DIR) ? CACHE_DIR : undefined;
|
||||||
|
@ -133,7 +133,7 @@ CachingMiddleware.prototype = new function () {
|
||||||
old_res.write = res.write;
|
old_res.write = res.write;
|
||||||
old_res.end = res.end;
|
old_res.end = res.end;
|
||||||
res.write = function(data, encoding) {};
|
res.write = function(data, encoding) {};
|
||||||
res.end = function(data, encoding) { respond() };
|
res.end = function(data, encoding) { respond(); };
|
||||||
} else {
|
} else {
|
||||||
res.writeHead(status, headers);
|
res.writeHead(status, headers);
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ CachingMiddleware.prototype = new function () {
|
||||||
} else if (req.method == 'GET') {
|
} else if (req.method == 'GET') {
|
||||||
var readStream = fs.createReadStream(pathStr);
|
var readStream = fs.createReadStream(pathStr);
|
||||||
res.writeHead(statusCode, headers);
|
res.writeHead(statusCode, headers);
|
||||||
util.pump(readStream, res);
|
readStream.pipe(res);
|
||||||
} else {
|
} else {
|
||||||
res.writeHead(statusCode, headers);
|
res.writeHead(statusCode, headers);
|
||||||
res.end();
|
res.end();
|
||||||
|
|
|
@ -68,7 +68,7 @@ PadDiff.prototype._isClearAuthorship = function(changeset){
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
PadDiff.prototype._createClearAuthorship = function(rev, callback){
|
PadDiff.prototype._createClearAuthorship = function(rev, callback){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -84,7 +84,7 @@ PadDiff.prototype._createClearAuthorship = function(rev, callback){
|
||||||
|
|
||||||
callback(null, changeset);
|
callback(null, changeset);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
PadDiff.prototype._createClearStartAtext = function(rev, callback){
|
PadDiff.prototype._createClearStartAtext = function(rev, callback){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -107,7 +107,7 @@ PadDiff.prototype._createClearStartAtext = function(rev, callback){
|
||||||
callback(null, newAText);
|
callback(null, newAText);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -124,7 +124,7 @@ PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
||||||
async.forEach(revisions, function(rev, callback){
|
async.forEach(revisions, function(rev, callback){
|
||||||
self._pad.getRevision(rev, function(err, revision){
|
self._pad.getRevision(rev, function(err, revision){
|
||||||
if(err){
|
if(err){
|
||||||
return callback(err)
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var arrayNum = rev-startRev;
|
var arrayNum = rev-startRev;
|
||||||
|
@ -137,7 +137,7 @@ PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
||||||
}, function(err){
|
}, function(err){
|
||||||
callback(err, changesets, authors);
|
callback(err, changesets, authors);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
PadDiff.prototype._addAuthors = function(authors) {
|
PadDiff.prototype._addAuthors = function(authors) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -147,7 +147,7 @@ PadDiff.prototype._addAuthors = function(authors) {
|
||||||
self._authors.push(author);
|
self._authors.push(author);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
PadDiff.prototype._createDiffAtext = function(callback) {
|
PadDiff.prototype._createDiffAtext = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -219,7 +219,7 @@ PadDiff.prototype._createDiffAtext = function(callback) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
PadDiff.prototype.getHtml = function(callback){
|
PadDiff.prototype.getHtml = function(callback){
|
||||||
//cache the html
|
//cache the html
|
||||||
|
@ -279,7 +279,7 @@ PadDiff.prototype.getAuthors = function(callback){
|
||||||
} else {
|
} else {
|
||||||
callback(null, self._authors);
|
callback(null, self._authors);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
PadDiff.prototype._extendChangesetWithAuthor = function(changeset, author, apool) {
|
PadDiff.prototype._extendChangesetWithAuthor = function(changeset, author, apool) {
|
||||||
//unpack
|
//unpack
|
||||||
|
@ -312,7 +312,7 @@ PadDiff.prototype._extendChangesetWithAuthor = function(changeset, author, apool
|
||||||
|
|
||||||
//return the modified changeset
|
//return the modified changeset
|
||||||
return Changeset.pack(unpacked.oldLen, unpacked.newLen, assem.toString(), unpacked.charBank);
|
return Changeset.pack(unpacked.oldLen, unpacked.newLen, assem.toString(), unpacked.charBank);
|
||||||
}
|
};
|
||||||
|
|
||||||
//this method is 80% like Changeset.inverse. I just changed so instead of reverting, it adds deletions and attribute changes to to the atext.
|
//this method is 80% like Changeset.inverse. I just changed so instead of reverting, it adds deletions and attribute changes to to the atext.
|
||||||
PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
|
@ -463,7 +463,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
// If the text this operator applies to is only a star, than this is a false positive and should be ignored
|
// If the text this operator applies to is only a star, than this is a false positive and should be ignored
|
||||||
if (csOp.attribs && textBank != "*") {
|
if (csOp.attribs && textBank != "*") {
|
||||||
var deletedAttrib = apool.putAttrib(["removed", true]);
|
var deletedAttrib = apool.putAttrib(["removed", true]);
|
||||||
var authorAttrib = apool.putAttrib(["author", ""]);;
|
var authorAttrib = apool.putAttrib(["author", ""]);
|
||||||
|
|
||||||
attribKeys.length = 0;
|
attribKeys.length = 0;
|
||||||
attribValues.length = 0;
|
attribValues.length = 0;
|
||||||
|
@ -473,7 +473,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
|
|
||||||
if(apool.getAttribKey(n) === "author"){
|
if(apool.getAttribKey(n) === "author"){
|
||||||
authorAttrib = n;
|
authorAttrib = n;
|
||||||
};
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var undoBackToAttribs = cachedStrFunc(function (attribs) {
|
var undoBackToAttribs = cachedStrFunc(function (attribs) {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"require-kernel" : "1.0.5",
|
"require-kernel" : "1.0.5",
|
||||||
"resolve" : "0.2.x",
|
"resolve" : "0.2.x",
|
||||||
"socket.io" : "0.9.x",
|
"socket.io" : "0.9.x",
|
||||||
"ueberDB" : "0.1.94",
|
"ueberDB" : "0.2.x",
|
||||||
"async" : "0.1.x",
|
"async" : "0.1.x",
|
||||||
"express" : "3.x",
|
"express" : "3.x",
|
||||||
"connect" : "2.4.x",
|
"connect" : "2.4.x",
|
||||||
|
@ -24,10 +24,10 @@
|
||||||
"uglify-js" : "1.2.5",
|
"uglify-js" : "1.2.5",
|
||||||
"formidable" : "1.0.9",
|
"formidable" : "1.0.9",
|
||||||
"log4js" : "0.5.x",
|
"log4js" : "0.5.x",
|
||||||
|
"nodemailer" : "0.3.x",
|
||||||
"jsdom-nocontextifiy" : "0.2.10",
|
"jsdom-nocontextifiy" : "0.2.10",
|
||||||
"async-stacktrace" : "0.0.2",
|
"async-stacktrace" : "0.0.2",
|
||||||
"npm" : "1.1.x",
|
"npm" : "1.2.x",
|
||||||
"npm-registry-client" : "0.2.10",
|
|
||||||
"ejs" : "0.6.1",
|
"ejs" : "0.6.1",
|
||||||
"graceful-fs" : "1.1.5",
|
"graceful-fs" : "1.1.5",
|
||||||
"slide" : "1.1.3",
|
"slide" : "1.1.3",
|
||||||
|
@ -46,5 +46,5 @@
|
||||||
"engines" : { "node" : ">=0.6.3",
|
"engines" : { "node" : ">=0.6.3",
|
||||||
"npm" : ">=1.0"
|
"npm" : ">=1.0"
|
||||||
},
|
},
|
||||||
"version" : "1.2.9"
|
"version" : "1.2.91"
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ div.innerwrapper {
|
||||||
box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2);
|
box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
max-width: 1150px;
|
max-width: 1150px;
|
||||||
min-height: 100%;
|
min-height: 101%;/*always display a scrollbar*/
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
@ -102,12 +102,26 @@ input[type="text"] {
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sort {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.sort:after {
|
||||||
|
content: '▲▼'
|
||||||
|
}
|
||||||
|
.sort.up:after {
|
||||||
|
content:'▲'
|
||||||
|
}
|
||||||
|
.sort.down:after {
|
||||||
|
content:'▼'
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
|
position:relative; /* Allows us to position the loading indicator relative to the table */
|
||||||
}
|
}
|
||||||
|
|
||||||
table thead tr {
|
table thead tr {
|
||||||
|
@ -122,13 +136,40 @@ td, th {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#progress {
|
#installed-plugins td>div {
|
||||||
position: absolute;
|
position: relative;/* Allows us to position the loading indicator relative to this row */
|
||||||
bottom: 50px;
|
display: inline-block; /*make this fill the whole cell*/
|
||||||
|
width:100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#progress img {
|
.messages td>* {
|
||||||
vertical-align: top;
|
display: none;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages .fetching {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; bottom:0; right:0;
|
||||||
|
padding: auto;
|
||||||
|
|
||||||
|
background: rgb(255,255,255);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-progress.progress {
|
||||||
|
padding-top: 20%;
|
||||||
|
background: rgba(255,255,255,0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress * {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings {
|
.settings {
|
||||||
|
@ -147,7 +188,25 @@ a:link, a:visited, a:hover, a:focus {
|
||||||
}
|
}
|
||||||
|
|
||||||
a:focus, a:hover {
|
a:focus, a:hover {
|
||||||
border-bottom: #333333 1px solid;
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installed-results a:link,
|
||||||
|
.search-results a:link,
|
||||||
|
.installed-results a:visited,
|
||||||
|
.search-results a:visited,
|
||||||
|
.installed-results a:hover,
|
||||||
|
.search-results a:hover,
|
||||||
|
.installed-results a:focus,
|
||||||
|
.search-results a:focus {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installed-results a:focus,
|
||||||
|
.search-results a:focus,
|
||||||
|
.installed-results a:hover,
|
||||||
|
.search-results a:hover {
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
|
|
|
@ -78,6 +78,7 @@ ul.list-indent8 { list-style-type: none; }
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
word-wrap: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
#outerdocbody {
|
#outerdocbody {
|
||||||
|
@ -93,6 +94,7 @@ body.grayedout { background-color: #eee !important }
|
||||||
|
|
||||||
body.doesWrap {
|
body.doesWrap {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
|
word-wrap: break-word; /* fix for issue #1648 - firefox not wrapping long lines (without spaces) correctly */
|
||||||
}
|
}
|
||||||
|
|
||||||
#innerdocbody {
|
#innerdocbody {
|
||||||
|
|
|
@ -559,6 +559,15 @@ table#otheruserstable {
|
||||||
margin: 4px 0 0 4px;
|
margin: 4px 0 0 4px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
#titlesticky{
|
||||||
|
font-size: 10px;
|
||||||
|
padding-top:2px;
|
||||||
|
float: right;
|
||||||
|
text-align: right;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
#titlecross {
|
#titlecross {
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -828,7 +837,44 @@ input[type=checkbox] {
|
||||||
padding: 4px 1px
|
padding: 4px 1px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 400px){
|
@media all and (max-width: 400px){
|
||||||
|
#gritter-notice-wrapper{
|
||||||
|
max-height:172px;
|
||||||
|
overflow:hidden;
|
||||||
|
width:100% !important;
|
||||||
|
background-color: #ccc;
|
||||||
|
bottom:20px;
|
||||||
|
left:0px;
|
||||||
|
right:0px;
|
||||||
|
color:#000;
|
||||||
|
}
|
||||||
|
.gritter-close {
|
||||||
|
display:block !important;
|
||||||
|
left: auto !important;
|
||||||
|
right:5px;
|
||||||
|
}
|
||||||
|
#gritter-notice-wrapper.bottom-right{
|
||||||
|
left:0px !important;
|
||||||
|
bottom:30px !important;
|
||||||
|
right:0px !important;
|
||||||
|
}
|
||||||
|
.gritter-item p{
|
||||||
|
color:black;
|
||||||
|
font-size:16px;
|
||||||
|
}
|
||||||
|
.gritter-title{
|
||||||
|
text-shadow: none !important;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
.gritter-item{
|
||||||
|
padding:2px 11px 8px 4px;
|
||||||
|
}
|
||||||
|
.gritter-item-wrapper{
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
|
.gritter-item-wrapper > div{
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
#editorcontainer {
|
#editorcontainer {
|
||||||
top: 68px;
|
top: 68px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1013,6 +1013,11 @@ function Ace2Inner(){
|
||||||
return caughtErrors.slice();
|
return caughtErrors.slice();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
editorInfo.ace_getDocument = function()
|
||||||
|
{
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
editorInfo.ace_getDebugProperty = function(prop)
|
editorInfo.ace_getDebugProperty = function(prop)
|
||||||
{
|
{
|
||||||
if (prop == "debugger")
|
if (prop == "debugger")
|
||||||
|
@ -3644,6 +3649,11 @@ function Ace2Inner(){
|
||||||
if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "s" && (evt.metaKey || evt.ctrlKey)) /* Do a saved revision on ctrl S */
|
if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "s" && (evt.metaKey || evt.ctrlKey)) /* Do a saved revision on ctrl S */
|
||||||
{
|
{
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
var originalBackground = parent.parent.$('#revisionlink').css("background")
|
||||||
|
parent.parent.$('#revisionlink').css({"background":"lightyellow"});
|
||||||
|
scheduler.setTimeout(function(){
|
||||||
|
parent.parent.$('#revisionlink').css({"background":originalBackground});
|
||||||
|
}, 1000);
|
||||||
parent.parent.pad.collabClient.sendMessage({"type":"SAVE_REVISION"}); /* The parent.parent part of this is BAD and I feel bad.. It may break something */
|
parent.parent.pad.collabClient.sendMessage({"type":"SAVE_REVISION"}); /* The parent.parent part of this is BAD and I feel bad.. It may break something */
|
||||||
specialHandled = true;
|
specialHandled = true;
|
||||||
}
|
}
|
||||||
|
@ -3712,6 +3722,9 @@ function Ace2Inner(){
|
||||||
specialHandled = true;
|
specialHandled = true;
|
||||||
}
|
}
|
||||||
if((evt.which == 33 || evt.which == 34) && type == 'keydown'){
|
if((evt.which == 33 || evt.which == 34) && type == 'keydown'){
|
||||||
|
|
||||||
|
evt.preventDefault(); // This is required, browsers will try to do normal default behavior on page up / down and the default behavior SUCKS
|
||||||
|
|
||||||
var oldVisibleLineRange = getVisibleLineRange();
|
var oldVisibleLineRange = getVisibleLineRange();
|
||||||
var topOffset = rep.selStart[0] - oldVisibleLineRange[0];
|
var topOffset = rep.selStart[0] - oldVisibleLineRange[0];
|
||||||
if(topOffset < 0 ){
|
if(topOffset < 0 ){
|
||||||
|
@ -3722,29 +3735,38 @@ function Ace2Inner(){
|
||||||
var isPageUp = evt.which === 33;
|
var isPageUp = evt.which === 33;
|
||||||
|
|
||||||
scheduler.setTimeout(function(){
|
scheduler.setTimeout(function(){
|
||||||
var newVisibleLineRange = getVisibleLineRange();
|
var newVisibleLineRange = getVisibleLineRange(); // the visible lines IE 1,10
|
||||||
var linesCount = rep.lines.length();
|
var linesCount = rep.lines.length(); // total count of lines in pad IE 10
|
||||||
|
var numberOfLinesInViewport = newVisibleLineRange[1] - newVisibleLineRange[0]; // How many lines are in the viewport right now?
|
||||||
|
|
||||||
var newCaretRow = rep.selStart[0];
|
|
||||||
if(isPageUp){
|
if(isPageUp){
|
||||||
newCaretRow = oldVisibleLineRange[0];
|
rep.selEnd[0] = rep.selEnd[0] - numberOfLinesInViewport; // move to the bottom line +1 in the viewport (essentially skipping over a page)
|
||||||
|
rep.selStart[0] = rep.selStart[0] - numberOfLinesInViewport; // move to the bottom line +1 in the viewport (essentially skipping over a page)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isPageDown){
|
if(isPageDown){ // if we hit page down
|
||||||
newCaretRow = newVisibleLineRange[0] + topOffset;
|
if(rep.selEnd[0] >= oldVisibleLineRange[0]){ // If the new viewpoint position is actually further than where we are right now
|
||||||
|
rep.selStart[0] = oldVisibleLineRange[1] -1; // dont go further in the page down than what's visible IE go from 0 to 50 if 50 is visible on screen but dont go below that else we miss content
|
||||||
|
rep.selEnd[0] = oldVisibleLineRange[1] -1; // dont go further in the page down than what's visible IE go from 0 to 50 if 50 is visible on screen but dont go below that else we miss content
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ensure min and max
|
//ensure min and max
|
||||||
if(newCaretRow < 0){
|
if(rep.selEnd[0] < 0){
|
||||||
newCaretRow = 0;
|
rep.selEnd[0] = 0;
|
||||||
}
|
}
|
||||||
if(newCaretRow >= linesCount){
|
if(rep.selStart[0] < 0){
|
||||||
newCaretRow = linesCount-1;
|
rep.selStart[0] = 0;
|
||||||
|
}
|
||||||
|
if(rep.selEnd[0] >= linesCount){
|
||||||
|
rep.selEnd[0] = linesCount-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rep.selStart[0] = newCaretRow;
|
|
||||||
rep.selEnd[0] = newCaretRow;
|
|
||||||
updateBrowserSelectionFromRep();
|
updateBrowserSelectionFromRep();
|
||||||
|
var myselection = document.getSelection(); // get the current caret selection, can't use rep. here because that only gives us the start position not the current
|
||||||
|
var caretOffsetTop = myselection.focusNode.parentNode.offsetTop | myselection.focusNode.offsetTop; // get the carets selection offset in px IE 214
|
||||||
|
// top.console.log(caretOffsetTop);
|
||||||
|
setScrollY(caretOffsetTop); // set the scrollY offset of the viewport on the document
|
||||||
|
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3752,32 +3774,44 @@ function Ace2Inner(){
|
||||||
We have to do this the way we do because rep. doesn't hold the value for keyheld events IE if the user
|
We have to do this the way we do because rep. doesn't hold the value for keyheld events IE if the user
|
||||||
presses and holds the arrow key */
|
presses and holds the arrow key */
|
||||||
if((evt.which == 37 || evt.which == 38 || evt.which == 39 || evt.which == 40) && $.browser.chrome){
|
if((evt.which == 37 || evt.which == 38 || evt.which == 39 || evt.which == 40) && $.browser.chrome){
|
||||||
|
var viewport = getViewPortTopBottom();
|
||||||
var newVisibleLineRange = getVisibleLineRange(); // get the current visible range -- This works great.
|
|
||||||
var lineHeight = textLineHeight(); // what Is the height of each line?
|
|
||||||
var myselection = document.getSelection(); // get the current caret selection, can't use rep. here because that only gives us the start position not the current
|
var myselection = document.getSelection(); // get the current caret selection, can't use rep. here because that only gives us the start position not the current
|
||||||
var caretOffsetTop = myselection.focusNode.parentNode.offsetTop; // get the carets selection offset in px IE 214
|
var caretOffsetTop = myselection.focusNode.parentNode.offsetTop; // get the carets selection offset in px IE 214
|
||||||
|
var lineHeight = $(myselection.focusNode.parentNode).parent().height(); // get the line height of the caret line
|
||||||
|
var caretOffsetTopBottom = caretOffsetTop + lineHeight;
|
||||||
|
var visibleLineRange = getVisibleLineRange(); // the visible lines IE 1,10
|
||||||
|
|
||||||
if(caretOffsetTop){ // sometimes caretOffsetTop bugs out and returns 0, not sure why, possible Chrome bug? Either way if it does we don't wanna mess with it
|
if(caretOffsetTop){ // sometimes caretOffsetTop bugs out and returns 0, not sure why, possible Chrome bug? Either way if it does we don't wanna mess with it
|
||||||
var lineNum = Math.round(caretOffsetTop / lineHeight) ; // Get the current Line Number IE 84
|
var caretIsNotVisible = (caretOffsetTop <= viewport.top || caretOffsetTopBottom >= viewport.bottom); // Is the Caret Visible to the user?
|
||||||
newVisibleLineRange[1] = newVisibleLineRange[1]-1;
|
if(caretIsNotVisible){ // is the cursor no longer visible to the user?
|
||||||
var caretIsVisible = (lineNum > newVisibleLineRange[0] && lineNum < newVisibleLineRange[1]); // Is the cursor in the visible Range IE ie 84 > 14 and 84 < 90?
|
|
||||||
|
|
||||||
if(!caretIsVisible){ // is the cursor no longer visible to the user?
|
|
||||||
// Oh boy the caret is out of the visible area, I need to scroll the browser window to lineNum.
|
// Oh boy the caret is out of the visible area, I need to scroll the browser window to lineNum.
|
||||||
// Get the new Y by getting the line number and multiplying by the height of each line.
|
if(evt.which == 37 || evt.which == 38){ // If left or up arrow
|
||||||
if(evt.which == 37 || evt.which == 38){ // If left or up
|
var newY = caretOffsetTop; // That was easy!
|
||||||
var newY = lineHeight * (lineNum -1); // -1 to go to the line above
|
}
|
||||||
}else if(evt.which == 39 || evt.which == 40){ // if down or right
|
if(evt.which == 39 || evt.which == 40){ // if down or right arrow
|
||||||
var newY = getScrollY() + (lineHeight*3); // the offset and one additional line
|
// only move the viewport if we're at the bottom of the viewport, if we hit down any other time the viewport shouldn't change
|
||||||
|
// NOTE: This behavior only fires if Chrome decides to break the page layout after a paste, it's annoying but nothing I can do
|
||||||
|
var selection = getSelection();
|
||||||
|
// top.console.log("line #", rep.selStart[0]); // the line our caret is on
|
||||||
|
// top.console.log("firstvisible", visibleLineRange[0]); // the first visiblel ine
|
||||||
|
// top.console.log("lastVisible", visibleLineRange[1]); // the last visible line
|
||||||
|
|
||||||
|
// Holding down arrow after a paste can lose the cursor -- This is the best fix I can find
|
||||||
|
if(rep.selStart[0] >= visibleLineRange[1] || rep.selStart[0] < visibleLineRange[0] ){ // if we're not at the bottom of the viewport
|
||||||
|
// top.console.log(viewport, lineHeight, myselection);
|
||||||
|
// TODO: Make it so chrome doesnt need to redraw the page by only applying this technique if required
|
||||||
|
var newY = caretOffsetTop;
|
||||||
|
}else{ // we're at the bottom of the viewport so snap to a "new viewport"
|
||||||
|
// top.console.log(viewport, lineHeight, myselection);
|
||||||
|
var newY = caretOffsetTopBottom; // Allow continuous holding of down arrow to redraw the screen so we can see what we are going to highlight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(newY){
|
||||||
|
setScrollY(newY); // set the scrollY offset of the viewport on the document
|
||||||
}
|
}
|
||||||
setScrollY(newY); // set the scroll height of the browser
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == "keydown")
|
if (type == "keydown")
|
||||||
|
|
|
@ -12,176 +12,248 @@ $(document).ready(function () {
|
||||||
//connect
|
//connect
|
||||||
socket = io.connect(url, {resource : resource}).of("/pluginfw/installer");
|
socket = io.connect(url, {resource : resource}).of("/pluginfw/installer");
|
||||||
|
|
||||||
$('.search-results').data('query', {
|
function search(searchTerm, limit) {
|
||||||
pattern: '',
|
if(search.searchTerm != searchTerm) {
|
||||||
offset: 0,
|
search.offset = 0
|
||||||
limit: 12,
|
search.results = []
|
||||||
});
|
search.end = false
|
||||||
|
}
|
||||||
var doUpdate = false;
|
limit = limit? limit : search.limit
|
||||||
|
search.searchTerm = searchTerm;
|
||||||
var search = function () {
|
socket.emit("search", {searchTerm: searchTerm, offset:search.offset, limit: limit, sortBy: search.sortBy, sortDir: search.sortDir});
|
||||||
socket.emit("search", $('.search-results').data('query'));
|
search.offset += limit;
|
||||||
tasks++;
|
$('#search-progress').show()
|
||||||
|
}
|
||||||
|
search.offset = 0;
|
||||||
|
search.limit = 12;
|
||||||
|
search.results = [];
|
||||||
|
search.sortBy = 'name';
|
||||||
|
search.sortDir = /*DESC?*/true;
|
||||||
|
search.end = true;// have we received all results already?
|
||||||
|
search.messages = {
|
||||||
|
show: function(msg) {
|
||||||
|
$('.search-results .messages').show()
|
||||||
|
$('.search-results .messages .'+msg+'').show()
|
||||||
|
},
|
||||||
|
hide: function(msg) {
|
||||||
|
$('.search-results .messages').hide()
|
||||||
|
$('.search-results .messages .'+msg+'').hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHandlers() {
|
var installed = {
|
||||||
$("form").submit(function(){
|
progress: {
|
||||||
var query = $('.search-results').data('query');
|
show: function(plugin, msg) {
|
||||||
query.pattern = $("#search-query").val();
|
$('.installed-results .'+plugin+' .progress').show()
|
||||||
query.offset = 0;
|
$('.installed-results .'+plugin+' .progress .message').text(msg)
|
||||||
search();
|
if($(window).scrollTop() > $('.'+plugin).offset().top)$(window).scrollTop($('.'+plugin).offset().top-100)
|
||||||
return false;
|
},
|
||||||
});
|
hide: function(plugin) {
|
||||||
|
$('.installed-results .'+plugin+' .progress').hide()
|
||||||
$("#search-query").unbind('keyup').keyup(function () {
|
$('.installed-results .'+plugin+' .progress .message').text('')
|
||||||
var query = $('.search-results').data('query');
|
|
||||||
query.pattern = $("#search-query").val();
|
|
||||||
query.offset = 0;
|
|
||||||
search();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".do-install, .do-update").unbind('click').click(function (e) {
|
|
||||||
var row = $(e.target).closest("tr");
|
|
||||||
doUpdate = true;
|
|
||||||
socket.emit("install", row.find(".name").text());
|
|
||||||
tasks++;
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".do-uninstall").unbind('click').click(function (e) {
|
|
||||||
var row = $(e.target).closest("tr");
|
|
||||||
doUpdate = true;
|
|
||||||
socket.emit("uninstall", row.find(".name").text());
|
|
||||||
tasks++;
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".do-prev-page").unbind('click').click(function (e) {
|
|
||||||
var query = $('.search-results').data('query');
|
|
||||||
query.offset -= query.limit;
|
|
||||||
if (query.offset < 0) {
|
|
||||||
query.offset = 0;
|
|
||||||
}
|
}
|
||||||
search();
|
},
|
||||||
});
|
messages: {
|
||||||
$(".do-next-page").unbind('click').click(function (e) {
|
show: function(msg) {
|
||||||
var query = $('.search-results').data('query');
|
$('.installed-results .messages').show()
|
||||||
var total = $('.search-results').data('total');
|
$('.installed-results .messages .'+msg+'').show()
|
||||||
if (query.offset + query.limit < total) {
|
},
|
||||||
query.offset += query.limit;
|
hide: function(msg) {
|
||||||
|
$('.installed-results .messages').hide()
|
||||||
|
$('.installed-results .messages .'+msg+'').hide()
|
||||||
}
|
}
|
||||||
search();
|
},
|
||||||
});
|
list: []
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHandlers();
|
function displayPluginList(plugins, container, template) {
|
||||||
|
plugins.forEach(function(plugin) {
|
||||||
var tasks = 0;
|
var row = template.clone();
|
||||||
socket.on('progress', function (data) {
|
|
||||||
$("#progress").show();
|
|
||||||
$('#progress').data('progress', data.progress);
|
|
||||||
|
|
||||||
var message = "Unknown status";
|
|
||||||
if (data.message) {
|
|
||||||
message = data.message.toString();
|
|
||||||
}
|
|
||||||
if (data.error) {
|
|
||||||
data.progress = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#progress .message").html(message);
|
|
||||||
|
|
||||||
if (data.progress >= 1) {
|
|
||||||
tasks--;
|
|
||||||
if (tasks <= 0) {
|
|
||||||
// Hide the activity indicator once all tasks are done
|
|
||||||
$("#progress").hide();
|
|
||||||
tasks = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.error) {
|
|
||||||
alert('An error occurred: '+data.error+' -- the server log might know more...');
|
|
||||||
}else {
|
|
||||||
if (doUpdate) {
|
|
||||||
doUpdate = false;
|
|
||||||
socket.emit("load");
|
|
||||||
tasks++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('search-result', function (data) {
|
|
||||||
var widget=$(".search-results");
|
|
||||||
|
|
||||||
widget.data('query', data.query);
|
|
||||||
widget.data('total', data.total);
|
|
||||||
|
|
||||||
widget.find('.offset').html(data.query.offset);
|
|
||||||
if (data.query.offset + data.query.limit > data.total){
|
|
||||||
widget.find('.limit').html(data.total);
|
|
||||||
}else{
|
|
||||||
widget.find('.limit').html(data.query.offset + data.query.limit);
|
|
||||||
}
|
|
||||||
widget.find('.total').html(data.total);
|
|
||||||
|
|
||||||
widget.find(".results *").remove();
|
|
||||||
for (plugin_name in data.results) {
|
|
||||||
var plugin = data.results[plugin_name];
|
|
||||||
var row = widget.find(".template tr").clone();
|
|
||||||
|
|
||||||
for (attr in plugin) {
|
for (attr in plugin) {
|
||||||
if(attr == "name"){ // Hack to rewrite URLS into name
|
if(attr == "name"){ // Hack to rewrite URLS into name
|
||||||
row.find(".name").html("<a target='_blank' href='https://npmjs.org/package/"+plugin['name']+"'>"+plugin[attr]+"</a>");
|
row.find(".name").html("<a target='_blank' title='Plugin details' href='https://npmjs.org/package/"+plugin['name']+"'>"+plugin['name'].substr(3)+"</a>"); // remove 'ep_'
|
||||||
}else{
|
}else{
|
||||||
row.find("." + attr).html(plugin[attr]);
|
row.find("." + attr).html(plugin[attr]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
row.find(".version").html( data.results[plugin_name]['dist-tags'].latest );
|
row.find(".version").html( plugin.version );
|
||||||
|
row.addClass(plugin.name)
|
||||||
widget.find(".results").append(row);
|
row.data('plugin', plugin.name)
|
||||||
}
|
container.append(row);
|
||||||
|
})
|
||||||
updateHandlers();
|
updateHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortPluginList(plugins, property, /*ASC?*/dir) {
|
||||||
|
return plugins.sort(function(a, b) {
|
||||||
|
if (a[property] < b[property])
|
||||||
|
return dir? -1 : 1;
|
||||||
|
if (a[property] > b[property])
|
||||||
|
return dir? 1 : -1;
|
||||||
|
// a must be equal to b
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infinite scroll
|
||||||
|
$(window).scroll(checkInfiniteScroll)
|
||||||
|
function checkInfiniteScroll() {
|
||||||
|
if(search.end) return;// don't keep requesting if there are no more results
|
||||||
|
try{
|
||||||
|
var top = $('.search-results .results > tr:last').offset().top
|
||||||
|
if($(window).scrollTop()+$(window).height() > top) search(search.searchTerm)
|
||||||
|
}catch(e){}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHandlers() {
|
||||||
|
// Search
|
||||||
|
$("#search-query").unbind('keyup').keyup(function () {
|
||||||
|
search($("#search-query").val());
|
||||||
|
});
|
||||||
|
|
||||||
|
// update & install
|
||||||
|
$(".do-install, .do-update").unbind('click').click(function (e) {
|
||||||
|
var $row = $(e.target).closest("tr")
|
||||||
|
, plugin = $row.data('plugin');
|
||||||
|
if($(this).hasClass('do-install')) {
|
||||||
|
$row.remove().appendTo('#installed-plugins')
|
||||||
|
installed.progress.show(plugin, 'Installing')
|
||||||
|
}else{
|
||||||
|
installed.progress.show(plugin, 'Updating')
|
||||||
|
}
|
||||||
|
socket.emit("install", plugin);
|
||||||
|
installed.messages.hide("nothing-installed")
|
||||||
|
});
|
||||||
|
|
||||||
|
// uninstall
|
||||||
|
$(".do-uninstall").unbind('click').click(function (e) {
|
||||||
|
var $row = $(e.target).closest("tr")
|
||||||
|
, pluginName = $row.data('plugin');
|
||||||
|
socket.emit("uninstall", pluginName);
|
||||||
|
installed.progress.show(pluginName, 'Uninstalling')
|
||||||
|
installed.list = installed.list.filter(function(plugin) {
|
||||||
|
return plugin.name != pluginName
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
$('.sort.up').unbind('click').click(function() {
|
||||||
|
search.sortBy = $(this).text().toLowerCase();
|
||||||
|
search.sortDir = false;
|
||||||
|
search.offset = 0;
|
||||||
|
search(search.searchTerm, search.results.length);
|
||||||
|
search.results = [];
|
||||||
|
})
|
||||||
|
$('.sort.down, .sort.none').unbind('click').click(function() {
|
||||||
|
search.sortBy = $(this).text().toLowerCase();
|
||||||
|
search.sortDir = true;
|
||||||
|
search.offset = 0;
|
||||||
|
search(search.searchTerm, search.results.length);
|
||||||
|
search.results = [];
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.on('results:search', function (data) {
|
||||||
|
if(!data.results.length) search.end = true;
|
||||||
|
search.messages.hide('nothing-found')
|
||||||
|
search.messages.hide('fetching')
|
||||||
|
$("#search-query").removeAttr('disabled')
|
||||||
|
|
||||||
|
console.log('got search results', data)
|
||||||
|
|
||||||
|
// add to results
|
||||||
|
search.results = search.results.concat(data.results);
|
||||||
|
|
||||||
|
// Update sorting head
|
||||||
|
$('.sort')
|
||||||
|
.removeClass('up down')
|
||||||
|
.addClass('none');
|
||||||
|
$('.search-results thead th[data-label='+data.query.sortBy+']')
|
||||||
|
.removeClass('none')
|
||||||
|
.addClass(data.query.sortDir? 'up' : 'down');
|
||||||
|
|
||||||
|
// re-render search results
|
||||||
|
var searchWidget = $(".search-results");
|
||||||
|
searchWidget.find(".results *").remove();
|
||||||
|
if(search.results.length > 0) {
|
||||||
|
displayPluginList(search.results, searchWidget.find(".results"), searchWidget.find(".template tr"))
|
||||||
|
}else {
|
||||||
|
search.messages.show('nothing-found')
|
||||||
|
}
|
||||||
|
$('#search-progress').hide()
|
||||||
|
checkInfiniteScroll()
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('installed-results', function (data) {
|
socket.on('results:installed', function (data) {
|
||||||
$("#installed-plugins *").remove();
|
installed.messages.hide("fetching")
|
||||||
|
installed.messages.hide("nothing-installed")
|
||||||
|
|
||||||
for (plugin_name in data.results) {
|
installed.list = data.installed
|
||||||
if (plugin_name == "ep_etherpad-lite") continue; // Hack...
|
sortPluginList(installed.list, 'name', /*ASC?*/true);
|
||||||
var plugin = data.results[plugin_name];
|
|
||||||
var row = $("#installed-plugin-template").clone();
|
|
||||||
|
|
||||||
for (attr in plugin.package) {
|
// filter out epl
|
||||||
if(attr == "name"){ // Hack to rewrite URLS into name
|
installed.list = installed.list.filter(function(plugin) {
|
||||||
row.find(".name").html("<a target='_blank' href='https://npmjs.org/package/"+plugin.package['name']+"'>"+plugin.package[attr]+"</a>");
|
return plugin.name != 'ep_etherpad-lite'
|
||||||
}else{
|
})
|
||||||
row.find("." + attr).html(plugin.package[attr]);
|
|
||||||
}
|
// remove all installed plugins (leave plugins that are still being installed)
|
||||||
}
|
installed.list.forEach(function(plugin) {
|
||||||
$("#installed-plugins").append(row);
|
$('#installed-plugins .'+plugin.name).remove()
|
||||||
|
})
|
||||||
|
|
||||||
|
if(installed.list.length > 0) {
|
||||||
|
displayPluginList(installed.list, $("#installed-plugins"), $("#installed-plugin-template"));
|
||||||
|
socket.emit('checkUpdates');
|
||||||
|
}else {
|
||||||
|
installed.messages.show("nothing-installed")
|
||||||
}
|
}
|
||||||
updateHandlers();
|
|
||||||
|
|
||||||
socket.emit('checkUpdates');
|
|
||||||
tasks++;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('updatable', function(data) {
|
socket.on('results:updatable', function(data) {
|
||||||
$('#installed-plugins>tr').each(function(i,tr) {
|
data.updatable.forEach(function(pluginName) {
|
||||||
var pluginName = $(tr).find('.name').text()
|
var $row = $('#installed-plugins > tr.'+pluginName)
|
||||||
|
, actions = $row.find('.actions')
|
||||||
if (data.updatable.indexOf(pluginName) >= 0) {
|
actions.append('<input class="do-update" type="button" value="Update" />')
|
||||||
var actions = $(tr).find('.actions')
|
|
||||||
actions.append('<input class="do-update" type="button" value="Update" />')
|
|
||||||
actions.css('width', 200)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
updateHandlers();
|
updateHandlers();
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.emit("load");
|
socket.on('finished:install', function(data) {
|
||||||
tasks++;
|
if(data.error) {
|
||||||
|
alert('An error occured while installing '+data.plugin+' \n'+data.error)
|
||||||
|
$('#installed-plugins .'+data.plugin).remove()
|
||||||
|
}
|
||||||
|
|
||||||
search();
|
socket.emit("getInstalled");
|
||||||
|
|
||||||
|
// update search results
|
||||||
|
search.offset = 0;
|
||||||
|
search(search.searchTerm, search.results.length);
|
||||||
|
search.results = [];
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on('finished:uninstall', function(data) {
|
||||||
|
if(data.error) alert('An error occured while uninstalling the '+data.plugin+' \n'+data.error)
|
||||||
|
|
||||||
|
// remove plugin from installed list
|
||||||
|
$('#installed-plugins .'+data.plugin).remove()
|
||||||
|
|
||||||
|
socket.emit("getInstalled");
|
||||||
|
|
||||||
|
// update search results
|
||||||
|
search.offset = 0;
|
||||||
|
search(search.searchTerm, search.results.length);
|
||||||
|
search.results = [];
|
||||||
|
})
|
||||||
|
|
||||||
|
// init
|
||||||
|
updateHandlers();
|
||||||
|
socket.emit("getInstalled");
|
||||||
|
search('');
|
||||||
|
|
||||||
|
// check for updates every 5mins
|
||||||
|
setInterval(function() {
|
||||||
|
socket.emit('checkUpdates');
|
||||||
|
}, 1000*60*5)
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
var padutils = require('./pad_utils').padutils;
|
var padutils = require('./pad_utils').padutils;
|
||||||
var padcookie = require('./pad_cookie').padcookie;
|
var padcookie = require('./pad_cookie').padcookie;
|
||||||
var Tinycon = require('tinycon/tinycon');
|
var Tinycon = require('tinycon/tinycon');
|
||||||
|
var hooks = require('./pluginfw/hooks');
|
||||||
|
|
||||||
var chat = (function()
|
var chat = (function()
|
||||||
{
|
{
|
||||||
|
@ -99,74 +100,68 @@ var chat = (function()
|
||||||
|
|
||||||
var text = padutils.escapeHtmlWithClickableLinks(msg.text, "_blank");
|
var text = padutils.escapeHtmlWithClickableLinks(msg.text, "_blank");
|
||||||
|
|
||||||
/* Performs an action if your name is mentioned */
|
|
||||||
var myName = $('#myusernameedit').val();
|
|
||||||
myName = myName.toLowerCase();
|
|
||||||
var chatText = text.toLowerCase();
|
|
||||||
var wasMentioned = false;
|
|
||||||
if (chatText.indexOf(myName) !== -1 && myName != "undefined"){
|
|
||||||
wasMentioned = true;
|
|
||||||
}
|
|
||||||
/* End of new action */
|
|
||||||
|
|
||||||
var authorName = msg.userName == null ? _('pad.userlist.unnamed') : padutils.escapeHtml(msg.userName);
|
var authorName = msg.userName == null ? _('pad.userlist.unnamed') : padutils.escapeHtml(msg.userName);
|
||||||
|
|
||||||
var html = "<p data-authorId='" + msg.userId + "' class='" + authorClass + "'><b>" + authorName + ":</b><span class='time " + authorClass + "'>" + timeStr + "</span> " + text + "</p>";
|
// the hook args
|
||||||
if(isHistoryAdd)
|
var ctx = {
|
||||||
$(html).insertAfter('#chatloadmessagesbutton');
|
"authorName" : authorName,
|
||||||
else
|
"author" : msg.userId,
|
||||||
$("#chattext").append(html);
|
"text" : text,
|
||||||
|
"sticky" : false,
|
||||||
|
"timestamp" : msg.time,
|
||||||
|
"timeStr" : timeStr
|
||||||
|
}
|
||||||
|
|
||||||
//should we increment the counter??
|
// is the users focus already in the chatbox?
|
||||||
if(increment && !isHistoryAdd)
|
var alreadyFocused = $("#chatinput").is(":focus");
|
||||||
{
|
|
||||||
var count = Number($("#chatcounter").text());
|
|
||||||
count++;
|
|
||||||
|
|
||||||
// is the users focus already in the chatbox?
|
// does the user already have the chatbox open?
|
||||||
var alreadyFocused = $("#chatinput").is(":focus");
|
var chatOpen = $("#chatbox").is(":visible");
|
||||||
|
|
||||||
// does the user already have the chatbox open?
|
// does this message contain this user's name? (is the curretn user mentioned?)
|
||||||
var chatOpen = $("#chatbox").is(":visible");
|
var myName = $('#myusernameedit').val();
|
||||||
|
var wasMentioned = (text.toLowerCase().indexOf(myName.toLowerCase()) !== -1 && myName != "undefined");
|
||||||
|
|
||||||
$("#chatcounter").text(count);
|
if(wasMentioned && !alreadyFocused && !isHistoryAdd && !chatOpen)
|
||||||
// chat throb stuff -- Just make it throw for twice as long
|
{ // If the user was mentioned show for twice as long and flash the browser window
|
||||||
if(wasMentioned && !alreadyFocused && !isHistoryAdd && !chatOpen)
|
chatMentions++;
|
||||||
{ // If the user was mentioned show for twice as long and flash the browser window
|
Tinycon.setBubble(chatMentions);
|
||||||
$.gritter.add({
|
ctx.sticky = true;
|
||||||
// (string | mandatory) the heading of the notification
|
}
|
||||||
title: authorName,
|
|
||||||
// (string | mandatory) the text inside the notification
|
|
||||||
text: text,
|
|
||||||
// (bool | optional) if you want it to fade out on its own or just sit there
|
|
||||||
sticky: true,
|
|
||||||
// (int | optional) the time you want it to be alive for before fading out
|
|
||||||
time: '2000'
|
|
||||||
});
|
|
||||||
|
|
||||||
chatMentions++;
|
// Call chat message hook
|
||||||
Tinycon.setBubble(chatMentions);
|
hooks.aCallAll("chatNewMessage", ctx, function() {
|
||||||
}
|
|
||||||
|
var html = "<p data-authorId='" + msg.userId + "' class='" + authorClass + "'><b>" + authorName + ":</b><span class='time " + authorClass + "'>" + ctx.timeStr + "</span> " + ctx.text + "</p>";
|
||||||
|
if(isHistoryAdd)
|
||||||
|
$(html).insertAfter('#chatloadmessagesbutton');
|
||||||
else
|
else
|
||||||
|
$("#chattext").append(html);
|
||||||
|
|
||||||
|
//should we increment the counter??
|
||||||
|
if(increment && !isHistoryAdd)
|
||||||
{
|
{
|
||||||
if(!chatOpen){
|
// Update the counter of unread messages
|
||||||
|
var count = Number($("#chatcounter").text());
|
||||||
|
count++;
|
||||||
|
$("#chatcounter").text(count);
|
||||||
|
|
||||||
|
if(!chatOpen) {
|
||||||
$.gritter.add({
|
$.gritter.add({
|
||||||
// (string | mandatory) the heading of the notification
|
// (string | mandatory) the heading of the notification
|
||||||
title: authorName,
|
title: ctx.authorName,
|
||||||
// (string | mandatory) the text inside the notification
|
// (string | mandatory) the text inside the notification
|
||||||
text: text,
|
text: ctx.text,
|
||||||
|
|
||||||
// (bool | optional) if you want it to fade out on its own or just sit there
|
// (bool | optional) if you want it to fade out on its own or just sit there
|
||||||
sticky: false,
|
sticky: ctx.sticky,
|
||||||
// (int | optional) the time you want it to be alive for before fading out
|
// (int | optional) the time you want it to be alive for before fading out
|
||||||
time: '4000'
|
time: '4000'
|
||||||
});
|
});
|
||||||
Tinycon.setBubble(count);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
// Clear the chat mentions when the user clicks on the chat input box
|
|
||||||
|
// Clear the chat mentions when the user clicks on the chat input box
|
||||||
$('#chatinput').click(function(){
|
$('#chatinput').click(function(){
|
||||||
chatMentions = 0;
|
chatMentions = 0;
|
||||||
Tinycon.setBubble(0);
|
Tinycon.setBubble(0);
|
||||||
|
|
|
@ -278,8 +278,9 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
|
||||||
if (!getSocket()) return;
|
if (!getSocket()) return;
|
||||||
if (!evt.data) return;
|
if (!evt.data) return;
|
||||||
var wrapper = evt;
|
var wrapper = evt;
|
||||||
if (wrapper.type != "COLLABROOM") return;
|
if (wrapper.type != "COLLABROOM" && wrapper.type != "CUSTOM") return;
|
||||||
var msg = wrapper.data;
|
var msg = wrapper.data;
|
||||||
|
|
||||||
if (msg.type == "NEW_CHANGES")
|
if (msg.type == "NEW_CHANGES")
|
||||||
{
|
{
|
||||||
var newRev = msg.newRev;
|
var newRev = msg.newRev;
|
||||||
|
@ -390,6 +391,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
|
||||||
callbacks.onUserLeave(userInfo);
|
callbacks.onUserLeave(userInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (msg.type == "DISCONNECT_REASON")
|
else if (msg.type == "DISCONNECT_REASON")
|
||||||
{
|
{
|
||||||
appLevelDisconnectReason = msg.reason;
|
appLevelDisconnectReason = msg.reason;
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
$.gritter.options = {
|
$.gritter.options = {
|
||||||
position: '',
|
position: '',
|
||||||
class_name: '', // could be set to 'gritter-light' to use white notifications
|
class_name: '', // could be set to 'gritter-light' to use white notifications
|
||||||
fade_in_speed: 'medium', // how fast notifications fade in
|
|
||||||
fade_out_speed: 1000, // how fast the notices fade out
|
|
||||||
time: 6000 // hang on the screen for...
|
time: 6000 // hang on the screen for...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,27 +23,27 @@
|
||||||
window.html10n = (function(window, document, undefined) {
|
window.html10n = (function(window, document, undefined) {
|
||||||
|
|
||||||
// fix console
|
// fix console
|
||||||
var console = window.console;
|
var console = window.console
|
||||||
function interceptConsole(method){
|
function interceptConsole(method){
|
||||||
if (!console) return function() {};
|
if (!console) return function() {}
|
||||||
|
|
||||||
var original = console[method];
|
var original = console[method]
|
||||||
|
|
||||||
// do sneaky stuff
|
// do sneaky stuff
|
||||||
if (original.bind){
|
if (original.bind){
|
||||||
// Do this for normal browsers
|
// Do this for normal browsers
|
||||||
return original.bind(console);
|
return original.bind(console)
|
||||||
}else{
|
}else{
|
||||||
return function() {
|
return function() {
|
||||||
// Do this for IE
|
// Do this for IE
|
||||||
var message = Array.prototype.slice.apply(arguments).join(' ');
|
var message = Array.prototype.slice.apply(arguments).join(' ')
|
||||||
original(message);
|
original(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var consoleLog = interceptConsole('log')
|
var consoleLog = interceptConsole('log')
|
||||||
, consoleWarn = interceptConsole('warn')
|
, consoleWarn = interceptConsole('warn')
|
||||||
, consoleError = interceptConsole('warn');
|
, consoleError = interceptConsole('warn')
|
||||||
|
|
||||||
|
|
||||||
// fix Array.prototype.instanceOf in, guess what, IE! <3
|
// fix Array.prototype.instanceOf in, guess what, IE! <3
|
||||||
|
@ -84,14 +84,14 @@ window.html10n = (function(window, document, undefined) {
|
||||||
* MicroEvent - to make any js object an event emitter (server or browser)
|
* MicroEvent - to make any js object an event emitter (server or browser)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var MicroEvent = function(){}
|
var MicroEvent = function(){}
|
||||||
MicroEvent.prototype = {
|
MicroEvent.prototype = {
|
||||||
bind : function(event, fct){
|
bind : function(event, fct){
|
||||||
this._events = this._events || {};
|
this._events = this._events || {};
|
||||||
this._events[event] = this._events[event] || [];
|
this._events[event] = this._events[event] || [];
|
||||||
this._events[event].push(fct);
|
this._events[event].push(fct);
|
||||||
},
|
},
|
||||||
unbind : function(event, fct){
|
unbind : function(event, fct){
|
||||||
this._events = this._events || {};
|
this._events = this._events || {};
|
||||||
if( event in this._events === false ) return;
|
if( event in this._events === false ) return;
|
||||||
this._events[event].splice(this._events[event].indexOf(fct), 1);
|
this._events[event].splice(this._events[event].indexOf(fct), 1);
|
||||||
|
@ -100,7 +100,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
this._events = this._events || {};
|
this._events = this._events || {};
|
||||||
if( event in this._events === false ) return;
|
if( event in this._events === false ) return;
|
||||||
for(var i = 0; i < this._events[event].length; i++){
|
for(var i = 0; i < this._events[event].length; i++){
|
||||||
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
|
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -122,50 +122,50 @@ window.html10n = (function(window, document, undefined) {
|
||||||
* and caching all necessary resources
|
* and caching all necessary resources
|
||||||
*/
|
*/
|
||||||
function Loader(resources) {
|
function Loader(resources) {
|
||||||
this.resources = resources;
|
this.resources = resources
|
||||||
this.cache = {}; // file => contents
|
this.cache = {} // file => contents
|
||||||
this.langs = {}; // lang => strings
|
this.langs = {} // lang => strings
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader.prototype.load = function(lang, cb) {
|
Loader.prototype.load = function(lang, cb) {
|
||||||
if(this.langs[lang]) return cb();
|
if(this.langs[lang]) return cb()
|
||||||
|
|
||||||
if (this.resources.length > 0) {
|
if (this.resources.length > 0) {
|
||||||
var reqs = 0;
|
var reqs = 0;
|
||||||
for (var i=0, n=this.resources.length; i < n; i++) {
|
for (var i=0, n=this.resources.length; i < n; i++) {
|
||||||
this.fetch(this.resources[i], lang, function(e) {
|
this.fetch(this.resources[i], lang, function(e) {
|
||||||
reqs++;
|
reqs++;
|
||||||
if(e) return setTimeout(function(){ throw e }, 0);
|
if(e) console.warn(e)
|
||||||
|
|
||||||
if (reqs < n) return;// Call back once all reqs are completed
|
if (reqs < n) return;// Call back once all reqs are completed
|
||||||
cb && cb();
|
cb && cb()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader.prototype.fetch = function(href, lang, cb) {
|
Loader.prototype.fetch = function(href, lang, cb) {
|
||||||
var that = this;
|
var that = this
|
||||||
|
|
||||||
if (this.cache[href]) {
|
if (this.cache[href]) {
|
||||||
this.parse(lang, href, this.cache[href], cb)
|
this.parse(lang, href, this.cache[href], cb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest()
|
||||||
xhr.open('GET', href, /*async: */true);
|
xhr.open('GET', href, /*async: */true)
|
||||||
if (xhr.overrideMimeType) {
|
if (xhr.overrideMimeType) {
|
||||||
xhr.overrideMimeType('application/json; charset=utf-8');
|
xhr.overrideMimeType('application/json; charset=utf-8');
|
||||||
}
|
}
|
||||||
xhr.onreadystatechange = function() {
|
xhr.onreadystatechange = function() {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState == 4) {
|
||||||
if (xhr.status == 200 || xhr.status === 0) {
|
if (xhr.status == 200 || xhr.status === 0) {
|
||||||
var data = JSON.parse(xhr.responseText);
|
var data = JSON.parse(xhr.responseText)
|
||||||
that.cache[href] = data;
|
that.cache[href] = data
|
||||||
// Pass on the contents for parsing
|
// Pass on the contents for parsing
|
||||||
that.parse(lang, href, data, cb);
|
that.parse(lang, href, data, cb)
|
||||||
} else {
|
} else {
|
||||||
cb(new Error('Failed to load '+href));
|
cb(new Error('Failed to load '+href))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -174,39 +174,38 @@ window.html10n = (function(window, document, undefined) {
|
||||||
|
|
||||||
Loader.prototype.parse = function(lang, currHref, data, cb) {
|
Loader.prototype.parse = function(lang, currHref, data, cb) {
|
||||||
if ('object' != typeof data) {
|
if ('object' != typeof data) {
|
||||||
cb(new Error('A file couldn\'t be parsed as json.'));
|
cb(new Error('A file couldn\'t be parsed as json.'))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data[lang]) lang = lang.substr(0, lang.indexOf('-') == -1? lang.length : lang.indexOf('-'));
|
|
||||||
if (!data[lang]) {
|
if (!data[lang]) {
|
||||||
cb(new Error('Couldn\'t find translations for '+lang));
|
cb(new Error('Couldn\'t find translations for '+lang))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('string' == typeof data[lang]) {
|
if ('string' == typeof data[lang]) {
|
||||||
// Import rule
|
// Import rule
|
||||||
|
|
||||||
// absolute path
|
// absolute path
|
||||||
var importUrl = data[lang];
|
var importUrl = data[lang]
|
||||||
|
|
||||||
// relative path
|
// relative path
|
||||||
if(data[lang].indexOf("http") != 0 && data[lang].indexOf("/") != 0) {
|
if(data[lang].indexOf("http") != 0 && data[lang].indexOf("/") != 0) {
|
||||||
importUrl = currHref+"/../"+data[lang];
|
importUrl = currHref+"/../"+data[lang]
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetch(importUrl, lang, cb);
|
this.fetch(importUrl, lang, cb)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('object' != typeof data[lang]) {
|
if ('object' != typeof data[lang]) {
|
||||||
cb(new Error('Translations should be specified as JSON objects!'));
|
cb(new Error('Translations should be specified as JSON objects!'))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.langs[lang] = data[lang];
|
this.langs[lang] = data[lang]
|
||||||
// TODO: Also store accompanying langs
|
// TODO: Also store accompanying langs
|
||||||
cb();
|
cb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -216,11 +215,11 @@ window.html10n = (function(window, document, undefined) {
|
||||||
var html10n =
|
var html10n =
|
||||||
{ language : null
|
{ language : null
|
||||||
}
|
}
|
||||||
MicroEvent.mixin(html10n);
|
MicroEvent.mixin(html10n)
|
||||||
|
|
||||||
html10n.macros = {};
|
html10n.macros = {}
|
||||||
|
|
||||||
html10n.rtl = ["ar","dv","fa","ha","he","ks","ku","ps","ur","yi"];
|
html10n.rtl = ["ar","dv","fa","ha","he","ks","ku","ps","ur","yi"]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get rules for plural forms (shared with JetPack), see:
|
* Get rules for plural forms (shared with JetPack), see:
|
||||||
|
@ -664,14 +663,22 @@ window.html10n = (function(window, document, undefined) {
|
||||||
* @param langs An array of lang codes defining fallbacks
|
* @param langs An array of lang codes defining fallbacks
|
||||||
*/
|
*/
|
||||||
html10n.localize = function(langs) {
|
html10n.localize = function(langs) {
|
||||||
var that = this;
|
var that = this
|
||||||
// if only one string => create an array
|
// if only one string => create an array
|
||||||
if ('string' == typeof langs) langs = [langs];
|
if ('string' == typeof langs) langs = [langs]
|
||||||
|
|
||||||
|
// Expand two-part locale specs
|
||||||
|
var i=0
|
||||||
|
langs.forEach(function(lang) {
|
||||||
|
if(!lang) return
|
||||||
|
langs[i++] = lang
|
||||||
|
if(~lang.indexOf('-')) langs[i++] = lang.substr(0, lang.indexOf('-'))
|
||||||
|
})
|
||||||
|
|
||||||
this.build(langs, function(er, translations) {
|
this.build(langs, function(er, translations) {
|
||||||
html10n.translations = translations;
|
html10n.translations = translations
|
||||||
html10n.translateElement(translations);
|
html10n.translateElement(translations)
|
||||||
that.trigger('localized');
|
that.trigger('localized')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,78 +689,78 @@ window.html10n = (function(window, document, undefined) {
|
||||||
* @param element A DOM element, if omitted, the document element will be used
|
* @param element A DOM element, if omitted, the document element will be used
|
||||||
*/
|
*/
|
||||||
html10n.translateElement = function(translations, element) {
|
html10n.translateElement = function(translations, element) {
|
||||||
element = element || document.documentElement;
|
element = element || document.documentElement
|
||||||
|
|
||||||
var children = element? getTranslatableChildren(element) : document.childNodes;
|
var children = element? getTranslatableChildren(element) : document.childNodes;
|
||||||
for (var i=0, n=children.length; i < n; i++) {
|
for (var i=0, n=children.length; i < n; i++) {
|
||||||
this.translateNode(translations, children[i]);
|
this.translateNode(translations, children[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate element itself if necessary
|
// translate element itself if necessary
|
||||||
this.translateNode(translations, element);
|
this.translateNode(translations, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
function asyncForEach(list, iterator, cb) {
|
function asyncForEach(list, iterator, cb) {
|
||||||
var i = 0
|
var i = 0
|
||||||
, n = list.length;
|
, n = list.length
|
||||||
iterator(list[i], i, function each(err) {
|
iterator(list[i], i, function each(err) {
|
||||||
if(err) consoleLog(err);
|
if(err) consoleLog(err)
|
||||||
i++;
|
i++
|
||||||
if (i < n) return iterator(list[i],i, each);
|
if (i < n) return iterator(list[i],i, each);
|
||||||
cb();
|
cb()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTranslatableChildren(element) {
|
function getTranslatableChildren(element) {
|
||||||
if(!document.querySelectorAll) {
|
if(!document.querySelectorAll) {
|
||||||
if (!element) return [];
|
if (!element) return []
|
||||||
var nodes = element.getElementsByTagName('*')
|
var nodes = element.getElementsByTagName('*')
|
||||||
, l10nElements = [];
|
, l10nElements = []
|
||||||
for (var i=0, n=nodes.length; i < n; i++) {
|
for (var i=0, n=nodes.length; i < n; i++) {
|
||||||
if (nodes[i].getAttribute('data-l10n-id'))
|
if (nodes[i].getAttribute('data-l10n-id'))
|
||||||
l10nElements.push(nodes[i]);
|
l10nElements.push(nodes[i]);
|
||||||
}
|
}
|
||||||
return l10nElements;
|
return l10nElements
|
||||||
}
|
}
|
||||||
return element.querySelectorAll('*[data-l10n-id]');
|
return element.querySelectorAll('*[data-l10n-id]')
|
||||||
}
|
}
|
||||||
|
|
||||||
html10n.get = function(id, args) {
|
html10n.get = function(id, args) {
|
||||||
var translations = html10n.translations;
|
var translations = html10n.translations
|
||||||
if(!translations) return consoleWarn('No translations available (yet)');
|
if(!translations) return consoleWarn('No translations available (yet)')
|
||||||
if(!translations[id]) return consoleWarn('Could not find string '+id);
|
if(!translations[id]) return consoleWarn('Could not find string '+id)
|
||||||
|
|
||||||
// apply args
|
// apply args
|
||||||
var str = substArguments(translations[id], args);
|
var str = substArguments(translations[id], args)
|
||||||
|
|
||||||
// apply macros
|
// apply macros
|
||||||
return substMacros(id, str, args);
|
return substMacros(id, str, args)
|
||||||
|
|
||||||
// replace {{arguments}} with their values or the
|
// replace {{arguments}} with their values or the
|
||||||
// associated translation string (based on its key)
|
// associated translation string (based on its key)
|
||||||
function substArguments(str, args) {
|
function substArguments(str, args) {
|
||||||
var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/
|
var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/
|
||||||
, match;
|
, match
|
||||||
|
|
||||||
while (match = reArgs.exec(str)) {
|
while (match = reArgs.exec(str)) {
|
||||||
if (!match || match.length < 2)
|
if (!match || match.length < 2)
|
||||||
return str; // argument key not found
|
return str // argument key not found
|
||||||
|
|
||||||
var arg = match[1]
|
var arg = match[1]
|
||||||
, sub = '';
|
, sub = ''
|
||||||
if (arg in args) {
|
if (arg in args) {
|
||||||
sub = args[arg];
|
sub = args[arg]
|
||||||
} else if (arg in translations) {
|
} else if (arg in translations) {
|
||||||
sub = translations[arg];
|
sub = translations[arg]
|
||||||
} else {
|
} else {
|
||||||
consoleWarn('Could not find argument {{' + arg + '}}');
|
consoleWarn('Could not find argument {{' + arg + '}}')
|
||||||
return str;
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
str = str.substring(0, match.index) + sub + str.substr(match.index + match[0].length);
|
str = str.substring(0, match.index) + sub + str.substr(match.index + match[0].length)
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace {[macros]} with their values
|
// replace {[macros]} with their values
|
||||||
|
@ -766,21 +773,21 @@ window.html10n = (function(window, document, undefined) {
|
||||||
// a macro has been found
|
// a macro has been found
|
||||||
// Note: at the moment, only one parameter is supported
|
// Note: at the moment, only one parameter is supported
|
||||||
var macroName = reMatch[1]
|
var macroName = reMatch[1]
|
||||||
, paramName = reMatch[2];
|
, paramName = reMatch[2]
|
||||||
|
|
||||||
if (!(macroName in gMacros)) return str;
|
if (!(macroName in gMacros)) return str
|
||||||
|
|
||||||
var param;
|
var param
|
||||||
if (args && paramName in args) {
|
if (args && paramName in args) {
|
||||||
param = args[paramName];
|
param = args[paramName]
|
||||||
} else if (paramName in translations) {
|
} else if (paramName in translations) {
|
||||||
param = translations[paramName];
|
param = translations[paramName]
|
||||||
}
|
}
|
||||||
|
|
||||||
// there's no macro parser yet: it has to be defined in gMacros
|
// there's no macro parser yet: it has to be defined in gMacros
|
||||||
var macro = html10n.macros[macroName];
|
var macro = html10n.macros[macroName]
|
||||||
str = macro(translations, key, str, param);
|
str = macro(translations, key, str, param)
|
||||||
return str;
|
return str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,26 +795,26 @@ window.html10n = (function(window, document, undefined) {
|
||||||
* Applies translations to a DOM node (recursive)
|
* Applies translations to a DOM node (recursive)
|
||||||
*/
|
*/
|
||||||
html10n.translateNode = function(translations, node) {
|
html10n.translateNode = function(translations, node) {
|
||||||
var str = {};
|
var str = {}
|
||||||
|
|
||||||
// get id
|
// get id
|
||||||
str.id = node.getAttribute('data-l10n-id');
|
str.id = node.getAttribute('data-l10n-id')
|
||||||
if (!str.id) return;
|
if (!str.id) return
|
||||||
|
|
||||||
if(!translations[str.id]) return consoleWarn('Couldn\'t find translation key '+str.id);
|
if(!translations[str.id]) return consoleWarn('Couldn\'t find translation key '+str.id)
|
||||||
|
|
||||||
// get args
|
// get args
|
||||||
if(window.JSON) {
|
if(window.JSON) {
|
||||||
str.args = JSON.parse(node.getAttribute('data-l10n-args'));
|
str.args = JSON.parse(node.getAttribute('data-l10n-args'))
|
||||||
}else{
|
}else{
|
||||||
try{
|
try{
|
||||||
str.args = eval(node.getAttribute('data-l10n-args'));
|
str.args = eval(node.getAttribute('data-l10n-args'))
|
||||||
}catch(e) {
|
}catch(e) {
|
||||||
consoleWarn('Couldn\'t parse args for '+str.id);
|
consoleWarn('Couldn\'t parse args for '+str.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
str.str = html10n.get(str.id, str.args);
|
str.str = html10n.get(str.id, str.args)
|
||||||
|
|
||||||
// get attribute name to apply str to
|
// get attribute name to apply str to
|
||||||
var prop
|
var prop
|
||||||
|
@ -817,31 +824,31 @@ window.html10n = (function(window, document, undefined) {
|
||||||
, "innerHTML": 1
|
, "innerHTML": 1
|
||||||
, "alt": 1
|
, "alt": 1
|
||||||
, "textContent": 1
|
, "textContent": 1
|
||||||
};
|
}
|
||||||
if (index > 0 && str.id.substr(index + 1) in attrList) { // an attribute has been specified
|
if (index > 0 && str.id.substr(index + 1) in attrList) { // an attribute has been specified
|
||||||
prop = str.id.substr(index + 1);
|
prop = str.id.substr(index + 1)
|
||||||
} else { // no attribute: assuming text content by default
|
} else { // no attribute: assuming text content by default
|
||||||
prop = document.body.textContent ? 'textContent' : 'innerText';
|
prop = document.body.textContent ? 'textContent' : 'innerText'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply translation
|
// Apply translation
|
||||||
if (node.children.length === 0 || prop != 'textContent') {
|
if (node.children.length === 0 || prop != 'textContent') {
|
||||||
node[prop] = str.str;
|
node[prop] = str.str
|
||||||
} else {
|
} else {
|
||||||
var children = node.childNodes,
|
var children = node.childNodes,
|
||||||
found = false;
|
found = false
|
||||||
for (var i=0, n=children.length; i < n; i++) {
|
for (var i=0, n=children.length; i < n; i++) {
|
||||||
if (children[i].nodeType === 3 && /\S/.test(children[i].textContent)) {
|
if (children[i].nodeType === 3 && /\S/.test(children[i].textContent)) {
|
||||||
if (!found) {
|
if (!found) {
|
||||||
children[i].nodeValue = str.str;
|
children[i].nodeValue = str.str
|
||||||
found = true;
|
found = true
|
||||||
} else {
|
} else {
|
||||||
children[i].nodeValue = '';
|
children[i].nodeValue = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
consoleWarn('Unexpected error: could not translate element content for key '+str.id, node);
|
consoleWarn('Unexpected error: could not translate element content for key '+str.id, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -852,32 +859,32 @@ window.html10n = (function(window, document, undefined) {
|
||||||
*/
|
*/
|
||||||
html10n.build = function(langs, cb) {
|
html10n.build = function(langs, cb) {
|
||||||
var that = this
|
var that = this
|
||||||
, build = {};
|
, build = {}
|
||||||
|
|
||||||
asyncForEach(langs, function (lang, i, next) {
|
asyncForEach(langs, function (lang, i, next) {
|
||||||
if(!lang) return next();
|
if(!lang) return next();
|
||||||
that.loader.load(lang, next);
|
that.loader.load(lang, next)
|
||||||
}, function() {
|
}, function() {
|
||||||
var lang;
|
var lang
|
||||||
langs.reverse();
|
langs.reverse()
|
||||||
|
|
||||||
// loop through priority array...
|
// loop through priority array...
|
||||||
for (var i=0, n=langs.length; i < n; i++) {
|
for (var i=0, n=langs.length; i < n; i++) {
|
||||||
lang = langs[i];
|
lang = langs[i]
|
||||||
|
|
||||||
if(!lang || !(lang in that.loader.langs)) continue;
|
if(!lang || !(lang in that.loader.langs)) continue;
|
||||||
|
|
||||||
// ... and apply all strings of the current lang in the list
|
// ... and apply all strings of the current lang in the list
|
||||||
// to our build object
|
// to our build object
|
||||||
for (var string in that.loader.langs[lang]) {
|
for (var string in that.loader.langs[lang]) {
|
||||||
build[string] = that.loader.langs[lang][string];
|
build[string] = that.loader.langs[lang][string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// the last applied lang will be exposed as the
|
// the last applied lang will be exposed as the
|
||||||
// lang the page was translated to
|
// lang the page was translated to
|
||||||
that.language = lang;
|
that.language = lang
|
||||||
}
|
}
|
||||||
cb(null, build);
|
cb(null, build)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,8 +900,8 @@ window.html10n = (function(window, document, undefined) {
|
||||||
* Returns the direction of the language returned be html10n#getLanguage
|
* Returns the direction of the language returned be html10n#getLanguage
|
||||||
*/
|
*/
|
||||||
html10n.getDirection = function() {
|
html10n.getDirection = function() {
|
||||||
var langCode = this.language.indexOf('-') == -1? this.language : this.language.substr(0, this.language.indexOf('-'));
|
var langCode = this.language.indexOf('-') == -1? this.language : this.language.substr(0, this.language.indexOf('-'))
|
||||||
return html10n.rtl.indexOf(langCode) == -1? 'ltr' : 'rtl';
|
return html10n.rtl.indexOf(langCode) == -1? 'ltr' : 'rtl'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -903,28 +910,28 @@ window.html10n = (function(window, document, undefined) {
|
||||||
html10n.index = function () {
|
html10n.index = function () {
|
||||||
// Find all <link>s
|
// Find all <link>s
|
||||||
var links = document.getElementsByTagName('link')
|
var links = document.getElementsByTagName('link')
|
||||||
, resources = [];
|
, resources = []
|
||||||
for (var i=0, n=links.length; i < n; i++) {
|
for (var i=0, n=links.length; i < n; i++) {
|
||||||
if (links[i].type != 'application/l10n+json')
|
if (links[i].type != 'application/l10n+json')
|
||||||
continue;
|
continue;
|
||||||
resources.push(links[i].href);
|
resources.push(links[i].href)
|
||||||
}
|
}
|
||||||
this.loader = new Loader(resources);
|
this.loader = new Loader(resources)
|
||||||
this.trigger('indexed');
|
this.trigger('indexed')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.addEventListener) // modern browsers and IE9+
|
if (document.addEventListener) // modern browsers and IE9+
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
html10n.index();
|
html10n.index()
|
||||||
}, false);
|
}, false)
|
||||||
else if (window.attachEvent)
|
else if (window.attachEvent)
|
||||||
window.attachEvent('onload', function() {
|
window.attachEvent('onload', function() {
|
||||||
html10n.index();
|
html10n.index()
|
||||||
}, false);
|
}, false)
|
||||||
|
|
||||||
// gettext-like shortcut
|
// gettext-like shortcut
|
||||||
if (window._ === undefined)
|
if (window._ === undefined)
|
||||||
window._ = html10n.get;
|
window._ = html10n.get;
|
||||||
|
|
||||||
return html10n;
|
return html10n
|
||||||
})(window, document);
|
})(window, document)
|
|
@ -191,7 +191,7 @@ function handshake()
|
||||||
createCookie("token", token, 60);
|
createCookie("token", token, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionID = readCookie("sessionID");
|
var sessionID = decodeURIComponent(readCookie("sessionID"));
|
||||||
var password = readCookie("password");
|
var password = readCookie("password");
|
||||||
|
|
||||||
var msg = {
|
var msg = {
|
||||||
|
@ -242,7 +242,7 @@ function handshake()
|
||||||
|
|
||||||
pad.collabClient.setChannelState("RECONNECTING");
|
pad.collabClient.setChannelState("RECONNECTING");
|
||||||
|
|
||||||
disconnectTimeout = setTimeout(disconnectEvent, 10000);
|
disconnectTimeout = setTimeout(disconnectEvent, 20000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -252,14 +252,22 @@ function handshake()
|
||||||
socket.on('message', function(obj)
|
socket.on('message', function(obj)
|
||||||
{
|
{
|
||||||
//the access was not granted, give the user a message
|
//the access was not granted, give the user a message
|
||||||
if(!receivedClientVars && obj.accessStatus)
|
if(obj.accessStatus)
|
||||||
{
|
{
|
||||||
$('.passForm').submit(require(module.id).savePassword);
|
if(!receivedClientVars)
|
||||||
|
$('.passForm').submit(require(module.id).savePassword);
|
||||||
|
|
||||||
if(obj.accessStatus == "deny")
|
if(obj.accessStatus == "deny")
|
||||||
{
|
{
|
||||||
$('#loading').hide();
|
$('#loading').hide();
|
||||||
$("#permissionDenied").show();
|
$("#permissionDenied").show();
|
||||||
|
|
||||||
|
if(receivedClientVars)
|
||||||
|
{
|
||||||
|
// got kicked
|
||||||
|
$("#editorcontainer").hide();
|
||||||
|
$("#editorloadingbox").show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(obj.accessStatus == "needPassword")
|
else if(obj.accessStatus == "needPassword")
|
||||||
{
|
{
|
||||||
|
@ -365,8 +373,7 @@ function handshake()
|
||||||
|
|
||||||
$.extend($.gritter.options, {
|
$.extend($.gritter.options, {
|
||||||
position: 'bottom-right', // defaults to 'top-right' but can be 'bottom-left', 'bottom-right', 'top-left', 'top-right' (added in 1.7.1)
|
position: 'bottom-right', // defaults to 'top-right' but can be 'bottom-left', 'bottom-right', 'top-left', 'top-right' (added in 1.7.1)
|
||||||
fade_in_speed: 'medium', // how fast notifications fade in (string or int)
|
fade: false, // dont fade, too jerky on mobile
|
||||||
fade_out_speed: 2000, // how fast the notices fade out
|
|
||||||
time: 6000 // hang on the screen for...
|
time: 6000 // hang on the screen for...
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -442,6 +449,7 @@ var pad = {
|
||||||
|
|
||||||
//initialize the chat
|
//initialize the chat
|
||||||
chat.init(this);
|
chat.init(this);
|
||||||
|
padcookie.init(); // initialize the cookies
|
||||||
pad.initTime = +(new Date());
|
pad.initTime = +(new Date());
|
||||||
pad.padOptions = clientVars.initialOptions;
|
pad.padOptions = clientVars.initialOptions;
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,6 @@ var padconnectionstatus = (function()
|
||||||
},
|
},
|
||||||
isFullyConnected: function()
|
isFullyConnected: function()
|
||||||
{
|
{
|
||||||
padmodals.hideOverlay();
|
|
||||||
return status.what == 'connected';
|
return status.what == 'connected';
|
||||||
},
|
},
|
||||||
getStatus: function()
|
getStatus: function()
|
||||||
|
|
|
@ -40,22 +40,10 @@ var padmodals = (function()
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
showOverlay: function(duration) {
|
showOverlay: function(duration) {
|
||||||
$("#overlay").show().css(
|
$("#overlay").show();
|
||||||
{
|
|
||||||
'opacity': 0
|
|
||||||
}).animate(
|
|
||||||
{
|
|
||||||
'opacity': 1
|
|
||||||
}, duration);
|
|
||||||
},
|
},
|
||||||
hideOverlay: function(duration) {
|
hideOverlay: function(duration) {
|
||||||
$("#overlay").animate(
|
$("#overlay").hide();
|
||||||
{
|
|
||||||
'opacity': 0
|
|
||||||
}, duration, function()
|
|
||||||
{
|
|
||||||
$("#modaloverlay").hide();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return self;
|
return self;
|
||||||
|
|
|
@ -1,118 +1,77 @@
|
||||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
||||||
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
|
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
|
||||||
var npm = require("npm");
|
var npm = require("npm");
|
||||||
var RegClient = require("npm-registry-client")
|
|
||||||
|
|
||||||
var registry = new RegClient(
|
var npmIsLoaded = false;
|
||||||
{ registry: "http://registry.npmjs.org"
|
var withNpm = function (npmfn) {
|
||||||
, cache: npm.cache }
|
if(npmIsLoaded) return npmfn();
|
||||||
);
|
|
||||||
|
|
||||||
var withNpm = function (npmfn, final, cb) {
|
|
||||||
npm.load({}, function (er) {
|
npm.load({}, function (er) {
|
||||||
if (er) return cb({progress:1, error:er});
|
if (er) return npmfn(er);
|
||||||
|
npmIsLoaded = true;
|
||||||
npm.on("log", function (message) {
|
npm.on("log", function (message) {
|
||||||
cb({progress: 0.5, message:message.msg + ": " + message.pref});
|
console.log('npm: ',message)
|
||||||
});
|
|
||||||
npmfn(function (er, data) {
|
|
||||||
if (er) {
|
|
||||||
console.error(er);
|
|
||||||
return cb({progress:1, error: er.message});
|
|
||||||
}
|
|
||||||
if (!data) data = {};
|
|
||||||
data.progress = 1;
|
|
||||||
data.message = "Done.";
|
|
||||||
cb(data);
|
|
||||||
final();
|
|
||||||
});
|
});
|
||||||
|
npmfn();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// All these functions call their callback multiple times with
|
|
||||||
// {progress:[0,1], message:STRING, error:object}. They will call it
|
|
||||||
// with progress = 1 at least once, and at all times will either
|
|
||||||
// message or error be present, not both. It can be called multiple
|
|
||||||
// times for all values of propgress except for 1.
|
|
||||||
|
|
||||||
exports.uninstall = function(plugin_name, cb) {
|
exports.uninstall = function(plugin_name, cb) {
|
||||||
withNpm(
|
withNpm(function (er) {
|
||||||
function (cb) {
|
if (er) return cb && cb(er);
|
||||||
npm.commands.uninstall([plugin_name], function (er) {
|
npm.commands.uninstall([plugin_name], function (er) {
|
||||||
|
if (er) return cb && cb(er);
|
||||||
|
hooks.aCallAll("pluginUninstall", {plugin_name: plugin_name}, function (er, data) {
|
||||||
if (er) return cb(er);
|
if (er) return cb(er);
|
||||||
hooks.aCallAll("pluginUninstall", {plugin_name: plugin_name}, function (er, data) {
|
plugins.update(cb);
|
||||||
if (er) return cb(er);
|
hooks.aCallAll("restartServer", {}, function () {});
|
||||||
plugins.update(cb);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
function () {
|
});
|
||||||
hooks.aCallAll("restartServer", {}, function () {});
|
|
||||||
},
|
|
||||||
cb
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.install = function(plugin_name, cb) {
|
exports.install = function(plugin_name, cb) {
|
||||||
withNpm(
|
withNpm(function (er) {
|
||||||
function (cb) {
|
if (er) return cb && cb(er);
|
||||||
npm.commands.install([plugin_name], function (er) {
|
npm.commands.install([plugin_name], function (er) {
|
||||||
|
if (er) return cb && cb(er);
|
||||||
|
hooks.aCallAll("pluginInstall", {plugin_name: plugin_name}, function (er, data) {
|
||||||
if (er) return cb(er);
|
if (er) return cb(er);
|
||||||
hooks.aCallAll("pluginInstall", {plugin_name: plugin_name}, function (er, data) {
|
plugins.update(cb);
|
||||||
if (er) return cb(er);
|
hooks.aCallAll("restartServer", {}, function () {});
|
||||||
plugins.update(cb);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
function () {
|
});
|
||||||
hooks.aCallAll("restartServer", {}, function () {});
|
|
||||||
},
|
|
||||||
cb
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.searchCache = null;
|
exports.availablePlugins = null;
|
||||||
|
var cacheTimestamp = 0;
|
||||||
|
|
||||||
exports.search = function(query, cache, cb) {
|
exports.getAvailablePlugins = function(maxCacheAge, cb) {
|
||||||
withNpm(
|
withNpm(function (er) {
|
||||||
function (cb) {
|
if (er) return cb && cb(er);
|
||||||
var getData = function (cb) {
|
if(exports.availablePlugins && maxCacheAge && Math.round(+new Date/1000)-cacheTimestamp <= maxCacheAge) {
|
||||||
if (cache && exports.searchCache) {
|
return cb && cb(null, exports.availablePlugins)
|
||||||
cb(null, exports.searchCache);
|
}
|
||||||
} else {
|
npm.commands.search(['ep_'], /*silent?*/true, function(er, results) {
|
||||||
registry.get(
|
if(er) return cb && cb(er);
|
||||||
"/-/all", 600, false, true,
|
exports.availablePlugins = results;
|
||||||
function (er, data) {
|
cacheTimestamp = Math.round(+new Date/1000);
|
||||||
if (er) return cb(er);
|
cb && cb(null, results)
|
||||||
exports.searchCache = data;
|
})
|
||||||
cb(er, data);
|
});
|
||||||
}
|
};
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
exports.search = function(searchTerm, maxCacheAge, cb) {
|
||||||
getData(
|
exports.getAvailablePlugins(maxCacheAge, function(er, results) {
|
||||||
function (er, data) {
|
if(er) return cb && cb(er);
|
||||||
if (er) return cb(er);
|
var res = {};
|
||||||
var res = {};
|
searchTerm = searchTerm.toLowerCase();
|
||||||
var i = 0;
|
for (var pluginName in results) { // for every available plugin
|
||||||
var pattern = query.pattern.toLowerCase();
|
if (pluginName.indexOf(plugins.prefix) != 0) continue; // TODO: Also search in keywords here!
|
||||||
for (key in data) { // for every plugin in the data from npm
|
if(pluginName.indexOf(searchTerm) < 0 && results[pluginName].description.indexOf(searchTerm) < 0) continue;
|
||||||
if ( key.indexOf(plugins.prefix) == 0
|
res[pluginName] = results[pluginName];
|
||||||
&& key.indexOf(pattern) != -1
|
}
|
||||||
|| key.indexOf(plugins.prefix) == 0
|
cb && cb(null, res)
|
||||||
&& data[key].description.indexOf(pattern) != -1
|
})
|
||||||
) { // If the name contains ep_ and the search string is in the name or description
|
|
||||||
i++;
|
|
||||||
if (i > query.offset
|
|
||||||
&& i <= query.offset + query.limit) {
|
|
||||||
res[key] = data[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cb(null, {results:res, query: query, total:i});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
function () { },
|
|
||||||
cb
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -116,7 +116,7 @@ function init() {
|
||||||
//sends a message over the socket
|
//sends a message over the socket
|
||||||
function sendSocketMsg(type, data)
|
function sendSocketMsg(type, data)
|
||||||
{
|
{
|
||||||
var sessionID = readCookie("sessionID");
|
var sessionID = decodeURIComponent(readCookie("sessionID"));
|
||||||
var password = readCookie("password");
|
var password = readCookie("password");
|
||||||
|
|
||||||
var msg = { "component" : "pad", // FIXME: Remove this stupidity!
|
var msg = { "component" : "pad", // FIXME: Remove this stupidity!
|
||||||
|
|
|
@ -28,43 +28,11 @@
|
||||||
<li><a href="plugins/info">Troubleshooting information</a> </li>
|
<li><a href="plugins/info">Troubleshooting information</a> </li>
|
||||||
<% e.end_block(); %>
|
<% e.end_block(); %>
|
||||||
</ul>
|
</ul>
|
||||||
<div id="progress"><img src="../static/img/loading.gif"> <span class="message"></span></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="innerwrapper">
|
<div class="innerwrapper">
|
||||||
<h2>Installed plugins</h2>
|
<h2>Installed plugins</h2>
|
||||||
<table>
|
<table class="installed-results">
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Version</th>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="template">
|
|
||||||
<tr id="installed-plugin-template">
|
|
||||||
<td class="name" data-label="Name"></td>
|
|
||||||
<td class="description" data-label="Description"></td>
|
|
||||||
<td class="version" data-label="Version"></td>
|
|
||||||
<td class="actions">
|
|
||||||
<input type="button" value="Uninstall" class="do-uninstall">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
<tbody id="installed-plugins">
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="paged listing search-results">
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<h2>Available plugins</h2>
|
|
||||||
<form>
|
|
||||||
<input type="text" name="search" placeholder="Search for plugins to install" id="search-query">
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
@ -74,22 +42,69 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="template">
|
<tbody class="template">
|
||||||
<tr>
|
<tr id="installed-plugin-template">
|
||||||
<td class="name" data-label="Name"></td>
|
<td class="name" data-label="Name"></td>
|
||||||
<td class="description" data-label="Description"></td>
|
<td class="description" data-label="Description"></td>
|
||||||
<td class="version" data-label="Version"></td>
|
<td class="version" data-label="Version"></td>
|
||||||
<td class="actions">
|
<td>
|
||||||
<input type="button" value="Install" class="do-install">
|
<div class="actions">
|
||||||
</td>
|
<input type="button" value="Uninstall" class="do-uninstall">
|
||||||
|
<div class="progress"><p><img src="../static/img/loading.gif"/></p><p><span class="message"></span></p></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tbody class="results">
|
<tbody id="installed-plugins">
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tbody class="messages">
|
||||||
|
<tr><td></td><td>
|
||||||
|
<p class="nothing-installed">You haven't installed any plugins yet.</p>
|
||||||
|
<p class="fetching"><img src="../static/img/loading.gif"/><br/>Fetching installed plugins...</p>
|
||||||
|
</td><td></td></tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<input type="button" value="<<" class="do-prev-page">
|
|
||||||
<span class="offset"></span>..<span class="limit"></span> of <span class="total"></span>.
|
<div class="paged listing search-results">
|
||||||
<input type="button" value=">>" class="do-next-page">
|
<div class="separator"></div>
|
||||||
</div>
|
|
||||||
|
<h2>Available plugins</h2>
|
||||||
|
<form>
|
||||||
|
<input type="text" name="search" disabled placeholder="Search for plugins to install" id="search-query">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sort up" data-label="name">Name</th>
|
||||||
|
<th class="sort none" data-label="description">Description</th>
|
||||||
|
<th class="sort none" data-label="version">Version</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="template">
|
||||||
|
<tr>
|
||||||
|
<td class="name" data-label="Name"></td>
|
||||||
|
<td class="description" data-label="Description"></td>
|
||||||
|
<td class="version" data-label="Version"></td>
|
||||||
|
<td>
|
||||||
|
<div class="actions">
|
||||||
|
<input type="button" value="Install" class="do-install">
|
||||||
|
<div class="progress"><p><img src="../static/img/loading.gif"/></p><p><span class="message"></span></p></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tbody class="results">
|
||||||
|
</tbody>
|
||||||
|
<tbody class="messages">
|
||||||
|
<tr><td></td><td>
|
||||||
|
<div class="search-progress" class="progress"><img src="../static/img/loading.gif"/></div>
|
||||||
|
<p class="nothing-found">No plugins found.</p>
|
||||||
|
<p class="fetching"><img src="../static/img/loading.gif"/><br/>Fetching catalogue...</p>
|
||||||
|
</td><td></td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -195,7 +195,9 @@
|
||||||
<div id="wrongPassword">
|
<div id="wrongPassword">
|
||||||
<p data-l10n-id="pad.wrongPassword">Your password was wrong</p>
|
<p data-l10n-id="pad.wrongPassword">Your password was wrong</p>
|
||||||
</div>
|
</div>
|
||||||
|
<% e.begin_block("loading"); %>
|
||||||
<p data-l10n-id="pad.loading" id="loading">Loading...</p>
|
<p data-l10n-id="pad.loading" id="loading">Loading...</p>
|
||||||
|
<% e.end_block(); %>
|
||||||
<noscript><strong>Sorry, you have to enable Javascript in order to use this.</strong></noscript>
|
<noscript><strong>Sorry, you have to enable Javascript in order to use this.</strong></noscript>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -376,7 +378,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="chatbox">
|
<div id="chatbox">
|
||||||
<div id="titlebar"><span id ="titlelabel" data-l10n-id="pad.chat"></span><a id="titlecross" onClick="chat.hide();return false;">- </a></div>
|
<div id="titlebar"><span id ="titlelabel" data-l10n-id="pad.chat"></span>
|
||||||
|
<a id="titlecross" onClick="chat.hide();return false;">- </a>
|
||||||
|
<a id="titlesticky" onClick="chat.stickToScreen(true);$('#options-stickychat').prop('checked', true);return false;" title="Stick chat to screen">█ </a>
|
||||||
|
</div>
|
||||||
<div id="chattext" class="authorColors">
|
<div id="chattext" class="authorColors">
|
||||||
<img alt="loading.." id="chatloadmessagesball" class="chatloadmessages" src="../static/img/loading.gif" align="top">
|
<img alt="loading.." id="chatloadmessagesball" class="chatloadmessages" src="../static/img/loading.gif" align="top">
|
||||||
<button id="chatloadmessagesbutton" class="chatloadmessages" data-l10n-id="pad.chat.loadmessages"></button>
|
<button id="chatloadmessagesbutton" class="chatloadmessages" data-l10n-id="pad.chat.loadmessages"></button>
|
||||||
|
|
334
tests/frontend/specs/caret.js
Normal file
334
tests/frontend/specs/caret.js
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
describe("As the caret is moved is the UI properly updated?", function(){
|
||||||
|
var padName;
|
||||||
|
var numberOfRows = 50;
|
||||||
|
|
||||||
|
it("creates a pad", function(done) {
|
||||||
|
padName = helper.newPad(done);
|
||||||
|
this.timeout(60000);
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Tests to do
|
||||||
|
* Keystroke up (38), down (40), left (37), right (39) with and without special keys IE control / shift
|
||||||
|
* Page up (33) / down (34) with and without special keys
|
||||||
|
* Page up on the first line shouldn't move the viewport
|
||||||
|
* Down down on the last line shouldn't move the viewport
|
||||||
|
* Down arrow on any other line except the last lines shouldn't move the viewport
|
||||||
|
* Do all of the above tests after a copy/paste event
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Challenges
|
||||||
|
* How do we keep the authors focus on a line if the lines above the author are modified? We should only redraw the user to a location if they are typing and make sure shift and arrow keys aren't redrawing the UI else highlight - copy/paste would get broken
|
||||||
|
* How can we simulate an edit event in the test framework?
|
||||||
|
*/
|
||||||
|
|
||||||
|
// THIS DOESNT WORK AS IT DOESNT MOVE THE CURSOR!
|
||||||
|
it("down arrow", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
$newFirstTextElement.focus();
|
||||||
|
keyEvent(inner$, 37, false, false); // arrow down
|
||||||
|
keyEvent(inner$, 37, false, false); // arrow down
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
it("Creates N lines", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var chrome$ = helper.padChrome$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
|
||||||
|
prepareDocument(numberOfRows, $newFirstTextElement); // N lines into the first div as a target
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
return inner$("div").first().text().length == 6;
|
||||||
|
}).done(function(){ // Once the DOM has registered the items
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Moves caret up a line", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalCaretPosition = caretPosition(inner$);
|
||||||
|
var originalPos = originalCaretPosition.y;
|
||||||
|
var newCaretPos;
|
||||||
|
keyEvent(inner$, 38, false, false); // arrow up
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
var newCaretPosition = caretPosition(inner$);
|
||||||
|
newCaretPos = newCaretPosition.y;
|
||||||
|
return (newCaretPos < originalPos);
|
||||||
|
}).done(function(){
|
||||||
|
expect(newCaretPos).to.be.lessThan(originalPos);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Moves caret down a line", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalCaretPosition = caretPosition(inner$);
|
||||||
|
var originalPos = originalCaretPosition.y;
|
||||||
|
var newCaretPos;
|
||||||
|
keyEvent(inner$, 40, false, false); // arrow down
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
var newCaretPosition = caretPosition(inner$);
|
||||||
|
newCaretPos = newCaretPosition.y;
|
||||||
|
return (newCaretPos > originalPos);
|
||||||
|
}).done(function(){
|
||||||
|
expect(newCaretPos).to.be.moreThan(originalPos);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Moves caret to top of doc", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalCaretPosition = caretPosition(inner$);
|
||||||
|
var originalPos = originalCaretPosition.y;
|
||||||
|
var newCaretPos;
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
while(i < numberOfRows){ // press pageup key N times
|
||||||
|
keyEvent(inner$, 33, false, false);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
var newCaretPosition = caretPosition(inner$);
|
||||||
|
newCaretPos = newCaretPosition.y;
|
||||||
|
return (newCaretPos < originalPos);
|
||||||
|
}).done(function(){
|
||||||
|
expect(newCaretPos).to.be.lessThan(originalPos);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Moves caret right a position", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalCaretPosition = caretPosition(inner$);
|
||||||
|
var originalPos = originalCaretPosition.x;
|
||||||
|
var newCaretPos;
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
var newCaretPosition = caretPosition(inner$);
|
||||||
|
newCaretPos = newCaretPosition.x;
|
||||||
|
return (newCaretPos > originalPos);
|
||||||
|
}).done(function(){
|
||||||
|
expect(newCaretPos).to.be.moreThan(originalPos);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Moves caret left a position", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalCaretPosition = caretPosition(inner$);
|
||||||
|
var originalPos = originalCaretPosition.x;
|
||||||
|
var newCaretPos;
|
||||||
|
keyEvent(inner$, 33, false, false); // arrow left
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
var newCaretPosition = caretPosition(inner$);
|
||||||
|
newCaretPos = newCaretPosition.x;
|
||||||
|
return (newCaretPos < originalPos);
|
||||||
|
}).done(function(){
|
||||||
|
expect(newCaretPos).to.be.lessThan(originalPos);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Moves caret to the next line using right arrow", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalCaretPosition = caretPosition(inner$);
|
||||||
|
var originalPos = originalCaretPosition.y;
|
||||||
|
var newCaretPos;
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
keyEvent(inner$, 39, false, false); // arrow right
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
var newCaretPosition = caretPosition(inner$);
|
||||||
|
newCaretPos = newCaretPosition.y;
|
||||||
|
return (newCaretPos > originalPos);
|
||||||
|
}).done(function(){
|
||||||
|
expect(newCaretPos).to.be.moreThan(originalPos);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Moves caret to the previous line using left arrow", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalCaretPosition = caretPosition(inner$);
|
||||||
|
var originalPos = originalCaretPosition.y;
|
||||||
|
var newCaretPos;
|
||||||
|
keyEvent(inner$, 33, false, false); // arrow left
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
var newCaretPosition = caretPosition(inner$);
|
||||||
|
newCaretPos = newCaretPosition.y;
|
||||||
|
return (newCaretPos < originalPos);
|
||||||
|
}).done(function(){
|
||||||
|
expect(newCaretPos).to.be.lessThan(originalPos);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
it("Creates N rows, changes height of rows, updates UI by caret key events", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var chrome$ = helper.padChrome$;
|
||||||
|
var numberOfRows = 50;
|
||||||
|
|
||||||
|
//ace creates a new dom element when you press a keystroke, so just get the first text element again
|
||||||
|
var $newFirstTextElement = inner$("div").first();
|
||||||
|
var originalDivHeight = inner$("div").first().css("height");
|
||||||
|
prepareDocument(numberOfRows, $newFirstTextElement); // N lines into the first div as a target
|
||||||
|
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
return inner$("div").first().text().length == 6;
|
||||||
|
}).done(function(){ // Once the DOM has registered the items
|
||||||
|
inner$("div").each(function(index){ // Randomize the item heights (replicates images / headings etc)
|
||||||
|
var random = Math.floor(Math.random() * (50)) + 20;
|
||||||
|
$(this).css("height", random+"px");
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(caretPosition(inner$));
|
||||||
|
var newDivHeight = inner$("div").first().css("height");
|
||||||
|
var heightHasChanged = originalDivHeight != newDivHeight; // has the new div height changed from the original div height
|
||||||
|
expect(heightHasChanged).to.be(true); // expect the first line to be blank
|
||||||
|
});
|
||||||
|
|
||||||
|
// Is this Element now visible to the pad user?
|
||||||
|
helper.waitFor(function(){ // Wait for the DOM to register the new items
|
||||||
|
return isScrolledIntoView(inner$("div:nth-child("+numberOfRows+")"), inner$); // Wait for the DOM to scroll into place
|
||||||
|
}).done(function(){ // Once the DOM has registered the items
|
||||||
|
inner$("div").each(function(index){ // Randomize the item heights (replicates images / headings etc)
|
||||||
|
var random = Math.floor(Math.random() * (80 - 20 + 1)) + 20;
|
||||||
|
$(this).css("height", random+"px");
|
||||||
|
});
|
||||||
|
|
||||||
|
var newDivHeight = inner$("div").first().css("height");
|
||||||
|
var heightHasChanged = originalDivHeight != newDivHeight; // has the new div height changed from the original div height
|
||||||
|
expect(heightHasChanged).to.be(true); // expect the first line to be blank
|
||||||
|
});
|
||||||
|
var i = 0;
|
||||||
|
while(i < numberOfRows){ // press down arrow
|
||||||
|
console.log("dwn");
|
||||||
|
keyEvent(inner$, 40, false, false);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does scrolling back up the pad with the up arrow show the correct contents?
|
||||||
|
helper.waitFor(function(){ // Wait for the new position to be in place
|
||||||
|
try{
|
||||||
|
return isScrolledIntoView(inner$("div:nth-child("+numberOfRows+")"), inner$); // Wait for the DOM to scroll into place
|
||||||
|
}catch(e){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}).done(function(){ // Once the DOM has registered the items
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
while(i < numberOfRows){ // press down arrow
|
||||||
|
keyEvent(inner$, 33, false, false); // doesn't work
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does scrolling back up the pad with the up arrow show the correct contents?
|
||||||
|
helper.waitFor(function(){ // Wait for the new position to be in place
|
||||||
|
try{
|
||||||
|
return isScrolledIntoView(inner$("div:nth-child(0)"), inner$); // Wait for the DOM to scroll into place
|
||||||
|
}catch(e){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}).done(function(){ // Once the DOM has registered the items
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
while(i < numberOfRows){ // press down arrow
|
||||||
|
keyEvent(inner$, 33, false, false); // doesn't work
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Does scrolling back up the pad with the up arrow show the correct contents?
|
||||||
|
helper.waitFor(function(){ // Wait for the new position to be in place
|
||||||
|
return isScrolledIntoView(inner$("div:nth-child(1)"), inner$); // Wait for the DOM to scroll into place
|
||||||
|
}).done(function(){ // Once the DOM has registered the items
|
||||||
|
expect(true).to.be(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function prepareDocument(n, target){ // generates a random document with random content on n lines
|
||||||
|
var i = 0;
|
||||||
|
while(i < n){ // for each line
|
||||||
|
target.sendkeys(makeStr()); // generate a random string and send that to the editor
|
||||||
|
target.sendkeys('{enter}'); // generator an enter keypress
|
||||||
|
i++; // rinse n times
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyEvent(target, charCode, ctrl, shift){ // sends a charCode to the window
|
||||||
|
if(target.browser.mozilla){ // if it's a mozilla browser
|
||||||
|
var evtType = "keypress";
|
||||||
|
}else{
|
||||||
|
var evtType = "keydown";
|
||||||
|
}
|
||||||
|
var e = target.Event(evtType);
|
||||||
|
console.log(e);
|
||||||
|
if(ctrl){
|
||||||
|
e.ctrlKey = true; // Control key
|
||||||
|
}
|
||||||
|
if(shift){
|
||||||
|
e.shiftKey = true; // Shift Key
|
||||||
|
}
|
||||||
|
e.which = charCode;
|
||||||
|
e.keyCode = charCode;
|
||||||
|
target("#innerdocbody").trigger(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeStr(){ // from http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript
|
||||||
|
var text = "";
|
||||||
|
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
||||||
|
for( var i=0; i < 5; i++ )
|
||||||
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isScrolledIntoView(elem, $){ // from http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
|
||||||
|
var docViewTop = $(window).scrollTop();
|
||||||
|
var docViewBottom = docViewTop + $(window).height();
|
||||||
|
var elemTop = $(elem).offset().top; // how far the element is from the top of it's container
|
||||||
|
var elemBottom = elemTop + $(elem).height(); // how far plus the height of the elem.. IE is it all in?
|
||||||
|
elemBottom = elemBottom - 16; // don't ask, sorry but this is needed..
|
||||||
|
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
|
||||||
|
}
|
||||||
|
|
||||||
|
function caretPosition($){
|
||||||
|
var doc = $.window.document;
|
||||||
|
var pos = doc.getSelection();
|
||||||
|
pos.y = pos.anchorNode.parentElement.offsetTop;
|
||||||
|
pos.x = pos.anchorNode.parentElement.offsetLeft;
|
||||||
|
console.log(pos);
|
||||||
|
return pos;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue