Compare commits

..

29 Commits

Author SHA1 Message Date
7d9d2fdf3d nodejs: conversion to md 2026-02-19 09:44:30 +03:00
3a0a713c5a Merge pull request 'update documentserver version to 9.3 in compose files' from 9.3.0-update-compose into release/v9.3.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/93
2026-02-18 06:08:08 +00:00
496092c09f update documentserver version to 9.3 in compose files 2026-02-17 15:48:09 +07:00
c0a870458b Merge remote-tracking branch 'remotes/origin/feature/aiautofiller' into release/v9.3.0 2026-02-16 09:46:28 +03:00
35da4e1de1 update autofill plugin 2026-02-16 09:46:03 +03:00
11974256a9 Merge remote-tracking branch 'remotes/origin/feature/aiautofiller' into release/v9.3.0 2026-02-11 13:21:25 +03:00
f69fabb44a nodejs: autofill auto started on Fill mode only 2026-02-11 13:21:05 +03:00
976d7072a9 Merge remote-tracking branch 'remotes/origin/feature/aiautofiller' into release/v9.3.0 2026-02-04 13:33:42 +03:00
8272c83660 update autofill plugin 2026-02-04 13:33:12 +03:00
c73aae1c4b Merge pull request 'fix: disable autofill plugin for 'comment' mode' from feature/aiautofiller into release/v9.3.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/87
2026-01-30 08:39:00 +00:00
4340c34c23 nodejs: fix lint 2026-01-30 11:38:01 +03:00
3eff9b469b fix: disable autofill plugin for 'comment' mode 2026-01-30 11:37:20 +03:00
eabda30bf7 Merge branch 'feature/aiautofiller' into release/v9.3.0
# Conflicts:
#	.gitmodules
2026-01-21 17:18:43 +03:00
548f24aaff nodejs: update autofill plugin 2026-01-21 17:16:24 +03:00
c1ec722b9f nodejs: anonymous without ai autofill 2026-01-21 17:16:24 +03:00
92a1aff932 nodejs: plugin data update 2026-01-21 17:16:23 +03:00
4fe6e961d3 nodejs: plugin for pdf only 2026-01-21 17:16:23 +03:00
e612717b0b fix: fallback to default plugins 2026-01-21 17:16:23 +03:00
e0e0bc96bf fix(plugins): merge configs with in-line plugin config 2026-01-21 17:16:23 +03:00
c3739fb08a fix: use plugin path without build 2026-01-21 17:16:23 +03:00
c22dbea9bf chore: added additional data 2026-01-21 17:16:23 +03:00
606a14ce8f deps: bumped autofill plugin 2026-01-21 17:16:22 +03:00
4cb50c752b chore: update plugin submodule 2026-01-21 17:16:22 +03:00
c304b5f526 chore: new sample data 2026-01-21 17:16:22 +03:00
f02726d138 refactor: move data to json, build path to the plugin from config 2026-01-21 17:16:22 +03:00
85b0fdc33f chore: strict check 2026-01-21 17:16:22 +03:00
0e8c99aaab fix: do not autostart non edit mode 2026-01-21 17:16:21 +03:00
5a4b47c4bd feat: initial aiautofiller example 2026-01-21 17:16:21 +03:00
9775c8e175 nodejs: support tsv 2026-01-21 17:02:57 +03:00
253 changed files with 4165 additions and 5916 deletions

5
.gitmodules vendored
View File

@ -5,6 +5,11 @@
[submodule "web/documentserver-example/nodejs/public/assets/document-formats"]
path = web/documentserver-example/nodejs/public/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
branch = release/v9.3.0
[submodule "web/documentserver-example/nodejs/public/assets/plugin-aiautofill"]
path = web/documentserver-example/nodejs/public/assets/plugin-aiautofill
url = https://github.com/ONLYOFFICE/plugin-aiautofill.git
branch = develop
[submodule "web/documentserver-example/csharp-mvc/assets/document-templates"]
path = web/documentserver-example/csharp-mvc/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates

View File

@ -1,20 +1,6 @@
# Change Log
- nodejs: wopi CopyPasteRestrictions for anonymous
- update insertImage formats
- new mobile index page view
- update action icons
- php-laravel: 5 editor icons on index page
- java-spring: 5 editor icons on index page
- ruby: display mode buttons by actions
- python: display mode buttons by actions
- php: display mode buttons by actions
- java: display mode buttons by actions
- go: display mode buttons by actions
- csharp-mvc: display mode buttons by actions
- csharp: display mode buttons by actions
- nodejs: display mode buttons by actions
- nodejs: wopi UserCanOnlyComment
- nodejs: support tsv
## 1.15.0
- php-laravel: fix custom jwt header

View File

@ -21,6 +21,56 @@ You should change `http://documentserver` to your server address in these files:
More information on how to use these examples can be found here: [https://api.onlyoffice.com/docs/docs-api/samples/language-specific-examples/](https://api.onlyoffice.com/docs/docs-api/samples/language-specific-examples/)
## API methods for test examples
The methods described below are available for all of the test examples.
### POST `/upload`
| | |
| ---------------------- | ------------------------------------------------------------ |
| **Summary** | Upload file to test example via request |
| **URL** | /upload |
| **Method** | POST |
| **Request<br>Headers** | `Content-Type: multipart/form-data` |
| **Request<br>Body** | `uploadedFile=@<filepath>`<br> `filepath` - file for uploading<br />Multipart body with the file binary contents |
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `{ "filename": <filename>}`<br />**Content on error:**<br /> `{ "error": "Uploaded file not found" }` <br /> Or <br /> `{ "error": "File size is incorrect" }` |
| **Sample** | `curl -X POST -F uploadedFile=@filename.docx http://localhost/upload` |
### DELETE `/file`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Delete one file or all files |
| **URL** | /file |
| **Method** | DELETE |
| ****URL Params**** | **Optional:**<br /> `filename=[string]` - file for deleting. <br /> *WARNING! Without this parameter, all files will be deleted* |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `{ "success": true }` |
| **Sample** | **Delete one file:**<br />`curl -X DELETE http://localhost/file?filename=filename.docx`<br />**Delete all files:**<br />`curl -X DELETE http://localhost/file`<br /> |
### GET `/files`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Get information about all files |
| **URL** | /files |
| **Method** | GET |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}, ..., {...}]` |
| **Sample** | `curl -X GET http://localhost/files/` |
### GET `/files/file/{fileId}`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Get information about a file by file id |
| **URL** | /files/file/{fileId} |
| **Method** | GET |
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}]`<br />**Content on error:**<br /> `"File not found"` |
| **Sample** | `curl -X GET http://localhost/files/{fileId}` |
## Important security info
Please keep in mind the following security aspects when you are using test examples:

View File

@ -51,8 +51,8 @@
.tableHeader td:last-child, .tableRow td:last-child {
width: 10%;
text-align: right;
display: revert;
text-align: center;
padding: 0 !important;
}
.tableHeader {
@ -81,11 +81,6 @@ menu.links {
.scroll-table-body {
overflow-y: auto;
width: 100%;
}
.scroll-table-body td {
padding: 0 !important;
}
.stored-list {

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 6H5L5 15H19V6ZM5 4C3.89543 4 3 4.89543 3 6V15C3 16.1046 3.89543 17 5 17H10V18H6V20H18V18H14V17H19C20.1046 17 21 16.1046 21 15V6C21 4.89543 20.1046 4 19 4H5Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 331 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="4" y="6" width="16" height="13" rx="1" stroke="#444444" stroke-width="2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.148 8.69651C13.8858 8.43384 13.4601 8.43384 13.1979 8.69651V8.69651C12.9362 8.95858 12.9362 9.38302 13.1979 9.64509L15.3401 11.7908C15.7296 12.1809 15.7299 12.8126 15.3409 13.2031L13.1967 15.3554C12.9357 15.6173 12.9357 16.041 13.1967 16.3029V16.3029C13.4591 16.5663 13.8855 16.5663 14.1478 16.3029L17.3302 13.1086V13.1086C17.668 12.7702 17.668 12.2222 17.3302 11.8838L14.148 8.69651Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.85199 16.3035C10.1142 16.5662 10.5399 16.5662 10.8021 16.3035V16.3035C11.0638 16.0414 11.0638 15.617 10.8021 15.3549L8.65987 13.2092C8.2704 12.8191 8.27006 12.1874 8.65911 11.7969L10.8033 9.64461C11.0643 9.38266 11.0643 8.959 10.8033 8.69706V8.69706C10.5409 8.43371 10.1145 8.43371 9.85218 8.69706L6.66983 11.8914V11.8914C6.33201 12.2298 6.33201 12.7778 6.66983 13.1162L9.85199 16.3035Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 379 B

View File

@ -1,3 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 5C17.6569 5 19 6.34315 19 8V16C19 17.6569 17.6569 19 16 19H8C6.34315 19 5 17.6569 5 16V8C5 6.34315 6.34315 5 8 5H16ZM11 7V17H16L16.1025 16.9951C16.573 16.9472 16.9472 16.573 16.9951 16.1025L17 16V8C17 7.48232 16.6067 7.05621 16.1025 7.00488L16 7H11Z" fill="#EFEFEF"/>
</svg>
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="2" rx="1" fill="white"/>
<rect y="6" width="20" height="2" rx="1" fill="white"/>
<rect y="12" width="20" height="2" rx="1" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 278 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C6.89543 3 6 3.89543 6 5V19C6 20.1046 6.89543 21 8 21H16C17.1046 21 18 20.1046 18 19V5C18 3.89543 17.1046 3 16 3H8ZM16.8462 6H7.15385V18H16.8462V6ZM10.3846 4H13.6154V5H10.3846V4ZM12 20C12.2974 20 12.5385 19.7761 12.5385 19.5C12.5385 19.2239 12.2974 19 12 19C11.7026 19 11.4615 19.2239 11.4615 19.5C11.4615 19.7761 11.7026 20 12 20Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 506 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.33331 10C4.22665 10 3.33331 10.8933 3.33331 12C3.33331 13.1067 4.22665 14 5.33331 14C6.43998 14 7.33331 13.1067 7.33331 12C7.33331 10.8933 6.43998 10 5.33331 10ZM18.6666 10C17.56 10 16.6666 10.8933 16.6666 12C16.6666 13.1067 17.56 14 18.6666 14C19.7733 14 20.6666 13.1067 20.6666 12C20.6666 10.8933 19.7733 10 18.6666 10ZM12 10C10.8933 10 9.99998 10.8933 9.99998 12C9.99998 13.1067 10.8933 14 12 14C13.1066 14 14 13.1067 14 12C14 10.8933 13.1066 10 12 10Z" fill="#808080"/>
</svg>

Before

Width:  |  Height:  |  Size: 588 B

View File

@ -34,15 +34,15 @@
}
.tableHeaderCellFileName {
width: 29%;
width: 25%;
}
.tableHeaderCellEditors {
width: 12%;
width: 13%;
}
.tableHeaderCellViewers {
width: 15%;
width: 18%;
text-align: right;
}
@ -84,7 +84,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 90%;
}
@ -143,7 +142,6 @@
.scroll-table-body {
top: 31px;
height: calc(100% - 34px);
}
footer {
@ -184,14 +182,9 @@
@media (max-width: 715px) {
.tableRow,
.storedHeader,
menu.links {
width: 45%;
}
.storedHeaderClearAll {
padding-right: 24px;
}
}
@media (max-width: 670px) and (min-width: 620px){
.main-panel{
@ -227,15 +220,15 @@
.tableRow td:first-child {
flex-grow: 0;
width: 26%;
}
.tableHeaderCellFileName {
width: 15%;
}
.tableHeaderCellFileName {
width: 9%;
}
.tableHeaderCellEditors {
width: 3%;
width: 13%;
}
.tableHeaderCellViewers {
@ -260,12 +253,12 @@
}
.tableHeaderCellEditors {
width: 13%;
width: 15%;
text-align: left;
}
.tableHeaderCellFileName {
width: 29%;
width: 28%;
}
.tableHeaderCellViewers {
@ -288,7 +281,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 75%;
}
@ -310,10 +302,6 @@
.firstContentCellViewers {
margin-left: 0;
}
.storedHeaderClearAll {
padding-right: 39px;
}
}
@media (max-width: 890px) and (min-width: 769px ) {
@ -329,7 +317,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 95%;
}
@ -350,7 +337,7 @@
}
.tableHeaderCellFileName {
width: 22%;
width: 20%;
}
.tableHeaderCellEditors {
@ -359,22 +346,18 @@
}
.tableHeaderCellViewers {
width: 15%;
width: 19%;
}
.tableHeaderCellAction {
width: 19%;
padding-right: 45px;
}
.storedHeaderClearAll {
padding-right: 30px;
}
}
@media (max-width: 890px) {
.tableRow td:first-child {
max-width: 22%;
max-width: 17%;
}
#portal-info {
max-width: 60vw;
@ -453,6 +436,61 @@
padding: 16px 0 6px;
}
.tableRow,
menu.links {
width: 40%;
}
.tableRow td {
border: none;
}
.firstContentCellShift {
border: none;
flex-basis: 10%;
flex-grow: 1;
}
.downloadContentCellShift {
max-width: 7%;
margin-right: 24px;
margin-left: 0;
}
.contentCells-icon {
width: 13%;
}
.tableRow td:last-child {
width: 7%;
padding-right: 0px;
border: none;
}
.contentCells-shift {
padding-right: 0px;
}
.downloadContentCellShift:after {
width: 85%;
}
.firstContentCellViewers {
margin-left: 0;
border-bottom: 1px solid #e5e5e5 !important;
}
.firstContentCellViewers ~ td {
border-bottom: 1px solid #e5e5e5;
}
.tableRow td:first-child{
border: none;
width: 85%;
}
.contentCellsEmpty{
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
@ -527,7 +565,104 @@
}
}
@media (max-width: 560px) and (min-width: 510px) {
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
padding-right: 16px;
max-width: 4%;
}
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow,
menu.links {
width: 35%;
}
.tableRow td:first-child{
width: 83%;
}
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
max-width: 6%;
padding-right: 6px;
}
.firstContentCellShift {
flex-basis: 9%;
}
.tableRow td:last-child {
padding-right: 28px;
}
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow,
menu.links {
width: 30%;
}
.tableRow td:first-child{
width: 85%;
}
.contentCells-icon {
width: 11%;
}
.downloadContentCellShift {
max-width: 3%;
padding-right: 0px;
padding-left: 0;
}
.firstContentCellShift {
margin-left: 2px;
flex-basis: 14%;
}
.tableRow td:last-child {
width: 5%;
padding-right: 63px;
}
.firstContentCellViewers{
padding-right: 2px;
width: 12%;
}
.contentCellsEmpty{
display: none;
}
}
@media (max-width: 420px) {
.tableRow,
menu.links {
width: 25%;
}
.tableRow td:last-child {
width: 6%;
padding-right: 16px;
}
.downloadContentCellShift {
max-width: 4%;
margin-right: 18px;
margin-left: -1px;
}
.firstContentCellShift {
flex-basis: 2%;
}
.contentCells-icon{
width: 12%;
}
footer table td {
margin: 0;
padding-right: 5px;
@ -538,6 +673,10 @@
padding-right: 5px;
margin: 0;
}
.firstContentCellViewers{
padding-right: 2px;
width: 11%;
}
}
@media (max-width: 1160px) {
@ -546,15 +685,20 @@
}
}
@media (min-width: 593px) {
.contentCellsEmpty {
display: none;
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow,
.storedHeader,
menu.links {
width: 50%;
}
.storedHeaderClearAll {
padding-right: 26px;
}
@media (max-width: 510px) {
.tableRow td:first-child{
flex-grow: 0;
}
}
@media (max-width: 1100px) and (min-width: 890px){
@ -638,8 +782,8 @@
margin: 0;
position: fixed;
left: 0;
height: calc(100% - 44px);
z-index: 101;
height: calc(100% - 124px);
z-index:99;
}
.left-panel.active {
@ -749,7 +893,6 @@
.scroll-table-body {
top: 36px;
height: calc(100% - 34px);
}
.scroll-table-body tr:first-child {
@ -758,37 +901,16 @@
.tableRow {
border-bottom: 1px solid #e5e5e5;
padding: 12px 0;
padding: 16px 0;
width: 100%;
flex-wrap: nowrap;
}
.tableRow td:first-child {
width: 100%;
}
.tableRow td:last-child {
display: block;
width: 24px;
}
.contentCells {
padding: 0;
font-size: 13px;
}
.contentCells-icon {
width: auto;
display: none;
}
.stored-edit {
height: 12px;
padding: 6px 0 6px 34px;
}
.stored-edit span {
font-size: 13px;
font-size: 14px;
}
.header-list {
@ -796,7 +918,7 @@
}
.firstContentCellViewers {
margin: 0;
border-bottom: none !important;
}
.firstContentCellViewers ~ td {
@ -831,19 +953,4 @@
.user-block-table {
height: auto;
}
.upload-panel {
padding: 12px 0;
}
.user-block-table td select {
height: 48px;
padding-left: 12px;
border-radius: 6px;
border-color: #aaaaaa;
}
.user-block-table tr:last-child {
display: none;
}
}

View File

@ -752,6 +752,7 @@ footer table tr td:first-child {
.contentCells {
display: block;
border-bottom: 1px solid #EFEFEF;
font-family: 'Open Sans', sans-serif;
font-size: 16px;
padding: 4px;
@ -844,7 +845,6 @@ footer table tr td:first-child {
position: absolute;
right: 0;
top: 71px;
height: calc(100% - 130px);
scrollbar-color: #D0D5DA transparent;
scrollbar-width: thin;
}
@ -915,18 +915,18 @@ html {
position: relative;
}
.tableRow td:first-child {
display: flex;
flex-grow: 1;
max-width: 29%;
}
.tableRow td:first-child {
display: flex;
flex-grow: 1;
max-width: 25%;
}
.tableHeaderCellFileName {
width: 24%;
width: 20%;
}
.tableHeaderCellEditors {
width: 24%;
width: 20%;
}
.tableHeaderCellViewers {
@ -984,103 +984,3 @@ html {
top: 50%;
transform: translate(-50%, -50%);
}
.tableRow td:last-child {
display: none;
}
#mobileContextMenu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(51, 51, 51, 0.3);
display: flex;
justify-content: center;
align-items: flex-end;
z-index: 100;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0s linear 0.4s;
}
#mobileContextMenu.active {
visibility: visible;
opacity: 1;
transition: opacity 0.3s ease;
}
#mobileContextMenu .context-body {
width: 100%;
max-height: 100%;
transform: translateY(100%);
transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
}
#mobileContextMenu.active .context-body {
transform: translateY(0);
}
#mobileContextMenu table {
background-color: white;
width: 100%;
margin-top: 150px;
padding-bottom: 96px;
}
#mobileContextMenu thead {
padding: 12px 16px 0;
height: 48px;
position: sticky;
top: -1px;
display: flex;
align-items: center;
background-color: white;
}
#mobileContextMenu thead:not(.is-pinned)::after {
content: '';
position: absolute;
left: 16px;
right: 16px;
bottom: 0px;
height: 1px;
background: #e2e2e2;
}
#mobileContextMenu thead.is-pinned {
box-shadow: 0px 4px 6px 0px #CCCCCC4D;
transition: all 0.4s ease-out;
}
#mobileContextMenu tbody {
padding: 0 16px;
display: block
}
#mobileContextMenu tr {
display: block;
padding: 12px;
}
.context-section {
padding: 24px 0 6px !important;
font-size: 13px;
font-weight: 600;
color: #808080;
}
#mobileContextMenu a:not(.stored-edit) {
display: flex;
flex-direction: row;
align-items: center;
text-decoration: none;
}
#mobileContextMenu img {
margin-right: 8px;
}

View File

@ -327,18 +327,13 @@ namespace OnlineEditorsExampleMVC.Models
logoConfig.Add("directUrl", directMailMergeUrl.ToString());
}
var result = new Dictionary<string, object>
{
{ "images", new List<Dictionary<string, object>>{logoConfig} }
};
if (JwtManager.Enabled) // if the secret key to generate token exists
{
var token = JwtManager.Encode(result); // encode logoConfig into the token
result.Add("token", token); // and add it to the logo config
var token = JwtManager.Encode(logoConfig); // encode logoConfig into the token
logoConfig.Add("token", token); // and add it to the logo config
}
logoUrl = jss.Serialize(result).Replace("{", "").Replace("}", "");
logoUrl = jss.Serialize(logoConfig).Replace("{", "").Replace("}", "");
}
// get a mail merge config

View File

@ -239,13 +239,6 @@ namespace OnlineEditorsExampleMVC.Models
return cachedFormats;
}
public static List<string> GetFormatActions(string extension)
{
return All()
.Find(format => format.Extension() == extension)
.Actions;
}
private static string GetPath()
{
string path = Path.Combine(GetDirectory(), "onlyoffice-docs-formats.json");

View File

@ -98,18 +98,18 @@
<Content Include="Content\images\close.svg" />
<Content Include="Content\images\comment.svg" />
<Content Include="Content\images\delete.svg" />
<Content Include="Content\images\desktop.svg" />
<Content Include="Content\images\done.svg" />
<Content Include="Content\images\download.svg" />
<Content Include="Content\images\edit.svg" />
<Content Include="Content\images\embedview.svg" />
<Content Include="Content\images\embeded.svg" />
<Content Include="Content\images\error.svg" />
<Content Include="Content\images\file_docx.svg" />
<Content Include="Content\images\file_docxf.svg" />
<Content Include="Content\images\file_pptx.svg" />
<Content Include="Content\images\file_upload.svg" />
<Content Include="Content\images\file_xlsx.svg" />
<Content Include="Content\images\fill-forms.svg" />
<Content Include="Content\images\filter.svg" />
<Content Include="Content\images\formsubmit.svg" />
<Content Include="Content\images\home.svg" />
<Content Include="Content\images\icon_docx.svg" />
<Content Include="Content\images\icon_pptx.svg" />
@ -118,14 +118,12 @@
<Content Include="Content\images\loader16.gif" />
<Content Include="Content\images\logo.svg" />
<Content Include="Content\images\mobile-fill-forms.svg" />
<Content Include="Content\images\mobileEdit.svg" />
<Content Include="Content\images\mobileView.svg" />
<Content Include="Content\images\mobile.svg" />
<Content Include="Content\images\notdone.svg" />
<Content Include="Content\images\review.svg" />
<Content Include="Content\images\slide.ico" />
<Content Include="Content\images\uid-1.png" />
<Content Include="Content\images\uid-2.png" />
<Content Include="Content\images\view.svg" />
<Content Include="Content\images\word.ico" />
<Content Include="Content\jquery-ui.css" />
<Content Include="Content\media.css" />

View File

@ -79,45 +79,6 @@ In case the example and Document Server are installed on different computers, ma
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## File API methods used in this example
The methods described below are available for .Net (C# MVC) test example.
### POST `/webeditor.ashx?type=upload`
| | |
| ---------------------- | ------------------------------------------------------------ |
| **Summary** | Upload file to test example via request |
| **URL** | /webeditor.ashx?type=upload |
| **Method** | POST |
| **Request<br>Headers** | `Content-Type: multipart/form-data` |
| **Request<br>Body** | `uploadedFile=@<filepath>`<br> `filepath` - file for uploading<br />Multipart body with the file binary contents |
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `{ "filename": <filename>}`<br />**Content on error:**<br /> `{ "error": "File type is not supported" }` <br /> Or <br /> `{ "error": "File size is incorrect" }` |
| **Sample** | `curl -X POST -F uploadedFile=@filename.docx http://localhost/webeditor.ashx?type=upload` |
### GET `/webeditor.ashx?type=remove`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Delete one file or all files |
| **URL** | /webeditor.ashx?type=remove |
| **Method** | GET |
| ****URL Params**** | **Optional:**<br /> `filename=[string]` - file for deleting. <br /> *WARNING! Without this parameter, all files will be deleted* |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `{ "success": true }` |
| **Sample** | **Delete one file:**<br />`curl -X GET http://localhost/webeditor.ashx?type=remove&filename=filename.docx`<br />**Delete all files:**<br />`curl -X GET http://localhost/webeditor.ashx?type=remove`<br /> |
### GET `/webeditor.ashx?type=files`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Get information about all files |
| **URL** | /webeditor.ashx?type=files |
| **Method** | GET |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}, ..., {...}]` |
| **Sample** | `curl -X GET http://localhost/webeditor.ashx?type=files` |
## Important security info
Please keep in mind the following security aspects when you are using test examples:

View File

@ -562,75 +562,3 @@ function toggleUserDescr(event) {
else list.classList.add("active");
}
}
function toggleContextMenu(event) {
let contextMenu = document.querySelector("#mobileContextMenu");
let target = event.currentTarget.parentNode.parentNode.cloneNode(true);
const closeContextMenu = () => {
contextMenu.classList.remove("active");
}
if (contextMenu.classList.contains("active") || !target.classList.contains("tableRow")) {
if (event.target.id == "mobileContextMenuBody") closeContextMenu();
return;
}
let contextBody = document.querySelector("#mobileContextMenuBody");
contextBody.innerHTML = "";
let startY = 0;
let startScroll = 0;
contextBody.addEventListener('touchstart', (e) => {
startY = e.touches[0].clientY;
startScroll = contextBody.scrollTop;
});
contextBody.addEventListener('touchmove', (e) => {
const currentY = e.touches[0].clientY;
const diff = currentY - startY;
if (diff > 10 && (contextBody.scrollTop === 0 || contextBody.scrollTop === startScroll)) {
closeContextMenu();
}
});
let thead = document.createElement("thead");
thead.appendChild(target.children[0]);
const observer = new IntersectionObserver(
([e]) => e.target.classList.toggle("is-pinned", e.intersectionRatio < 1),
{ threshold: [1] }
);
observer.observe(thead);
let tbody = document.createElement("tbody");
for (let td of Array.from(target.children).slice(0, -1)){
if (td.getAttribute("data-section")){
let section = document.createElement("tr");
section.innerText = td.getAttribute("data-section");
section.classList.add("context-section");
tbody.appendChild(section);
}
if (td.children.length == 0) continue;
let action = document.createElement("div");
action.innerText = td.children[0].children[0].getAttribute("title");
td.children[0].appendChild(action);
td.children[0].onclick = () => {
setTimeout(() => window.location.reload(), 0);
}
td.style.display = "block";
td.classList.remove("downloadContentCellShift");
td.classList.remove("firstContentCellViewers");
let tr = document.createElement("tr");
tr.appendChild(td);
tbody.appendChild(tr);
}
let table = document.createElement("table");
table.appendChild(thead);
table.appendChild(tbody);
contextBody.appendChild(table);
contextMenu.classList.add("active");
}

View File

@ -48,13 +48,13 @@
</div>
<menu class="responsive-nav">
<li>
<a href="./">
<img src ="content/images/mobile-logo.svg" alt="ONLYOFFICE" />
<a href="#" onclick="toggleSidePanel(event)">
<img src="content/images/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="#" onclick="toggleSidePanel(event)">
<img src="content/images/mobile-menu.svg" alt="ONLYOFFICE" />
<a href="./">
<img src ="content/images/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
@ -127,7 +127,7 @@
<td valign="middle">
<label class="side-option">
<input id="directUrl" type="checkbox" class="checkbox" />Try opening on client
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server. Open each file in only one way." src="content/images/info.svg" />
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server." src="content/images/info.svg" />
</label>
</td>
</tr>
@ -204,136 +204,131 @@
<div class="scroll-table-body">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<% foreach (var storedFile in storedFiles) {
var isEnabledDirectUrl = DocManagerHelper.GetDirectUrl();
var editUrl = "doceditor.aspx?fileID=" + HttpUtility.UrlEncode(storedFile.Name);
var docType = FileUtility.GetFileType(storedFile.Name).ToString().ToLower();
var ext = Path.GetExtension(storedFile.Name).ToLower();
var actions = FormatManager.GetFormatActions(ext);
%>
<tr class="tableRow" title="<%= storedFile.Name %> [<%= DocManagerHelper.GetFileVersion(storedFile.Name, HttpContext.Current.Request.UserHostAddress.Replace(':', '_')) %>]">
<td class="contentCells">
<a class="stored-edit <%= docType %>" href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, directUrl = isEnabledDirectUrl }) %>" target="_blank">
<span><%= storedFile.Name %></span>
</a>
</td>
<% foreach (var storedFile in storedFiles)
{
var isEnabledDirectUrl = DocManagerHelper.GetDirectUrl();
var editUrl = "doceditor.aspx?fileID=" + HttpUtility.UrlEncode(storedFile.Name);
var docType = FileUtility.GetFileType(storedFile.Name).ToString().ToLower();
var ext = Path.GetExtension(storedFile.Name).ToLower();
var canEdit = DocManagerHelper.EditedExts.Contains(ext);
var isFillFormDoc = DocManagerHelper.FillFormExts.Contains(ext);
%>
<!-- 1-2 -->
<% if (actions.Contains("edit") || actions.Contains("lossy-edit")) { %>
<td class="contentCells contentCells-icon" data-section="EDITOR">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "edit", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/edit.svg" alt="Open for full size screens" title="Open for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "mobile", editorsMode = "edit", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/mobileEdit.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon" data-section="EDITOR"></td>
<td class="contentCells contentCells-icon"></td>
<% } %>
<!-- 3 -->
<% if (actions.Contains("comment")) { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "comment", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/comment.svg" alt="Open for comment" title="Open for comment"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon"></td>
<% } %>
<!-- 4-5 -->
<% if (actions.Contains("fill")) { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "fillForms", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/formsubmit.svg" alt="Open for filling in forms" title="Open for filling in forms"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift firstContentCellShift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "mobile", editorsMode = "fillForms", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/mobile-fill-forms.svg" alt="Open for filling in forms for mobile devices" title="Open for filling in forms for mobile devices"/>
</a>
</td>
<% } else { %>
<!-- 4 -->
<% if (actions.Contains("review")) { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "review", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/review.svg" alt="Open for review" title="Open for review"/>
</a>
</td>
<% } else if (actions.Contains("customfilter")) { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "filter", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/filter.svg" alt="Open without access to change the filter" title="Open without access to change the filter" />
</a>
<tr class="tableRow" title="<%= storedFile.Name %> [<%= DocManagerHelper.GetFileVersion(storedFile.Name, HttpContext.Current.Request.UserHostAddress.Replace(':', '_')) %>]">
<td class="contentCells">
<a class="stored-edit <%= docType %>" href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, directUrl = isEnabledDirectUrl }) %>" target="_blank">
<span><%= storedFile.Name %></span>
</a>
</td>
<% } else {%>
<td class="contentCells contentCells-icon"></td>
<% } %>
<!-- 5 -->
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon contentCells-shift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "blockcontent", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/block-content.svg" alt="Open without content control modification" title="Open without content control modification"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon contentCells-shift"></td>
<% } %>
<% } %>
<td class="contentCells contentCells-icon firstContentCellViewers" data-section="VIEWERS">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "view", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/view.svg" alt="Open for full size screens" title="Open for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "mobile", editorsMode = "view", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/mobileView.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "embedded", editorsMode = "embedded", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/embedview.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
</a>
</td>
<% if (docType != null ) { %>
<td class="contentCells contentCells-icon" data-section="ACTIONS">
<a class="convert-file" data="<%= storedFile.Name %>" data-type="<%= docType %>">
<img class="icon-action" src="content/images/convert.svg" alt="Convert" title="Convert" /></a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon downloadContentCellShift" data-section="ACTIONS"></td>
<% } %>
<td class="contentCells contentCells-icon downloadContentCellShift">
<a href="webeditor.ashx?type=download&fileName=<%= HttpUtility.UrlEncode(storedFile.Name) %>">
<img class="icon-download" src="content/images/download.svg" alt="Download" title="Download" />
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a class="delete-file" data-filename="<%= storedFile.Name %>">
<img class="icon-action" src="content/images/delete.svg" alt="Delete" title="Delete" />
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="#" onclick="toggleContextMenu(event)">
<img src="content/images/open-context.svg" alt="Open context menu" title="Open context menu" />
</a>
</td>
</tr>
<% } %>
</tbody>
</table>
<% if (canEdit) { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "edit", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/desktop.svg" alt="Open in editor for full size screens" title="Open in editor for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "mobile", editorsMode = "edit", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
</a>
</td>
<% if (docType != "pdf") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "comment", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "review", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/review.svg" alt="Open in editor for review" title="Open in editor for review"/>
</a>
</td>
<% } else if (docType == "cell") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "filter", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/filter.svg" alt="Open in editor without access to change the filter" title="Open in editor without access to change the filter" />
</a>
</td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "blockcontent", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/block-content.svg" alt="Open in editor without content control modification" title="Open in editor without content control modification"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon"></td>
<% } %>
<% if (docType != "word" && docType != "cell") { %>
<td class="contentCells contentCells-icon "></td>
<% } %>
<% if (isFillFormDoc) { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "fillForms", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
<% } %>
<% } else if (isFillFormDoc) { %>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "mobile", editorsMode = "fillForms", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/mobile-fill-forms.svg" alt="Open in editor for filling in forms for mobile devices" title="Open in editor for filling in forms for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "fillForms", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon contentCellsEmpty" colspan="6"></td>
<% } %>
<td class="contentCells contentCells-icon firstContentCellViewers">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "view", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/desktop.svg" alt="Open in viewer for full size screens" title="Open in viewer for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "mobile", editorsMode = "view", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/mobile.svg" alt="Open in viewer for mobile devices" title="Open in viewer for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "embedded", editorsMode = "embedded", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/embeded.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
</a>
</td>
<% if (docType != null ) { %>
<td class="contentCells contentCells-icon">
<a class="convert-file" data="<%= storedFile.Name %>" data-type="<%= docType %>">
<img class="icon-action" src="content/images/convert.svg" alt="Convert" title="Convert" /></a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon downloadContentCellShift"></td>
<% } %>
<td class="contentCells contentCells-icon downloadContentCellShift">
<a href="webeditor.ashx?type=download&fileName=<%= HttpUtility.UrlEncode(storedFile.Name) %>">
<img class="icon-download" src="content/images/download.svg" alt="Download" title="Download" />
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a class="delete-file" data-filename="<%= storedFile.Name %>">
<img class="icon-action" src="content/images/delete.svg" alt="Delete" title="Delete" />
</a>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
</div>
<% } %>
</div>
</td>
@ -439,11 +434,6 @@
</div>
</footer>
<div id="mobileContextMenu" onclick="toggleContextMenu(event)">
<div class="context-body" id="mobileContextMenuBody">
</div>
</div>
<%: Scripts.Render("~/bundles/jquery", "~/bundles/scripts") %>
<script language="javascript" type="text/javascript">

View File

@ -51,8 +51,8 @@
.tableHeader td:last-child, .tableRow td:last-child {
width: 10%;
text-align: right;
display: revert;
text-align: center;
padding: 0 !important;
}
.tableHeader {
@ -81,11 +81,6 @@ menu.links {
.scroll-table-body {
overflow-y: auto;
width: 100%;
}
.scroll-table-body td {
padding: 0 !important;
}
.stored-list {

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 6H5L5 15H19V6ZM5 4C3.89543 4 3 4.89543 3 6V15C3 16.1046 3.89543 17 5 17H10V18H6V20H18V18H14V17H19C20.1046 17 21 16.1046 21 15V6C21 4.89543 20.1046 4 19 4H5Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 331 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 19H8.11111L8.84845 18.2627L5.73734 15.1516L5 15.8889V19ZM10.2627 16.8484L19 8.11111V6.55556H17.4444V5H15.8889L7.15155 13.7373L10.2627 16.8484Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 316 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="4" y="6" width="16" height="13" rx="1" stroke="#444444" stroke-width="2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.148 8.69651C13.8858 8.43384 13.4601 8.43384 13.1979 8.69651V8.69651C12.9362 8.95858 12.9362 9.38302 13.1979 9.64509L15.3401 11.7908C15.7296 12.1809 15.7299 12.8126 15.3409 13.2031L13.1967 15.3554C12.9357 15.6173 12.9357 16.041 13.1967 16.3029V16.3029C13.4591 16.5663 13.8855 16.5663 14.1478 16.3029L17.3302 13.1086V13.1086C17.668 12.7702 17.668 12.2222 17.3302 11.8838L14.148 8.69651Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.85199 16.3035C10.1142 16.5662 10.5399 16.5662 10.8021 16.3035V16.3035C11.0638 16.0414 11.0638 15.617 10.8021 15.3549L8.65987 13.2092C8.2704 12.8191 8.27006 12.1874 8.65911 11.7969L10.8033 9.64461C11.0643 9.38266 11.0643 8.959 10.8033 8.69706V8.69706C10.5409 8.43371 10.1145 8.43371 9.85218 8.69706L6.66983 11.8914V11.8914C6.33201 12.2298 6.33201 12.7778 6.66983 13.1162L9.85199 16.3035Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.326 18.6739C13.8912 18.2391 13.8912 17.5342 14.326 17.0994L20.0993 11.3261C20.5341 10.8913 21.239 10.8913 21.6738 11.3261C22.1086 11.7609 22.1086 12.4658 21.6738 12.9006L15.9006 18.6739C15.4658 19.1087 14.7608 19.1087 14.326 18.6739Z" fill="#444444"/>
<path d="M14.326 5.3261C14.7608 4.8913 15.4658 4.8913 15.9006 5.3261L21.6738 11.0994C22.1086 11.5342 22.1086 12.2391 21.6738 12.6739C21.239 13.1087 20.5341 13.1087 20.0993 12.6739L14.326 6.90063C13.8912 6.46583 13.8912 5.76089 14.326 5.3261Z" fill="#444444"/>
<path d="M9.67385 5.3261C10.1086 5.76089 10.1086 6.46583 9.67385 6.90063L3.90061 12.6739C3.46582 13.1087 2.76088 13.1087 2.32609 12.6739C1.8913 12.2391 1.8913 11.5342 2.32609 11.0994L8.09933 5.3261C8.53412 4.8913 9.23905 4.8913 9.67385 5.3261Z" fill="#444444"/>
<path d="M9.67385 18.6739C9.23905 19.1087 8.53412 19.1087 8.09933 18.6739L2.32609 12.9006C1.8913 12.4658 1.8913 11.7609 2.32609 11.3261C2.76088 10.8913 3.46582 10.8913 3.90061 11.3261L9.67385 17.0994C10.1086 17.5342 10.1086 18.2391 9.67385 18.6739Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 379 B

View File

@ -1,3 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 5C17.6569 5 19 6.34315 19 8V16C19 17.6569 17.6569 19 16 19H8C6.34315 19 5 17.6569 5 16V8C5 6.34315 6.34315 5 8 5H16ZM11 7V17H16L16.1025 16.9951C16.573 16.9472 16.9472 16.573 16.9951 16.1025L17 16V8C17 7.48232 16.6067 7.05621 16.1025 7.00488L16 7H11Z" fill="#EFEFEF"/>
</svg>
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="2" rx="1" fill="white"/>
<rect y="6" width="20" height="2" rx="1" fill="white"/>
<rect y="12" width="20" height="2" rx="1" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 278 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C6.89543 3 6 3.89543 6 5V19C6 20.1046 6.89543 21 8 21H16C17.1046 21 18 20.1046 18 19V5C18 3.89543 17.1046 3 16 3H8ZM16.8462 6H7.15385V18H16.8462V6ZM10.3846 4H13.6154V5H10.3846V4ZM12 20C12.2974 20 12.5385 19.7761 12.5385 19.5C12.5385 19.2239 12.2974 19 12 19C11.7026 19 11.4615 19.2239 11.4615 19.5C11.4615 19.7761 11.7026 20 12 20Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 506 B

View File

@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 5C4 3.89543 4.89543 3 6 3H15C16.1046 3 17 3.89543 17 5V7H16V6H5V18H16V17H17V19C17 20.1046 16.1046 21 15 21H6C4.89543 21 4 20.1046 4 19V5ZM12 4H9V5H12V4ZM11 19.5C11 19.7761 10.7761 20 10.5 20C10.2239 20 10 19.7761 10 19.5C10 19.2239 10.2239 19 10.5 19C10.7761 19 11 19.2239 11 19.5Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 16H14L14.6464 15.3536L12.6464 13.3536L12 14V16ZM15.3536 14.6464L21 9V8H20V7H19L13.3536 12.6464L15.3536 14.6464Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 638 B

View File

@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 5C4 3.89543 4.89543 3 6 3H15C16.1046 3 17 3.89543 17 5V7H16V6H5V18H16V17H17V19C17 20.1046 16.1046 21 15 21H6C4.89543 21 4 20.1046 4 19V5ZM12 4H9V5H12V4ZM11 19.5C11 19.7761 10.7761 20 10.5 20C10.2239 20 10 19.7761 10 19.5C10 19.2239 10.2239 19 10.5 19C10.7761 19 11 19.2239 11 19.5Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 8C11.3252 8 8.89946 9.40288 7.10954 11.6815C6.96349 11.8682 6.96349 12.129 7.10954 12.3157C8.89946 14.5971 11.3252 16 14 16C16.6748 16 19.1005 14.5971 20.8905 12.3185C21.0365 12.1318 21.0365 11.871 20.8905 11.6843C19.1005 9.40288 16.6748 8 14 8ZM14.1955 14.9939C12.3863 15.1077 10.8923 13.6166 11.0061 11.8045C11.0995 10.3105 12.3105 9.09949 13.8045 9.00611C15.6137 8.89231 17.1077 10.3834 16.9939 12.1955C16.8976 13.6866 15.6866 14.8976 14.1955 14.9939ZM14.0641 12.998C13.4609 13.0359 12.9625 12.5392 13.0022 11.9359C13.0329 11.4373 13.4375 11.0346 13.9359 11.002C14.5391 10.9641 15.0375 11.4608 14.9978 12.0641C14.9653 12.5645 14.5607 12.9673 14.0641 12.998Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.33331 10C4.22665 10 3.33331 10.8933 3.33331 12C3.33331 13.1067 4.22665 14 5.33331 14C6.43998 14 7.33331 13.1067 7.33331 12C7.33331 10.8933 6.43998 10 5.33331 10ZM18.6666 10C17.56 10 16.6666 10.8933 16.6666 12C16.6666 13.1067 17.56 14 18.6666 14C19.7733 14 20.6666 13.1067 20.6666 12C20.6666 10.8933 19.7733 10 18.6666 10ZM12 10C10.8933 10 9.99998 10.8933 9.99998 12C9.99998 13.1067 10.8933 14 12 14C13.1066 14 14 13.1067 14 12C14 10.8933 13.1066 10 12 10Z" fill="#808080"/>
</svg>

Before

Width:  |  Height:  |  Size: 588 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C8.17879 6 4.71351 8.10432 2.15649 11.5223C1.94784 11.8023 1.94784 12.1935 2.15649 12.4736C4.71351 15.8957 8.17879 18 12 18C15.8212 18 19.2865 15.8957 21.8435 12.4777C22.0522 12.1977 22.0522 11.8065 21.8435 11.5264C19.2865 8.10432 15.8212 6 12 6ZM12.2607 15.9919C9.84844 16.1436 7.8564 14.1554 8.00813 11.7393C8.13264 9.74729 9.74728 8.13265 11.7393 8.00815C14.1516 7.85641 16.1436 9.84456 15.9919 12.2607C15.8635 14.2488 14.2488 15.8635 12.2607 15.9919ZM12.1282 13.9959C10.9219 14.0718 9.92498 13.0783 10.0044 11.8718C10.0658 10.8747 10.8749 10.0691 11.8718 10.0041C13.0781 9.92821 14.075 10.9217 13.9956 12.1282C13.9305 13.1289 13.1215 13.9345 12.1282 13.9959Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 838 B

View File

@ -34,15 +34,15 @@
}
.tableHeaderCellFileName {
width: 29%;
width: 25%;
}
.tableHeaderCellEditors {
width: 12%;
width: 13%;
}
.tableHeaderCellViewers {
width: 15%;
width: 18%;
text-align: right;
}
@ -84,7 +84,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 90%;
}
@ -143,7 +142,6 @@
.scroll-table-body {
top: 31px;
height: calc(100% - 34px);
}
footer {
@ -184,14 +182,9 @@
@media (max-width: 715px) {
.tableRow,
.storedHeader,
menu.links {
width: 45%;
}
.storedHeaderClearAll {
padding-right: 24px;
}
}
@media (max-width: 670px) and (min-width: 620px){
.main-panel{
@ -227,15 +220,15 @@
.tableRow td:first-child {
flex-grow: 0;
width: 26%;
}
.tableHeaderCellFileName {
width: 15%;
}
.tableHeaderCellFileName {
width: 9%;
}
.tableHeaderCellEditors {
width: 3%;
width: 13%;
}
.tableHeaderCellViewers {
@ -260,12 +253,12 @@
}
.tableHeaderCellEditors {
width: 13%;
width: 15%;
text-align: left;
}
.tableHeaderCellFileName {
width: 29%;
width: 28%;
}
.tableHeaderCellViewers {
@ -288,7 +281,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 75%;
}
@ -310,10 +302,6 @@
.firstContentCellViewers {
margin-left: 0;
}
.storedHeaderClearAll {
padding-right: 39px;
}
}
@media (max-width: 890px) and (min-width: 769px ) {
@ -329,7 +317,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 95%;
}
@ -350,7 +337,7 @@
}
.tableHeaderCellFileName {
width: 22%;
width: 20%;
}
.tableHeaderCellEditors {
@ -359,22 +346,18 @@
}
.tableHeaderCellViewers {
width: 15%;
width: 19%;
}
.tableHeaderCellAction {
width: 19%;
padding-right: 45px;
}
.storedHeaderClearAll {
padding-right: 30px;
}
}
@media (max-width: 890px) {
.tableRow td:first-child {
max-width: 22%;
max-width: 17%;
}
#portal-info {
max-width: 60vw;
@ -453,6 +436,61 @@
padding: 16px 0 6px;
}
.tableRow,
menu.links {
width: 40%;
}
.tableRow td {
border: none;
}
.firstContentCellShift {
border: none;
flex-basis: 10%;
flex-grow: 1;
}
.downloadContentCellShift {
max-width: 7%;
margin-right: 24px;
margin-left: 0;
}
.contentCells-icon {
width: 13%;
}
.tableRow td:last-child {
width: 7%;
padding-right: 0px;
border: none;
}
.contentCells-shift {
padding-right: 0px;
}
.downloadContentCellShift:after {
width: 85%;
}
.firstContentCellViewers {
margin-left: 0;
border-bottom: 1px solid #e5e5e5 !important;
}
.firstContentCellViewers ~ td {
border-bottom: 1px solid #e5e5e5;
}
.tableRow td:first-child{
border: none;
width: 85%;
}
.contentCellsEmpty{
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
@ -527,7 +565,104 @@
}
}
@media (max-width: 560px) and (min-width: 510px) {
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
padding-right: 16px;
max-width: 4%;
}
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow,
menu.links {
width: 35%;
}
.tableRow td:first-child{
width: 83%;
}
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
max-width: 6%;
padding-right: 6px;
}
.firstContentCellShift {
flex-basis: 9%;
}
.tableRow td:last-child {
padding-right: 28px;
}
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow,
menu.links {
width: 30%;
}
.tableRow td:first-child{
width: 85%;
}
.contentCells-icon {
width: 11%;
}
.downloadContentCellShift {
max-width: 3%;
padding-right: 0px;
padding-left: 0;
}
.firstContentCellShift {
margin-left: 2px;
flex-basis: 14%;
}
.tableRow td:last-child {
width: 5%;
padding-right: 63px;
}
.firstContentCellViewers{
padding-right: 2px;
width: 12%;
}
.contentCellsEmpty{
display: none;
}
}
@media (max-width: 420px) {
.tableRow,
menu.links {
width: 25%;
}
.tableRow td:last-child {
width: 6%;
padding-right: 16px;
}
.downloadContentCellShift {
max-width: 4%;
margin-right: 18px;
margin-left: -1px;
}
.firstContentCellShift {
flex-basis: 2%;
}
.contentCells-icon{
width: 12%;
}
footer table td {
margin: 0;
padding-right: 5px;
@ -538,6 +673,10 @@
padding-right: 5px;
margin: 0;
}
.firstContentCellViewers{
padding-right: 2px;
width: 11%;
}
}
@media (max-width: 1160px) {
@ -546,15 +685,20 @@
}
}
@media (min-width: 593px) {
.contentCellsEmpty {
display: none;
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow,
.storedHeader,
menu.links {
width: 50%;
}
.storedHeaderClearAll {
padding-right: 26px;
}
@media (max-width: 510px) {
.tableRow td:first-child{
flex-grow: 0;
}
}
@media (max-width: 1100px) and (min-width: 890px){
@ -638,8 +782,8 @@
margin: 0;
position: fixed;
left: 0;
height: calc(100% - 44px);
z-index: 101;
height: calc(100% - 124px);
z-index:99;
}
.left-panel.active {
@ -749,7 +893,6 @@
.scroll-table-body {
top: 36px;
height: calc(100% - 34px);
}
.scroll-table-body tr:first-child {
@ -758,37 +901,16 @@
.tableRow {
border-bottom: 1px solid #e5e5e5;
padding: 12px 0;
padding: 16px 0;
width: 100%;
flex-wrap: nowrap;
}
.tableRow td:first-child {
width: 100%;
}
.tableRow td:last-child {
display: block;
width: 24px;
}
.contentCells {
padding: 0;
font-size: 13px;
}
.contentCells-icon {
width: auto;
display: none;
}
.stored-edit {
height: 12px;
padding: 6px 0 6px 34px;
}
.stored-edit span {
font-size: 13px;
font-size: 14px;
}
.header-list {
@ -796,7 +918,7 @@
}
.firstContentCellViewers {
margin: 0;
border-bottom: none !important;
}
.firstContentCellViewers ~ td {
@ -831,19 +953,4 @@
.user-block-table {
height: auto;
}
.upload-panel {
padding: 12px 0;
}
.user-block-table td select {
height: 48px;
padding-left: 12px;
border-radius: 6px;
border-color: #aaaaaa;
}
.user-block-table tr:last-child {
display: none;
}
}

View File

@ -756,6 +756,7 @@ footer a:hover {
.contentCells {
display: block;
border-bottom: 1px solid #EFEFEF;
font-family: 'Open Sans', sans-serif;
font-size: 16px;
padding: 4px;
@ -848,7 +849,6 @@ footer a:hover {
position: absolute;
right: 0;
top: 71px;
height: calc(100% - 130px);
scrollbar-color: #D0D5DA transparent;
scrollbar-width: thin;
}
@ -919,18 +919,18 @@ html {
position: relative;
}
.tableRow td:first-child {
display: flex;
flex-grow: 1;
max-width: 29%;
}
.tableRow td:first-child {
display: flex;
flex-grow: 1;
max-width: 25%;
}
.tableHeaderCellFileName {
width: 24%;
width: 20%;
}
.tableHeaderCellEditors {
width: 17%;
width: 20%;
}
.tableHeaderCellViewers {
@ -988,103 +988,3 @@ html {
top: 50%;
transform: translate(-50%, -50%);
}
.tableRow td:last-child {
display: none;
}
#mobileContextMenu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(51, 51, 51, 0.3);
display: flex;
justify-content: center;
align-items: flex-end;
z-index: 100;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0s linear 0.4s;
}
#mobileContextMenu.active {
visibility: visible;
opacity: 1;
transition: opacity 0.3s ease;
}
#mobileContextMenu .context-body {
width: 100%;
max-height: 100%;
transform: translateY(100%);
transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
}
#mobileContextMenu.active .context-body {
transform: translateY(0);
}
#mobileContextMenu table {
background-color: white;
width: 100%;
margin-top: 150px;
padding-bottom: 96px;
}
#mobileContextMenu thead {
padding: 12px 16px 0;
height: 48px;
position: sticky;
top: -1px;
display: flex;
align-items: center;
background-color: white;
}
#mobileContextMenu thead:not(.is-pinned)::after {
content: '';
position: absolute;
left: 16px;
right: 16px;
bottom: 0px;
height: 1px;
background: #e2e2e2;
}
#mobileContextMenu thead.is-pinned {
box-shadow: 0px 4px 6px 0px #CCCCCC4D;
transition: all 0.4s ease-out;
}
#mobileContextMenu tbody {
padding: 0 16px;
display: block
}
#mobileContextMenu tr {
display: block;
padding: 12px;
}
.context-section {
padding: 24px 0 6px !important;
font-size: 13px;
font-weight: 600;
color: #808080;
}
#mobileContextMenu a:not(.stored-edit) {
display: flex;
flex-direction: row;
align-items: center;
text-decoration: none;
}
#mobileContextMenu img {
margin-right: 8px;
}

View File

@ -52,13 +52,13 @@
</div>
<menu class="responsive-nav">
<li>
<a href="./">
<img src ="app_themes/images/mobile-logo.svg" alt="ONLYOFFICE" />
<a href="#" onclick="toggleSidePanel(event)">
<img src="app_themes/images/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="#" onclick="toggleSidePanel(event)">
<img src="app_themes/images/mobile-menu.svg" alt="ONLYOFFICE" />
<a href="./">
<img src ="app_themes/images/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
@ -129,7 +129,7 @@
<td valign="middle">
<label class="side-option">
<input id="directUrl" type="checkbox" class="checkbox" />Try opening on client
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server. Open each file in only one way." src="app_themes/images/info.svg" />
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server." src="app_themes/images/info.svg" />
</label>
</td>
</tr>
@ -212,7 +212,8 @@
var editUrl = "doceditor.aspx?fileID=" + HttpUtility.UrlEncode(storedFile.Name) + directUrlParam;
var ext = Path.GetExtension(storedFile.Name).ToLower();
var docType = DocumentType(storedFile.Name);
var actions = FormatManager.GetFormatActions(ext);
var canEdit = EditedExts.Contains(ext);
var isFillFormDoc = FillFormsExts.Contains(ext);
%>
<tr class="tableRow" title="<%= storedFile.Name %> [<%= GetFileVersion(storedFile.Name, HttpContext.Current.Request.UserHostAddress.Replace(':','_')) %>]">
@ -221,101 +222,98 @@
<span><%= storedFile.Name %></span>
</a>
</td>
<!-- 1-2 -->
<% if (actions.Contains("edit") || actions.Contains("lossy-edit")) { %>
<td class="contentCells contentCells-icon" data-section="EDITOR">
<% if (canEdit) { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=edit" %>" target="_blank">
<img src="app_themes/images/edit.svg" alt="Open for full size screens" title="Open for full size screens"/>
<img src="app_themes/images/desktop.svg" alt="Open in editor for full size screens" title="Open in editor for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=mobile&editorsMode=edit" %>" target="_blank">
<img src="app_themes/images/mobileEdit.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
<img src="app_themes/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon" data-section="EDITOR"></td>
<td class="contentCells contentCells-icon"></td>
<% } %>
<!-- 3 -->
<% if (actions.Contains("comment")) { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=comment" %>" target="_blank">
<img src="app_themes/images/comment.svg" alt="Open for comment" title="Open for comment"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon"></td>
<% } %>
<!-- 4-5 -->
<% if (actions.Contains("fill")) { %>
<td class="contentCells contentCells-icon firstContentCellShift">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/formsubmit.svg" alt="Open for filling in forms" title="Open for filling in forms"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a href="<%= editUrl + "&editorsType=mobile&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/mobile-fill-forms.svg" alt="Open for filling in forms for mobile devices" title="Open for filling in forms for mobile devices"/>
</a>
</td>
<% } else { %>
<!-- 4 -->
<% if (actions.Contains("review")) { %>
<% if (docType != "pdf") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=comment" %>" target="_blank">
<img src="app_themes/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=review" %>" target="_blank">
<img src="app_themes/images/review.svg" alt="Open for review" title="Open for review"/>
<img src="app_themes/images/review.svg" alt="Open in editor for review" title="Open in editor for review"/>
</a>
</td>
<% } else if (actions.Contains("customfilter")) { %>
<% } else if (docType == "cell") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=filter" %>" target="_blank">
<img src="app_themes/images/filter.svg" alt="Open without access to change the filter" title="Open without access to change the filter" />
<img src="app_themes/images/filter.svg" alt="Open in editor without access to change the filter" title="Open in editor without access to change the filter" />
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon"></td>
<% } %>
<!-- 5 -->
<% if (actions.Contains("edit") && docType == "word") { %>
<td class="contentCells contentCells-icon contentCells-shift">
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=blockcontent" %>" target="_blank">
<img src="app_themes/images/block-content.svg" alt="Open without content control modification" title="Open without content control modification"/>
<img src="app_themes/images/block-content.svg" alt="Open in editor without content control modification" title="Open in editor without content control modification"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon contentCells-shift"></td>
<% } else{%>
<td class="contentCells contentCells-icon"></td>
<%} %>
<%if (docType != "word" && docType != "cell"){%>
<td class="contentCells contentCells-icon "></td>
<% } %>
<% if (isFillFormDoc) { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
<% } %>
<% } else if (isFillFormDoc) { %>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=mobile&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/mobile-fill-forms.svg" alt="Open in editor for filling in forms for mobile devices" title="Open in editor for filling in forms for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon contentCellsEmpty" colspan="6"></td>
<% } %>
<td class="contentCells contentCells-icon firstContentCellViewers" data-section="VIEWERS">
<td class="contentCells contentCells-icon firstContentCellViewers">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=view" %>" target="_blank">
<img src="app_themes/images/view.svg" alt="Open for full size screens" title="Open for full size screens"/>
<img src="app_themes/images/desktop.svg" alt="Open in viewer for full size screens" title="Open in viewer for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=mobile&editorsMode=view" %>" target="_blank">
<img src="app_themes/images/mobileView.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
<img src="app_themes/images/mobile.svg" alt="Open in viewer for mobile devices" title="Open in viewer for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a href="<%= editUrl + "&editorsType=embedded&editorsMode=embedded" %>" target="_blank">
<img src="app_themes/images/embedview.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
<img src="app_themes/images/embeded.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
</a>
</td>
<% if (docType != null ) { %>
<td class="contentCells contentCells-icon" data-section="ACTION">
<td class="contentCells contentCells-icon">
<a class="convert-file" data="<%= storedFile.Name %>" data-type="<%= docType %>">
<img class="icon-action" src="app_themes/images/convert.svg" alt="Convert" title="Convert" /></a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon downloadContentCellShift" data-section="ACTION"></td>
<td class="contentCells contentCells-icon downloadContentCellShift"></td>
<% } %>
<td class="contentCells contentCells-icon downloadContentCellShift">
<a href="webeditor.ashx?type=download&fileName=<%= HttpUtility.UrlEncode(storedFile.Name) %>">
@ -327,11 +325,6 @@
<img class="icon-action" src="app_themes/images/delete.svg" alt="Delete" title="Delete" />
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="#" onclick="toggleContextMenu(event)">
<img src="app_themes/images/open-context.svg" alt="Open context menu" title="Open context menu" />
</a>
</td>
</tr>
<% } %>
</tbody>
@ -444,11 +437,6 @@
</footer>
</form>
<div id="mobileContextMenu" onclick="toggleContextMenu(event)">
<div class="context-body" id="mobileContextMenuBody">
</div>
</div>
<script language="javascript" type="text/javascript" src="script/jquery-3.6.4.min.js"></script>
<script language="javascript" type="text/javascript" src="script/jquery-migrate-3.4.1.min.js"></script>
<script language="javascript" type="text/javascript" src="script/jquery-ui.min.js"></script>

View File

@ -372,18 +372,13 @@ namespace OnlineEditorsExample
logoConfig.Add("directUrl", DirectImageUrl.ToString());
}
var result = new Dictionary<string, object>
{
{ "images", new List<Dictionary<string, object>>{logoConfig} }
};
if (JwtManager.Enabled) // if the secret key to generate token exists
{
var insImageToken = JwtManager.Encode(result); // encode logoConfig into the token
result.Add("token", insImageToken); // and add it to the logo config
var insImageToken = JwtManager.Encode(logoConfig); // encode logoConfig into the token
logoConfig.Add("token", insImageToken); // and add it to the logo config
}
return result;
return logoConfig;
}
// get a document which will be compared with the current document

View File

@ -198,13 +198,6 @@ namespace OnlineEditorsExample
return cachedFormats;
}
public static List<string> GetFormatActions(string extension)
{
return All()
.Find(format => format.Extension() == extension)
.Actions;
}
private static string GetPath()
{
string path = Path.Combine(GetDirectory(), "onlyoffice-docs-formats.json");

View File

@ -66,18 +66,18 @@
<Content Include="App_Themes\images\close.svg" />
<Content Include="App_Themes\images\comment.svg" />
<Content Include="App_Themes\images\delete.svg" />
<Content Include="App_Themes\images\desktop.svg" />
<Content Include="App_Themes\images\done.svg" />
<Content Include="App_Themes\images\download.svg" />
<Content Include="App_Themes\images\edit.svg" />
<Content Include="App_Themes\images\embedview.svg" />
<Content Include="App_Themes\images\embeded.svg" />
<Content Include="App_Themes\images\error.svg" />
<Content Include="App_Themes\images\file_docx.svg" />
<Content Include="App_Themes\images\file_docxf.svg" />
<Content Include="App_Themes\images\file_pptx.svg" />
<Content Include="App_Themes\images\file_upload.svg" />
<Content Include="App_Themes\images\file_xlsx.svg" />
<Content Include="App_Themes\images\fill-forms.svg" />
<Content Include="App_Themes\images\filter.svg" />
<Content Include="App_Themes\images\formsubmit.svg" />
<Content Include="App_Themes\images\home.svg" />
<Content Include="App_Themes\images\icon_docx.svg" />
<Content Include="App_Themes\images\icon_pptx.svg" />
@ -85,14 +85,12 @@
<Content Include="App_Themes\images\info.svg" />
<Content Include="App_Themes\images\logo.svg" />
<Content Include="App_Themes\images\mobile-fill-forms.svg" />
<Content Include="App_Themes\images\mobileEdit.svg" />
<Content Include="App_Themes\images\mobileView.svg" />
<Content Include="App_Themes\images\mobile.svg" />
<Content Include="App_Themes\images\notdone.svg" />
<Content Include="App_Themes\images\review.svg" />
<Content Include="App_Themes\images\slide.ico" />
<Content Include="App_Themes\images\uid-1.png" />
<Content Include="App_Themes\images\uid-2.png" />
<Content Include="App_Themes\images\view.svg" />
<Content Include="App_Themes\images\word.ico" />
<Content Include="App_Themes\media.css" />
<Content Include="Forgotten.aspx" />

View File

@ -81,45 +81,6 @@ In case the example and Document Server are installed on different computers, ma
Make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## File API methods used in this example
The methods described below are available for .Net (C#) test example.
### POST `/webeditor.ashx?type=upload`
| | |
| ---------------------- | ------------------------------------------------------------ |
| **Summary** | Upload file to test example via request |
| **URL** | /webeditor.ashx?type=upload |
| **Method** | POST |
| **Request<br>Headers** | `Content-Type: multipart/form-data` |
| **Request<br>Body** | `uploadedFile=@<filepath>`<br> `filepath` - file for uploading<br />Multipart body with the file binary contents |
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `{ "filename": <filename>}`<br />**Content on error:**<br /> `{ "error": "File type is not supported" }` <br /> Or <br /> `{ "error": "File size is incorrect" }` |
| **Sample** | `curl -X POST -F uploadedFile=@filename.docx http://localhost/webeditor.ashx?type=upload` |
### GET `/webeditor.ashx?type=remove`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Delete one file or all files |
| **URL** | /webeditor.ashx?type=remove |
| **Method** | GET |
| ****URL Params**** | **Optional:**<br /> `filename=[string]` - file for deleting. <br /> *WARNING! Without this parameter, all files will be deleted* |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `{ "success": true }` |
| **Sample** | **Delete one file:**<br />`curl -X GET http://localhost/webeditor.ashx?type=remove&filename=filename.docx`<br />**Delete all files:**<br />`curl -X GET http://localhost/webeditor.ashx?type=remove`<br /> |
### GET `/webeditor.ashx?type=files`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Get information about all files |
| **URL** | /webeditor.ashx?type=files |
| **Method** | GET |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}, ..., {...}]` |
| **Sample** | `curl -X GET http://localhost/webeditor.ashx?type=files` |
## Important security info
Please keep in mind the following security aspects when you are using test examples:

View File

@ -561,76 +561,4 @@ function toggleUserDescr(event) {
if (list.classList.contains("active")) list.classList.remove("active");
else list.classList.add("active");
}
}
function toggleContextMenu(event) {
let contextMenu = document.querySelector("#mobileContextMenu");
let target = event.currentTarget.parentNode.parentNode.cloneNode(true);
const closeContextMenu = () => {
contextMenu.classList.remove("active");
}
if (contextMenu.classList.contains("active") || !target.classList.contains("tableRow")) {
if (event.target.id == "mobileContextMenuBody") closeContextMenu();
return;
}
let contextBody = document.querySelector("#mobileContextMenuBody");
contextBody.innerHTML = "";
let startY = 0;
let startScroll = 0;
contextBody.addEventListener('touchstart', (e) => {
startY = e.touches[0].clientY;
startScroll = contextBody.scrollTop;
});
contextBody.addEventListener('touchmove', (e) => {
const currentY = e.touches[0].clientY;
const diff = currentY - startY;
if (diff > 10 && (contextBody.scrollTop === 0 || contextBody.scrollTop === startScroll)) {
closeContextMenu();
}
});
let thead = document.createElement("thead");
thead.appendChild(target.children[0]);
const observer = new IntersectionObserver(
([e]) => e.target.classList.toggle("is-pinned", e.intersectionRatio < 1),
{ threshold: [1] }
);
observer.observe(thead);
let tbody = document.createElement("tbody");
for (let td of Array.from(target.children).slice(0, -1)){
if (td.getAttribute("data-section")){
let section = document.createElement("tr");
section.innerText = td.getAttribute("data-section");
section.classList.add("context-section");
tbody.appendChild(section);
}
if (td.children.length == 0) continue;
let action = document.createElement("div");
action.innerText = td.children[0].children[0].getAttribute("title");
td.children[0].appendChild(action);
td.children[0].onclick = () => {
setTimeout(() => window.location.reload(), 0);
}
td.style.display = "block";
td.classList.remove("downloadContentCellShift");
td.classList.remove("firstContentCellViewers");
let tr = document.createElement("tr");
tr.appendChild(td);
tbody.appendChild(tr);
}
let table = document.createElement("table");
table.appendChild(thead);
table.appendChild(tbody);
contextBody.appendChild(table);
contextMenu.classList.add("active");
}

View File

@ -79,51 +79,3 @@ Also, [specify the same secret key](https://helpcenter.onlyoffice.com/installati
### Step 7. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
## File API methods used in this example
The methods described below are available for Go test example.
### POST `/upload`
| | |
| ---------------------- | ------------------------------------------------------------ |
| **Summary** | Upload file to test example via request |
| **URL** | /upload |
| **Method** | POST |
| **Request<br>Headers** | `Content-Type: multipart/form-data` |
| **Request<br>Body** | `uploadedFile=@<filepath>`<br> `filepath` - file for uploading<br />Multipart body with the file binary contents |
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `{ "filename": <filename>}`<br />**Content on error:**<br /> `{ "error": "File type is not supported" }` <br /> Or <br /> `{ "error": "File size is incorrect" }` |
| **Sample** | `curl -X POST -F uploadedFile=@filename.docx http://localhost/upload` |
### GET `/remove`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Delete one file |
| **URL** | /remove |
| **Method** | GET |
| ****URL Params**** | `filename=[string]` - file for deleting. |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `{ "success": true }` |
| **Sample** | `curl -X GET http://localhost/remove?filename=filename.docx` |
### DELETE `/remove`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Delete all files |
| **URL** | /remove |
| **Method** | DELETE |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `{ "success": true }` |
| **Sample** |`curl -X DELETE http://localhost/remove` |
### GET `/files`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Get information about all files |
| **URL** | /files |
| **Method** | GET |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}, ..., {...}]` |
| **Sample** | `curl -X GET http://localhost/files` |

View File

@ -15,12 +15,19 @@
* limitations under the License.
*
*/
package models
package config
type Format struct {
Name string `json:"name"`
FormatType string `json:"type"`
Actions []string `json:"actions"`
Convert []string `json:"convert"`
Mime []string `json:"mime"`
type Extensions struct {
Viewed []string `json:"viewed"`
Edited []string `json:"edited"`
Converted []string `json:"converted"`
Filled []string `json:"filled"`
}
type ExtensionTypes struct {
Spreadsheet []string `json:"spreadsheet"`
Presentation []string `json:"presentation"`
Document []string `json:"document"`
Pdf []string `json:"pdf"`
Diagram []string `json:"diagram"`
}

View File

@ -22,6 +22,7 @@ import (
"runtime"
"time"
"github.com/ONLYOFFICE/document-server-integration/utils"
"github.com/spf13/viper"
"go.uber.org/fx"
)
@ -46,6 +47,11 @@ type ApplicationConfig struct {
Languages map[string]string `mapstructure:"LANGUAGES"`
}
type SpecificationConfig struct {
Extensions Extensions `mapstructure:"extensions"`
ExtensionTypes ExtensionTypes `mapstructure:"extension_types"`
}
func NewConfiguration() (app_config ApplicationConfig, err error) {
_, b, _, _ := runtime.Caller(0)
basepath := filepath.Dir(b)
@ -70,6 +76,33 @@ func NewConfiguration() (app_config ApplicationConfig, err error) {
return
}
func NewSpecification() (specification SpecificationConfig, err error) {
fm, err := utils.NewFormatManager()
if err != nil {
return SpecificationConfig{}, err
}
exts := Extensions{
fm.GetViewedExtensions(),
fm.GetEditedExtensions(),
fm.GetConvertedExtensions(),
fm.GetFilledExtensions(),
}
extTypes := ExtensionTypes{
fm.GetSpreadsheetExtensions(),
fm.GetPresentationExtensions(),
fm.GetDocumentExtensions(),
fm.GetPdfExtensions(),
fm.GetDiagramExtensions(),
}
specification = SpecificationConfig{
exts,
extTypes,
}
return
}
var ConfigurationModule = fx.Options(
fx.Provide(NewConfiguration),
fx.Provide(NewSpecification),
)

View File

@ -31,18 +31,20 @@ import (
)
type DefaultServerEndpointsHandler struct {
logger *zap.SugaredLogger
config config.ApplicationConfig
logger *zap.SugaredLogger
config config.ApplicationConfig
specification config.SpecificationConfig
*handlers.CallbackRegistry
*managers.Managers
}
func NewDefaultServerEndpointsHandler(logger *zap.SugaredLogger, config config.ApplicationConfig,
reg *handlers.CallbackRegistry,
spec config.SpecificationConfig, reg *handlers.CallbackRegistry,
managers *managers.Managers) api.ServerEndpointsHandler {
return &DefaultServerEndpointsHandler{
logger,
config,
spec,
reg,
managers,
}
@ -62,15 +64,6 @@ func generateUrl(r *http.Request) string {
}
var decoder = schema.NewDecoder()
var indexTemplate = template.Must(template.New("index.html").Funcs(template.FuncMap{
"contains": func(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
},
}).ParseFiles("templates/index.html"))
var indexTemplate = template.Must(template.ParseFiles("templates/index.html"))
var forgottenTemplate = template.Must(template.ParseFiles("templates/forgotten.html"))
var editorTemplate = template.Must(template.ParseFiles("templates/editor.html"))

View File

@ -79,9 +79,7 @@ func (srv *DefaultServerEndpointsHandler) Convert(w http.ResponseWriter, r *http
return
}
newUrl, newExt, err := srv.ConversionManager.GetConverterUri(
fileUrl, fileExt, toExt, key, true, filename, payload.Filepass,
)
newUrl, newExt, err := srv.ConversionManager.GetConverterUri(fileUrl, fileExt, toExt, key, true, filename)
if err != nil {
response.Error = err.Error()
srv.logger.Errorf("File conversion error: %s", err.Error())
@ -94,7 +92,8 @@ func (srv *DefaultServerEndpointsHandler) Convert(w http.ResponseWriter, r *http
response.Step = 100
supportedExt := true
for _, f := range srv.FormatManager.GetAllFormats() {
fm, err := utils.NewFormatManager()
for _, f := range fm.GetFormats() {
if f.Name == newExt && len(f.Actions) == 0 {
supportedExt = false
break

View File

@ -56,7 +56,7 @@ func (srv *DefaultServerEndpointsHandler) Create(w http.ResponseWriter, r *http.
}
fileExt := utils.GetFileExt(fileName, true)
if strings.TrimSpace(fileExt) == "" || !srv.FormatManager.HasAction(fileExt, "view") {
if strings.TrimSpace(fileExt) == "" || !utils.IsInList(fileExt, srv.specification.Extensions.Viewed) {
srv.logger.Errorf("%s extension is not supported", fileExt)
shared.SendCustomErrorResponse(w, "extension is not supported")
return
@ -106,7 +106,7 @@ func (srv *DefaultServerEndpointsHandler) Create(w http.ResponseWriter, r *http.
query := r.URL.Query()
fileExt, isSample := query.Get("fileExt"), query.Get("sample")
if strings.TrimSpace(fileExt) == "" || !srv.FormatManager.HasAction(fileExt, "edit") {
if strings.TrimSpace(fileExt) == "" || !utils.IsInList(fileExt, srv.specification.Extensions.Edited) {
srv.logger.Errorf("%s extension is not supported", fileExt)
http.Redirect(w, r, "/", http.StatusSeeOther)
return

View File

@ -67,12 +67,8 @@ func (srv *DefaultServerEndpointsHandler) Editor(w http.ResponseWriter, r *http.
"usersForMentions": usersForMentions,
"usersInfo": usersInfo,
"dataInsertImage": map[string]interface{}{
"images": []map[string]interface{}{
{
"fileType": "svg",
"url": remoteAddr + "/static/images/logo.svg",
},
},
"fileType": "svg",
"url": remoteAddr + "/static/images/logo.svg",
},
"dataDocument": map[string]interface{}{
"fileType": "docx",

View File

@ -71,7 +71,7 @@ func (srv *DefaultServerEndpointsHandler) Forgotten(w http.ResponseWriter, r *ht
if err = json.NewDecoder(res.Body).Decode(&file); err != nil {
srv.logger.Errorf("could not parse forgotten file[%s]: %s", file.Key, err.Error())
} else {
file.Type = srv.FormatManager.GetFileType(file.Url)
file.Type = srv.Managers.ConversionManager.GetFileType(file.Url)
files = append(files, file)
}
}

View File

@ -18,13 +18,21 @@
package dapi
import (
"fmt"
"net/http"
"github.com/ONLYOFFICE/document-server-integration/server/shared"
"github.com/ONLYOFFICE/document-server-integration/utils"
)
func (srv *DefaultServerEndpointsHandler) Formats(w http.ResponseWriter, r *http.Request) {
srv.logger.Debug("A new formats call")
fm, err := utils.NewFormatManager()
if err != nil {
srv.logger.Errorf("could not fetch formats: %s", err.Error())
shared.SendCustomErrorResponse(w, fmt.Sprintf("could not fetch formats: %s", err.Error()))
return
}
shared.SendResponse(w, srv.FormatManager.GetAllFormats())
shared.SendResponse(w, fm.GetFormats())
}

View File

@ -29,6 +29,7 @@ func (srv *DefaultServerEndpointsHandler) Index(w http.ResponseWriter, r *http.R
}
data := map[string]interface{}{
"Extensions": srv.specification.Extensions,
"Users": srv.Managers.UserManager.GetUsers(),
"Files": files,
"Preloader": srv.config.DocumentServerHost + srv.config.DocumentServerPreloader,
@ -37,8 +38,5 @@ func (srv *DefaultServerEndpointsHandler) Index(w http.ResponseWriter, r *http.R
"ServerVersion": srv.config.Version,
}
err = indexTemplate.Execute(w, data)
if err != nil {
srv.logger.Errorf("Could not execute template: %s", err.Error())
}
indexTemplate.Execute(w, data) // nolint: errcheck
}

View File

@ -73,26 +73,17 @@ type JwtManager interface {
}
type ConversionManager interface {
GetFileType(filename string) string
GetInternalExtension(fileType string) string
GetConverterUri(
docUri, fromExt, toExt, docKey string,
isAsync bool, title string, filePass string,
) (string, string, error)
IsCanConvert(ext string) bool
IsCanFill(ext string) bool
GetConverterUri(docUri, fromExt, toExt, docKey string, isAsync bool, title string) (string, string, error)
}
type CommandManager interface {
CommandRequest(method string, docKey string, meta interface{}) (*http.Response, error)
}
type FormatManager interface {
GetAllFormats() []models.Format
GetFormat(ext string) models.Format
GetActions(ext string) []string
GetTypeByExtension(ext string) string
GetFileType(filename string) string
HasAction(ext string, action string) bool
}
type Managers struct {
DocumentManager
HistoryManager
@ -101,13 +92,12 @@ type Managers struct {
JwtManager
ConversionManager
CommandManager
FormatManager
}
func New(umanager UserManager, smanager StorageManager,
hmanager HistoryManager, dmanager DocumentManager,
jmanager JwtManager, cmanager ConversionManager,
commanager CommandManager, fmanager FormatManager) *Managers {
commanager CommandManager) *Managers {
return &Managers{
HistoryManager: hmanager,
StorageManager: smanager,
@ -116,6 +106,5 @@ func New(umanager UserManager, smanager StorageManager,
JwtManager: jmanager,
ConversionManager: cmanager,
CommandManager: commanager,
FormatManager: fmanager,
}
}

View File

@ -35,20 +35,46 @@ import (
)
type DefaultConversionManager struct {
config config.ApplicationConfig
logger *zap.SugaredLogger
config config.ApplicationConfig
specification config.SpecificationConfig
logger *zap.SugaredLogger
managers.JwtManager
}
func NewDefaultConversionManager(config config.ApplicationConfig,
func NewDefaultConversionManager(config config.ApplicationConfig, spec config.SpecificationConfig,
logger *zap.SugaredLogger, jmanager managers.JwtManager) managers.ConversionManager {
return &DefaultConversionManager{
config,
spec,
logger,
jmanager,
}
}
func (cm DefaultConversionManager) GetFileType(filename string) string {
ext := utils.GetFileExt(filename, true)
exts := cm.specification.ExtensionTypes
if utils.IsInList(ext, exts.Pdf) {
return shared.ONLYOFFICE_PDF
}
if utils.IsInList(ext, exts.Document) {
return shared.ONLYOFFICE_DOCUMENT
}
if utils.IsInList(ext, exts.Spreadsheet) {
return shared.ONLYOFFICE_SPREADSHEET
}
if utils.IsInList(ext, exts.Presentation) {
return shared.ONLYOFFICE_PRESENTATION
}
if utils.IsInList(ext, exts.Diagram) {
return shared.ONLYOFFICE_DIAGRAM
}
return shared.ONLYOFFICE_DOCUMENT
}
func (cm DefaultConversionManager) GetInternalExtension(fileType string) string {
switch fileType {
case shared.ONLYOFFICE_DOCUMENT:
@ -62,6 +88,14 @@ func (cm DefaultConversionManager) GetInternalExtension(fileType string) string
}
}
func (cm DefaultConversionManager) IsCanFill(ext string) bool {
return utils.IsInList(ext, cm.specification.Extensions.Filled)
}
func (cm DefaultConversionManager) IsCanConvert(ext string) bool {
return utils.IsInList(ext, cm.specification.Extensions.Converted)
}
func (cm DefaultConversionManager) GetConverterUri(
docUri string,
fromExt string,
@ -69,7 +103,6 @@ func (cm DefaultConversionManager) GetConverterUri(
docKey string,
isAsync bool,
title string,
filePass string,
) (string, string, error) {
if fromExt == "" {
fromExt = utils.GetFileExt(docUri, true)
@ -82,7 +115,6 @@ func (cm DefaultConversionManager) GetConverterUri(
Title: title,
Key: docKey,
Async: isAsync,
Password: filePass,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * cm.config.JwtExpiresIn)),
IssuedAt: jwt.NewNumericDate(time.Now()),

View File

@ -33,13 +33,13 @@ import (
)
type DefaultDocumentManager struct {
config config.ApplicationConfig
logger *zap.SugaredLogger
config config.ApplicationConfig
specification config.SpecificationConfig
logger *zap.SugaredLogger
managers.StorageManager
managers.UserManager
managers.ConversionManager
managers.JwtManager
managers.FormatManager
}
const (
@ -53,18 +53,17 @@ const (
onlyoffice_permission_comment = "comment"
)
func NewDefaultDocumentManager(config config.ApplicationConfig, logger *zap.SugaredLogger,
smanager managers.StorageManager, umanager managers.UserManager,
cmanager managers.ConversionManager, jmanager managers.JwtManager,
fmanager managers.FormatManager) managers.DocumentManager {
func NewDefaultDocumentManager(config config.ApplicationConfig, specification config.SpecificationConfig,
logger *zap.SugaredLogger, smanager managers.StorageManager, umanager managers.UserManager,
cmanager managers.ConversionManager, jmanager managers.JwtManager) managers.DocumentManager {
return &DefaultDocumentManager{
config,
specification,
logger,
smanager,
umanager,
cmanager,
jmanager,
fmanager,
}
}
@ -77,8 +76,7 @@ func (dm DefaultDocumentManager) sanitizeEditorParameters(parameters *managers.E
parameters.PermissionsMode = "edit"
}
actions := dm.FormatManager.GetActions(utils.GetFileExt(parameters.Filename, true))
parameters.CanEdit = slices.Contains(actions, "edit") || slices.Contains(actions, "lossy-edit")
parameters.CanEdit = utils.IsInList(utils.GetFileExt(parameters.Filename, true), dm.specification.Extensions.Edited)
if parameters.CanEdit && parameters.PermissionsMode != "view" {
parameters.Mode = "edit"
@ -157,7 +155,7 @@ func (dm DefaultDocumentManager) BuildDocumentConfig(
config := &models.Config{
Type: parameters.Type,
DocumentType: dm.FormatManager.GetFileType(parameters.Filename),
DocumentType: dm.ConversionManager.GetFileType(parameters.Filename),
Document: models.Document{
Title: parameters.Filename,
Url: furi,
@ -247,8 +245,8 @@ func (dm DefaultDocumentManager) BuildDocumentConfig(
func (dm DefaultDocumentManager) IsDocumentConvertable(filename string) bool {
ext := utils.GetFileExt(filename, true)
actions := dm.FormatManager.GetActions(ext)
return slices.Contains(actions, "view") || slices.Contains(actions, "edit") || slices.Contains(actions, "convert")
return utils.IsInList(ext, dm.specification.Extensions.Viewed) ||
utils.IsInList(ext, dm.specification.Extensions.Edited) || utils.IsInList(ext, dm.specification.Extensions.Converted)
}
func (dm DefaultDocumentManager) generateCallbackUrl(filename string, remoteAddress string) string {

View File

@ -1,89 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2026
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package dmanager
import (
"encoding/json"
"io"
"os"
"path/filepath"
"runtime"
"slices"
"github.com/ONLYOFFICE/document-server-integration/server/managers"
"github.com/ONLYOFFICE/document-server-integration/server/models"
"github.com/ONLYOFFICE/document-server-integration/utils"
)
type DefaultFormatManager struct {
formats []models.Format
}
func NewDefaultFormatManager() (managers.FormatManager, error) {
_, b, _, _ := runtime.Caller(0)
parentDir := filepath.Dir(filepath.Dir(filepath.Dir(filepath.Dir(b))))
path := filepath.Join(parentDir, "static", "assets", "document-formats", "onlyoffice-docs-formats.json")
fileContent, err := os.Open(path)
if err != nil {
return DefaultFormatManager{}, err
}
defer fileContent.Close()
byteResult, _ := io.ReadAll(fileContent)
var formats []models.Format
err = json.Unmarshal(byteResult, &formats)
if err != nil {
return DefaultFormatManager{}, err
}
return DefaultFormatManager{
formats,
}, err
}
func (fm DefaultFormatManager) GetAllFormats() []models.Format {
return fm.formats
}
func (fm DefaultFormatManager) GetFormat(ext string) models.Format {
for _, f := range fm.formats {
if f.Name == ext {
return f
}
}
return models.Format{}
}
func (fm DefaultFormatManager) GetActions(ext string) []string {
return fm.GetFormat(ext).Actions
}
func (fm DefaultFormatManager) GetTypeByExtension(ext string) string {
return fm.GetFormat(ext).FormatType
}
func (fm DefaultFormatManager) GetFileType(filename string) string {
ext := utils.GetFileExt(filename, true)
return fm.GetTypeByExtension(ext)
}
func (fm DefaultFormatManager) HasAction(ext string, action string) bool {
return slices.Contains(fm.GetActions(ext), action)
}

View File

@ -27,5 +27,4 @@ var DefaultManagersModule = fx.Options(
fx.Provide(NewDefaultJwtManager),
fx.Provide(NewDefaultConversionManager),
fx.Provide(NewDefaultCommandManager),
fx.Provide(NewDefaultFormatManager),
)

View File

@ -36,19 +36,19 @@ import (
)
type DefaultStorageManager struct {
config config.ApplicationConfig
logger *zap.SugaredLogger
config config.ApplicationConfig
specification config.SpecificationConfig
logger *zap.SugaredLogger
managers.ConversionManager
managers.FormatManager
}
func NewDefaultStorageManager(config config.ApplicationConfig, logger *zap.SugaredLogger,
conversionManager managers.ConversionManager, formatManager managers.FormatManager) managers.StorageManager {
func NewDefaultStorageManager(config config.ApplicationConfig, specification config.SpecificationConfig,
logger *zap.SugaredLogger, conversionManager managers.ConversionManager) managers.StorageManager {
return &DefaultStorageManager{
config,
specification,
logger,
conversionManager,
formatManager,
}
}
@ -115,10 +115,11 @@ func (sm DefaultStorageManager) GetStoredFiles(remoteAddress string) ([]models.D
}
documents = append(documents, models.Document{
FileType: sm.FormatManager.GetFileType(filename),
FileType: sm.ConversionManager.GetFileType(filename),
Title: filename,
Url: sm.GeneratePublicFileUri(filename, remoteAddress, managers.FileMeta{}),
Actions: sm.FormatManager.GetActions(utils.GetFileExt(filename, true)),
CanEdit: !sm.ConversionManager.IsCanConvert(utils.GetFileExt(filename, true)),
CanFill: sm.ConversionManager.IsCanFill(utils.GetFileExt(filename, true)),
Version: fmt.Sprint(version),
})
}

View File

@ -30,6 +30,23 @@ type DefaultUserManager struct {
func NewDefaultUserManager(logger *zap.SugaredLogger) managers.UserManager {
users := []models.User{
{
Id: "uid-0",
Username: "",
Email: "",
Group: "",
ReviewGroups: nil,
CommentGroups: nil,
UserInfoGroups: nil,
Favorite: -1,
DeniedPermissions: []string{"protect"},
Description: descriptionUser0,
Templates: false,
Avatar: false,
Goback: nil,
Close: nil,
Roles: []string{},
},
{
Id: "uid-1",
Username: "John Smith",
@ -99,23 +116,6 @@ func NewDefaultUserManager(logger *zap.SugaredLogger) managers.UserManager {
},
Roles: []string{"role"},
},
{
Id: "uid-0",
Username: "",
Email: "",
Group: "",
ReviewGroups: nil,
CommentGroups: nil,
UserInfoGroups: nil,
Favorite: -1,
DeniedPermissions: []string{"protect"},
Description: descriptionUser0,
Templates: false,
Avatar: false,
Goback: nil,
Close: nil,
Roles: []string{},
},
}
return &DefaultUserManager{
users,
@ -197,7 +197,7 @@ func (um DefaultUserManager) GetUserById(uid string) (models.User, error) {
}
}
return um.GetUserById("uid-0")
return um.users[0], nil
}
func (um DefaultUserManager) GetUserInfoById(uid string, serverAddress string) models.UserInfo {

View File

@ -99,7 +99,6 @@ type ConvertRequestPayload struct {
Key string `json:"key"`
Async bool `json:"async"`
JwtToken string `json:"token,omitempty"`
Password string `json:"password"`
jwt.RegisteredClaims
}

View File

@ -51,5 +51,6 @@ type Document struct {
Version string `json:"version"`
Permissions Permissions `json:"permissions,omitempty"`
ReferenceData ReferenceData `json:"referenceData"`
Actions []string
CanEdit bool
CanFill bool
}

View File

@ -30,8 +30,9 @@ import (
)
type Server struct {
Http *http.Server
Config config.ApplicationConfig
Http *http.Server
Config config.ApplicationConfig
ServerSpecification config.SpecificationConfig
*api.ServerAPI
Logger *zap.SugaredLogger
*managers.Managers
@ -39,15 +40,16 @@ type Server struct {
isRunning bool
}
func New(config config.ApplicationConfig,
func New(config config.ApplicationConfig, specification config.SpecificationConfig,
logger *zap.SugaredLogger, managers *managers.Managers, api *api.ServerAPI, reg *handlers.CallbackRegistry) *Server {
srv := Server{
Config: config,
ServerAPI: api,
Logger: logger,
isRunning: false,
Managers: managers,
CallbackRegistry: reg,
Config: config,
ServerSpecification: specification,
ServerAPI: api,
Logger: logger,
isRunning: false,
Managers: managers,
CallbackRegistry: reg,
}
r := srv.configureRouter()

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 6H5L5 15H19V6ZM5 4C3.89543 4 3 4.89543 3 6V15C3 16.1046 3.89543 17 5 17H10V18H6V20H18V18H14V17H19C20.1046 17 21 16.1046 21 15V6C21 4.89543 20.1046 4 19 4H5Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 331 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 19H8.11111L8.84845 18.2627L5.73734 15.1516L5 15.8889V19ZM10.2627 16.8484L19 8.11111V6.55556H17.4444V5H15.8889L7.15155 13.7373L10.2627 16.8484Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 316 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="4" y="6" width="16" height="13" rx="1" stroke="#444444" stroke-width="2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.148 8.69651C13.8858 8.43384 13.4601 8.43384 13.1979 8.69651V8.69651C12.9362 8.95858 12.9362 9.38302 13.1979 9.64509L15.3401 11.7908C15.7296 12.1809 15.7299 12.8126 15.3409 13.2031L13.1967 15.3554C12.9357 15.6173 12.9357 16.041 13.1967 16.3029V16.3029C13.4591 16.5663 13.8855 16.5663 14.1478 16.3029L17.3302 13.1086V13.1086C17.668 12.7702 17.668 12.2222 17.3302 11.8838L14.148 8.69651Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.85199 16.3035C10.1142 16.5662 10.5399 16.5662 10.8021 16.3035V16.3035C11.0638 16.0414 11.0638 15.617 10.8021 15.3549L8.65987 13.2092C8.2704 12.8191 8.27006 12.1874 8.65911 11.7969L10.8033 9.64461C11.0643 9.38266 11.0643 8.959 10.8033 8.69706V8.69706C10.5409 8.43371 10.1145 8.43371 9.85218 8.69706L6.66983 11.8914V11.8914C6.33201 12.2298 6.33201 12.7778 6.66983 13.1162L9.85199 16.3035Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.326 18.6739C13.8912 18.2391 13.8912 17.5342 14.326 17.0994L20.0993 11.3261C20.5341 10.8913 21.239 10.8913 21.6738 11.3261C22.1086 11.7609 22.1086 12.4658 21.6738 12.9006L15.9006 18.6739C15.4658 19.1087 14.7608 19.1087 14.326 18.6739Z" fill="#444444"/>
<path d="M14.326 5.3261C14.7608 4.8913 15.4658 4.8913 15.9006 5.3261L21.6738 11.0994C22.1086 11.5342 22.1086 12.2391 21.6738 12.6739C21.239 13.1087 20.5341 13.1087 20.0993 12.6739L14.326 6.90063C13.8912 6.46583 13.8912 5.76089 14.326 5.3261Z" fill="#444444"/>
<path d="M9.67385 5.3261C10.1086 5.76089 10.1086 6.46583 9.67385 6.90063L3.90061 12.6739C3.46582 13.1087 2.76088 13.1087 2.32609 12.6739C1.8913 12.2391 1.8913 11.5342 2.32609 11.0994L8.09933 5.3261C8.53412 4.8913 9.23905 4.8913 9.67385 5.3261Z" fill="#444444"/>
<path d="M9.67385 18.6739C9.23905 19.1087 8.53412 19.1087 8.09933 18.6739L2.32609 12.9006C1.8913 12.4658 1.8913 11.7609 2.32609 11.3261C2.76088 10.8913 3.46582 10.8913 3.90061 11.3261L9.67385 17.0994C10.1086 17.5342 10.1086 18.2391 9.67385 18.6739Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 379 B

View File

@ -1,3 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 5C17.6569 5 19 6.34315 19 8V16C19 17.6569 17.6569 19 16 19H8C6.34315 19 5 17.6569 5 16V8C5 6.34315 6.34315 5 8 5H16ZM11 7V17H16L16.1025 16.9951C16.573 16.9472 16.9472 16.573 16.9951 16.1025L17 16V8C17 7.48232 16.6067 7.05621 16.1025 7.00488L16 7H11Z" fill="#EFEFEF"/>
</svg>
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="2" rx="1" fill="white"/>
<rect y="6" width="20" height="2" rx="1" fill="white"/>
<rect y="12" width="20" height="2" rx="1" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 278 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C6.89543 3 6 3.89543 6 5V19C6 20.1046 6.89543 21 8 21H16C17.1046 21 18 20.1046 18 19V5C18 3.89543 17.1046 3 16 3H8ZM16.8462 6H7.15385V18H16.8462V6ZM10.3846 4H13.6154V5H10.3846V4ZM12 20C12.2974 20 12.5385 19.7761 12.5385 19.5C12.5385 19.2239 12.2974 19 12 19C11.7026 19 11.4615 19.2239 11.4615 19.5C11.4615 19.7761 11.7026 20 12 20Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 506 B

View File

@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 5C4 3.89543 4.89543 3 6 3H15C16.1046 3 17 3.89543 17 5V7H16V6H5V18H16V17H17V19C17 20.1046 16.1046 21 15 21H6C4.89543 21 4 20.1046 4 19V5ZM12 4H9V5H12V4ZM11 19.5C11 19.7761 10.7761 20 10.5 20C10.2239 20 10 19.7761 10 19.5C10 19.2239 10.2239 19 10.5 19C10.7761 19 11 19.2239 11 19.5Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 16H14L14.6464 15.3536L12.6464 13.3536L12 14V16ZM15.3536 14.6464L21 9V8H20V7H19L13.3536 12.6464L15.3536 14.6464Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 638 B

View File

@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 5C4 3.89543 4.89543 3 6 3H15C16.1046 3 17 3.89543 17 5V7H16V6H5V18H16V17H17V19C17 20.1046 16.1046 21 15 21H6C4.89543 21 4 20.1046 4 19V5ZM12 4H9V5H12V4ZM11 19.5C11 19.7761 10.7761 20 10.5 20C10.2239 20 10 19.7761 10 19.5C10 19.2239 10.2239 19 10.5 19C10.7761 19 11 19.2239 11 19.5Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 8C11.3252 8 8.89946 9.40288 7.10954 11.6815C6.96349 11.8682 6.96349 12.129 7.10954 12.3157C8.89946 14.5971 11.3252 16 14 16C16.6748 16 19.1005 14.5971 20.8905 12.3185C21.0365 12.1318 21.0365 11.871 20.8905 11.6843C19.1005 9.40288 16.6748 8 14 8ZM14.1955 14.9939C12.3863 15.1077 10.8923 13.6166 11.0061 11.8045C11.0995 10.3105 12.3105 9.09949 13.8045 9.00611C15.6137 8.89231 17.1077 10.3834 16.9939 12.1955C16.8976 13.6866 15.6866 14.8976 14.1955 14.9939ZM14.0641 12.998C13.4609 13.0359 12.9625 12.5392 13.0022 11.9359C13.0329 11.4373 13.4375 11.0346 13.9359 11.002C14.5391 10.9641 15.0375 11.4608 14.9978 12.0641C14.9653 12.5645 14.5607 12.9673 14.0641 12.998Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.33331 10C4.22665 10 3.33331 10.8933 3.33331 12C3.33331 13.1067 4.22665 14 5.33331 14C6.43998 14 7.33331 13.1067 7.33331 12C7.33331 10.8933 6.43998 10 5.33331 10ZM18.6666 10C17.56 10 16.6666 10.8933 16.6666 12C16.6666 13.1067 17.56 14 18.6666 14C19.7733 14 20.6666 13.1067 20.6666 12C20.6666 10.8933 19.7733 10 18.6666 10ZM12 10C10.8933 10 9.99998 10.8933 9.99998 12C9.99998 13.1067 10.8933 14 12 14C13.1066 14 14 13.1067 14 12C14 10.8933 13.1066 10 12 10Z" fill="#808080"/>
</svg>

Before

Width:  |  Height:  |  Size: 588 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C8.17879 6 4.71351 8.10432 2.15649 11.5223C1.94784 11.8023 1.94784 12.1935 2.15649 12.4736C4.71351 15.8957 8.17879 18 12 18C15.8212 18 19.2865 15.8957 21.8435 12.4777C22.0522 12.1977 22.0522 11.8065 21.8435 11.5264C19.2865 8.10432 15.8212 6 12 6ZM12.2607 15.9919C9.84844 16.1436 7.8564 14.1554 8.00813 11.7393C8.13264 9.74729 9.74728 8.13265 11.7393 8.00815C14.1516 7.85641 16.1436 9.84456 15.9919 12.2607C15.8635 14.2488 14.2488 15.8635 12.2607 15.9919ZM12.1282 13.9959C10.9219 14.0718 9.92498 13.0783 10.0044 11.8718C10.0658 10.8747 10.8749 10.0691 11.8718 10.0041C13.0781 9.92821 14.075 10.9217 13.9956 12.1282C13.9305 13.1289 13.1215 13.9345 12.1282 13.9959Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 838 B

View File

@ -130,7 +130,7 @@ if (typeof jQuery !== "undefined") {
var responseText = data.responseText;
var response = jq.parseJSON(responseText);
if (response.error) {
if (response.error.includes("-5")) {
if (response.error.includes("Incorrect password")) {
jq(".current").removeClass("current");
jq("#step2").addClass("error");
jq("#blockPassword").show();
@ -545,76 +545,4 @@ function toggleUserDescr(event) {
if (list.classList.contains("active")) list.classList.remove("active");
else list.classList.add("active");
}
}
function toggleContextMenu(event) {
let contextMenu = document.querySelector("#mobileContextMenu");
let target = event.currentTarget.parentNode.parentNode.cloneNode(true);
const closeContextMenu = () => {
contextMenu.classList.remove("active");
}
if (contextMenu.classList.contains("active") || !target.classList.contains("tableRow")) {
if (event.target.id == "mobileContextMenuBody") closeContextMenu();
return;
}
let contextBody = document.querySelector("#mobileContextMenuBody");
contextBody.innerHTML = "";
let startY = 0;
let startScroll = 0;
contextBody.addEventListener('touchstart', (e) => {
startY = e.touches[0].clientY;
startScroll = contextBody.scrollTop;
});
contextBody.addEventListener('touchmove', (e) => {
const currentY = e.touches[0].clientY;
const diff = currentY - startY;
if (diff > 10 && (contextBody.scrollTop === 0 || contextBody.scrollTop === startScroll)) {
closeContextMenu();
}
});
let thead = document.createElement("thead");
thead.appendChild(target.children[0]);
const observer = new IntersectionObserver(
([e]) => e.target.classList.toggle("is-pinned", e.intersectionRatio < 1),
{ threshold: [1] }
);
observer.observe(thead);
let tbody = document.createElement("tbody");
for (let td of Array.from(target.children).slice(0, -1)){
if (td.getAttribute("data-section")){
let section = document.createElement("tr");
section.innerText = td.getAttribute("data-section");
section.classList.add("context-section");
tbody.appendChild(section);
}
if (td.children.length == 0) continue;
let action = document.createElement("div");
action.innerText = td.children[0].children[0].getAttribute("title");
td.children[0].appendChild(action);
td.children[0].onclick = () => {
setTimeout(() => window.location.reload(), 0);
}
td.style.display = "block";
td.classList.remove("downloadContentCellShift");
td.classList.remove("firstContentCellViewers");
let tr = document.createElement("tr");
tr.appendChild(td);
tbody.appendChild(tr);
}
let table = document.createElement("table");
table.appendChild(thead);
table.appendChild(tbody);
contextBody.appendChild(table);
contextMenu.classList.add("active");
}

View File

@ -51,8 +51,8 @@
.tableHeader td:last-child, .tableRow td:last-child {
width: 10%;
text-align: right;
display: revert;
text-align: center;
padding: 0 !important;
}
.tableHeader {
@ -81,11 +81,6 @@ menu.links {
.scroll-table-body {
overflow-y: auto;
width: 100%;
}
.scroll-table-body td {
padding: 0 !important;
}
.stored-list {

View File

@ -34,15 +34,15 @@
}
.tableHeaderCellFileName {
width: 29%;
width: 25%;
}
.tableHeaderCellEditors {
width: 12%;
width: 13%;
}
.tableHeaderCellViewers {
width: 15%;
width: 18%;
text-align: right;
}
@ -84,7 +84,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 90%;
}
@ -143,7 +142,6 @@
.scroll-table-body {
top: 31px;
height: calc(100% - 34px);
}
footer {
@ -184,14 +182,9 @@
@media (max-width: 715px) {
.tableRow,
.storedHeader,
menu.links {
width: 45%;
}
.storedHeaderClearAll{
padding-right: 24px;
}
}
@media (max-width: 670px) and (min-width: 620px){
.main-panel{
@ -227,15 +220,15 @@
.tableRow td:first-child {
flex-grow: 0;
width: 26%;
}
.tableHeaderCellFileName {
width: 15%;
}
.tableHeaderCellFileName {
width: 9%;
}
.tableHeaderCellEditors {
width: 3%;
width: 13%;
}
.tableHeaderCellViewers {
@ -260,12 +253,12 @@
}
.tableHeaderCellEditors {
width: 13%;
width: 15%;
text-align: left;
}
.tableHeaderCellFileName {
width: 29%;
width: 28%;
}
.tableHeaderCellViewers {
@ -288,7 +281,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 75%;
}
@ -310,10 +302,6 @@
.firstContentCellViewers {
margin-left: 0;
}
.storedHeaderClearAll {
padding-right: 39px;
}
}
@media (max-width: 890px) and (min-width: 769px ) {
@ -329,7 +317,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 95%;
}
@ -350,7 +337,7 @@
}
.tableHeaderCellFileName {
width: 22%;
width: 20%;
}
.tableHeaderCellEditors {
@ -359,22 +346,18 @@
}
.tableHeaderCellViewers {
width: 15%;
width: 19%;
}
.tableHeaderCellAction {
width: 19%;
padding-right: 45px;
}
.storedHeaderClearAll {
padding-right: 29px;
}
}
@media (max-width: 890px) {
.tableRow td:first-child {
max-width: 22%;
max-width: 17%;
}
#portal-info {
@ -454,6 +437,61 @@
padding: 16px 0 6px;
}
.tableRow,
menu.links {
width: 40%;
}
.tableRow td {
border: none;
}
.firstContentCellShift {
border: none;
flex-basis: 10%;
flex-grow: 1;
}
.downloadContentCellShift {
max-width: 7%;
margin-right: 24px;
margin-left: 0;
}
.contentCells-icon {
width: 13%;
}
.tableRow td:last-child {
width: 7%;
padding-right: 0px;
border: none;
}
.contentCells-shift {
padding-right: 0px;
}
.downloadContentCellShift:after {
width: 85%;
}
.firstContentCellViewers {
margin-left: 0;
border-bottom: 1px solid #e5e5e5 !important;
}
.firstContentCellViewers ~ td {
border-bottom: 1px solid #e5e5e5;
}
.tableRow td:first-child{
border: none;
width: 85%;
}
.contentCellsEmpty{
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
@ -528,7 +566,104 @@
}
}
@media (max-width: 560px) and (min-width: 510px) {
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
padding-right: 16px;
max-width: 4%;
}
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow,
menu.links {
width: 35%;
}
.tableRow td:first-child{
width: 83%;
}
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
max-width: 6%;
padding-right: 6px;
}
.firstContentCellShift {
flex-basis: 9%;
}
.tableRow td:last-child {
padding-right: 28px;
}
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow,
menu.links {
width: 30%;
}
.tableRow td:first-child{
width: 85%;
}
.contentCells-icon {
width: 11%;
}
.downloadContentCellShift {
max-width: 3%;
padding-right: 0px;
padding-left: 0;
}
.firstContentCellShift {
margin-left: 2px;
flex-basis: 14%;
}
.tableRow td:last-child {
width: 5%;
padding-right: 63px;
}
.firstContentCellViewers{
padding-right: 2px;
width: 12%;
}
.contentCellsEmpty{
display: none;
}
}
@media (max-width: 420px) {
.tableRow,
menu.links {
width: 25%;
}
.tableRow td:last-child {
width: 6%;
padding-right: 16px;
}
.downloadContentCellShift {
max-width: 4%;
margin-right: 18px;
margin-left: -1px;
}
.firstContentCellShift {
flex-basis: 2%;
}
.contentCells-icon{
width: 12%;
}
footer table td {
margin: 0;
padding-right: 5px;
@ -539,6 +674,10 @@
padding-right: 5px;
margin: 0;
}
.firstContentCellViewers{
padding-right: 2px;
width: 11%;
}
}
@media (max-width: 1160px) {
@ -547,15 +686,20 @@
}
}
@media (min-width: 593px) {
.contentCellsEmpty {
display: none;
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow,
.storedHeader,
menu.links {
width: 50%;
}
.storedHeaderClearAll{
padding-right: 26px;
}
@media (max-width: 510px) {
.tableRow td:first-child{
flex-grow: 0;
}
}
@media (max-width: 1100px) and (min-width: 890px){
@ -637,8 +781,8 @@
margin: 0;
position: fixed;
left: 0;
height: calc(100% - 44px);
z-index: 101;
height: calc(100% - 124px);
z-index:99;
}
.left-panel.active {
@ -748,7 +892,6 @@
.scroll-table-body {
top: 36px;
height: calc(100% - 34px);
}
.scroll-table-body tr:first-child {
@ -757,37 +900,16 @@
.tableRow {
border-bottom: 1px solid #e5e5e5;
padding: 12px 0;
padding: 16px 0;
width: 100%;
flex-wrap: nowrap;
}
.tableRow td:first-child {
width: 100%;
}
.tableRow td:last-child {
display: block;
width: 24px;
}
.contentCells {
padding: 0;
font-size: 13px;
}
.contentCells-icon {
width: auto;
display: none;
}
.stored-edit {
height: 12px;
padding: 6px 0 6px 34px;
}
.stored-edit span {
font-size: 13px;
font-size: 14px;
}
.header-list {
@ -795,7 +917,7 @@
}
.firstContentCellViewers {
margin: 0;
border-bottom: none !important;
}
.firstContentCellViewers ~ td {
@ -830,19 +952,4 @@
.user-block-table {
height: auto;
}
.upload-panel {
padding: 12px 0;
}
.user-block-table td select {
height: 48px;
padding-left: 12px;
border-radius: 6px;
border-color: #aaaaaa;
}
.user-block-table tr:last-child {
display: none;
}
}

View File

@ -753,6 +753,7 @@ footer table tr td:first-child {
.contentCells {
display: block;
border-bottom: 1px solid #EFEFEF;
font-family: 'Open Sans', sans-serif;
font-size: 16px;
padding: 4px;
@ -845,7 +846,6 @@ footer table tr td:first-child {
position: absolute;
right: 0;
top: 71px;
height: calc(100% - 130px);
scrollbar-color: #D0D5DA transparent;
scrollbar-width: thin;
}
@ -919,15 +919,15 @@ html {
.tableRow td:first-child {
display: flex;
flex-grow: 1;
max-width: 29%;
max-width: 25%;
}
.tableHeaderCellFileName {
width: 24%;
width: 20%;
}
.tableHeaderCellEditors {
width: 17%;
width: 20%;
}
.tableHeaderCellViewers {
@ -984,104 +984,4 @@ html {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
.tableRow td:last-child {
display: none;
}
#mobileContextMenu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(51, 51, 51, 0.3);
display: flex;
justify-content: center;
align-items: flex-end;
z-index: 100;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0s linear 0.4s;
}
#mobileContextMenu.active {
visibility: visible;
opacity: 1;
transition: opacity 0.3s ease;
}
#mobileContextMenu .context-body {
width: 100%;
max-height: 100%;
transform: translateY(100%);
transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
}
#mobileContextMenu.active .context-body {
transform: translateY(0);
}
#mobileContextMenu table {
background-color: white;
width: 100%;
margin-top: 150px;
padding-bottom: 96px;
}
#mobileContextMenu thead {
padding: 12px 16px 0;
height: 48px;
position: sticky;
top: -1px;
display: flex;
align-items: center;
background-color: white;
}
#mobileContextMenu thead:not(.is-pinned)::after {
content: '';
position: absolute;
left: 16px;
right: 16px;
bottom: 0px;
height: 1px;
background: #e2e2e2;
}
#mobileContextMenu thead.is-pinned {
box-shadow: 0px 4px 6px 0px #CCCCCC4D;
transition: all 0.4s ease-out;
}
#mobileContextMenu tbody {
padding: 0 16px;
display: block
}
#mobileContextMenu tr {
display: block;
padding: 12px;
}
.context-section {
padding: 24px 0 6px !important;
font-size: 13px;
font-weight: 600;
color: #808080;
}
#mobileContextMenu a:not(.stored-edit) {
display: flex;
flex-direction: row;
align-items: center;
text-decoration: none;
}
#mobileContextMenu img {
margin-right: 8px;
}

View File

@ -40,13 +40,13 @@
</div>
<menu class="responsive-nav">
<li>
<a href="./">
<img src ="static/images/mobile-logo.svg" alt="ONLYOFFICE" />
<a href="#" onclick="toggleSidePanel(event)">
<img src ="static/images/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="#" onclick="toggleSidePanel(event)">
<img src ="static/images/mobile-menu.svg" alt="ONLYOFFICE" />
<a href="./">
<img src ="static/images/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
@ -116,7 +116,7 @@
<td valign="middle">
<label class="side-option">
<input id="directUrl" type="checkbox" class="checkbox" />Try opening on client
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server. Open each file in only one way." src="static/images/info.svg" />
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server." src="static/images/info.svg" />
</label>
</td>
</tr>
@ -199,101 +199,98 @@
<span>{{ .Title }}</span>
</a>
</td>
<!-- 1-2 -->
{{ if or (contains .Actions "edit") (contains .Actions "lossy-edit") }}
<td class="contentCells contentCells-icon" data-section="EDITOR">
{{ if .CanEdit }}
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=edit" target="_blank">
<img src="static/images/edit.svg" alt="Open for full size screens" title="Open for full size screens"/>
<img src="static/images/desktop.svg" alt="Open in editor for full size screens" title="Open in editor for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=mobile&mode=edit" target="_blank">
<img src="static/images/mobileEdit.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
<img src="static/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
</a>
</td>
{{ else }}
<td class="contentCells contentCells-icon" data-section="EDITOR"></td>
<td class="contentCells contentCells-icon"></td>
{{ end }}
<!-- 3 -->
{{ if contains .Actions "comment" }}
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=comment" target="_blank">
<img src="static/images/comment.svg" alt="Open for comment" title="Open for comment"/>
</a>
</td>
{{ else }}
<td class="contentCells contentCells-icon"></td>
{{ end }}
<!-- 4-5 -->
{{ if contains .Actions "fill" }}
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=fillForms" target="_blank">
<img src="static/images/formsubmit.svg" alt="Open for filling in forms" title="Open for filling in forms"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift firstContentCellShift">
<a href="editor?fileName={{ .Title }}&type=mobile&mode=fillForms" target="_blank">
<img src="static/images/mobile-fill-forms.svg" alt="Open for filling in forms for mobile devices" title="Open for filling in forms for mobile devices"/>
</a>
</td>
{{ else }}
<!-- 4 -->
{{ if contains .Actions "review" }}
{{ if ne .FileType "pdf" }}
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=comment" target="_blank">
<img src="static/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
{{ end }}
{{ if eq .FileType "word" }}
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=review" target="_blank">
<img src="static/images/review.svg" alt="Open for review" title="Open for review"/>
<img src="static/images/review.svg" alt="Open in editor for review" title="Open in editor for review"/>
</a>
</td>
{{ else if contains .Actions "customfilter" }}
{{ else if eq .FileType "cell" }}
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=filter" target="_blank">
<img src="static/images/filter.svg" alt="Open without access to change the filter" title="Open without access to change the filter" />
<img src="static/images/filter.svg" alt="Open in editor without access to change the filter" title="Open in editor without access to change the filter" />
</a>
</td>
{{ else }}
<td class="contentCells contentCells-icon"></td>
{{ end }}
<!-- 5 -->
{{ if and (contains .Actions "edit") (eq .FileType "word") }}
<td class="contentCells contentCells-icon contentCells-shift">
{{ if eq .FileType "word" }}
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=blockcontent" target="_blank">
<img src="static/images/block-content.svg" alt="Open without content control modification" title="Open without content control modification"/>
<img src="static/images/block-content.svg" alt="Open in editor without content control modification" title="Open in editor without content control modification"/>
</a>
</td>
{{ else }}
<td class="contentCells contentCells-icon contentCells-shift firstContentCellShift"></td>
<td class="contentCells contentCells-icon"></td>
{{ end }}
{{ if eq .FileType "slide" }}
<td class="contentCells contentCells-icon "></td>
{{ end }}
{{ if .CanFill }}
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=fillForms" target="_blank">
<img src="static/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
{{ else }}
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
{{ end }}
{{ else if .CanFill }}
<td class="contentCells contentCells-icon"></td>
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=mobile&mode=fillForms" target="_blank">
<img src="static/images/mobile-fill-forms.svg" alt="Open in editor for filling in forms for mobile devices" title="Open in editor for filling in forms for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon"></td>
<td class="contentCells contentCells-icon"></td>
<td class="contentCells contentCells-icon"></td>
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=fillForms" target="_blank">
<img src="static/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
{{ else }}
<td class="contentCells contentCells-shift contentCells-icon contentCellsEmpty" colspan="6"></td>
{{ end }}
<td class="contentCells contentCells-icon firstContentCellViewers" data-section="VIEWERS">
<td class="contentCells contentCells-icon firstContentCellViewers">
<a href="editor?fileName={{ .Title }}&type=desktop&mode=view" target="_blank">
<img src="static/images/view.svg" alt="Open for full size screens" title="Open for full size screens"/>
<img src="static/images/desktop.svg" alt="Open in viewer for full size screens" title="Open in viewer for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="editor?fileName={{ .Title }}&type=mobile&mode=view" target="_blank">
<img src="static/images/mobileView.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
<img src="static/images/mobile.svg" alt="Open in viewer for mobile devices" title="Open in viewer for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a href="editor?fileName={{ .Title }}&type=embedded&mode=embedded" target="_blank">
<img src="static/images/embedview.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
<img src="static/images/embeded.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
</a>
</td>
{{ if ne .FileType "" }}
<td class="contentCells contentCells-icon" data-section="ACTIONS">
<td class="contentCells contentCells-icon">
<a class="convert-file" data="{{ .Title }}" data-type="{{ .FileType }}">
<img class="icon-action" src="static/images/convert.svg" alt="Convert" title="Convert" /></a>
</td>
{{ else }}
<td class="contentCells contentCells-icon downloadContentCellShift" data-section="ACTIONS"></td>
<td class="contentCells contentCells-icon downloadContentCellShift"></td>
{{ end }}
<td class="contentCells contentCells-icon downloadContentCellShift">
<a href="download?fileName={{ .Title }}">
@ -305,11 +302,6 @@
<img class="icon-action" src="static/images/delete.svg" alt="Delete" title="Delete" />
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="#" onclick="toggleContextMenu(event)">
<img src="static/images/open-context.svg" alt="Open context menu" title="Open context menu" />
</a>
</td>
</tr>
{{ end }}
</tbody>
@ -420,11 +412,6 @@
</div>
</footer>
<div id="mobileContextMenu" onclick="toggleContextMenu(event)">
<div class="context-body" id="mobileContextMenuBody">
</div>
</div>
<script type="text/javascript" src="static/javascripts/jquery-3.6.4.min.js"></script>
<script type="text/javascript" src="static/javascripts/jquery-migrate-3.4.1.min.js"></script>
<script type="text/javascript" src="static/javascripts/jquery-ui.js"></script>

View File

@ -0,0 +1,161 @@
/**
*
* (c) Copyright Ascensio System SIA 2026
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package utils
import (
"encoding/json"
"io"
"os"
"path/filepath"
"runtime"
"slices"
)
type Format struct {
Name string `json:"name"`
FormatType string `json:"type"`
Actions []string `json:"actions"`
Convert []string `json:"convert"`
Mime []string `json:"mime"`
}
type DefaultFormatManager struct {
formats []Format
}
type FormatManager interface {
GetFormats() []Format
GetViewedExtensions() []string
GetEditedExtensions() []string
GetConvertedExtensions() []string
GetFilledExtensions() []string
GetDocumentExtensions() []string
GetSpreadsheetExtensions() []string
GetPresentationExtensions() []string
GetPdfExtensions() []string
GetDiagramExtensions() []string
}
func NewFormatManager() (FormatManager, error) {
_, b, _, _ := runtime.Caller(0)
parentDir := filepath.Dir(filepath.Dir(b))
path := filepath.Join(parentDir, "static", "assets", "document-formats", "onlyoffice-docs-formats.json")
fileContent, err := os.Open(path)
if err != nil {
return DefaultFormatManager{}, err
}
defer fileContent.Close()
byteResult, _ := io.ReadAll(fileContent)
var formats []Format
err = json.Unmarshal(byteResult, &formats)
if err != nil {
return DefaultFormatManager{}, err
}
return DefaultFormatManager{
formats,
}, err
}
func (fm DefaultFormatManager) GetFormats() []Format {
return fm.formats
}
func (fm DefaultFormatManager) GetViewedExtensions() (viewed []string) {
for _, f := range fm.formats {
if slices.Contains(f.Actions, "view") {
viewed = append(viewed, f.Name)
}
}
return
}
func (fm DefaultFormatManager) GetEditedExtensions() (edited []string) {
for _, f := range fm.formats {
if slices.Contains(f.Actions, "edit") {
edited = append(edited, f.Name)
}
}
return
}
func (fm DefaultFormatManager) GetConvertedExtensions() (converted []string) {
for _, f := range fm.formats {
if slices.Contains(f.Actions, "auto-convert") {
converted = append(converted, f.Name)
}
}
return converted
}
func (fm DefaultFormatManager) GetFilledExtensions() (filled []string) {
for _, f := range fm.formats {
if slices.Contains(f.Actions, "fill") {
filled = append(filled, f.Name)
}
}
return filled
}
func (fm DefaultFormatManager) GetDocumentExtensions() (word []string) {
for _, f := range fm.formats {
if f.FormatType == "word" {
word = append(word, f.Name)
}
}
return
}
func (fm DefaultFormatManager) GetSpreadsheetExtensions() (cell []string) {
for _, f := range fm.formats {
if f.FormatType == "cell" {
cell = append(cell, f.Name)
}
}
return
}
func (fm DefaultFormatManager) GetPresentationExtensions() (slide []string) {
for _, f := range fm.formats {
if f.FormatType == "slide" {
slide = append(slide, f.Name)
}
}
return
}
func (fm DefaultFormatManager) GetPdfExtensions() (pdf []string) {
for _, f := range fm.formats {
if f.FormatType == "pdf" {
pdf = append(pdf, f.Name)
}
}
return
}
func (fm DefaultFormatManager) GetDiagramExtensions() (diagram []string) {
for _, f := range fm.formats {
if f.FormatType == "diagram" {
diagram = append(diagram, f.Name)
}
}
return
}

View File

@ -295,45 +295,6 @@ In case the example and Document Server are installed on different computers, ma
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## File API methods used in this example
The methods described below are available for Java (Spring) test example.
### POST `/upload`
| | |
| ---------------------- | ------------------------------------------------------------ |
| **Summary** | Upload file to test example via request |
| **URL** | /upload |
| **Method** | POST |
| **Request<br>Headers** | `Content-Type: multipart/form-data` |
| **Request<br>Body** | `uploadedFile=@<filepath>`<br> `filepath` - file for uploading<br />Multipart body with the file binary contents |
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `{ "filename": <filename>}`<br />**Content on error:**<br /> `{ "error": "File type is not supported" }` <br /> Or <br /> `{ "error": "File size is incorrect" }` |
| **Sample** | `curl -X POST -F uploadedFile=@filename.docx http://localhost/upload` |
### POST `/delete`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Delete one file or all files |
| **URL** | /delete |
| **Method** | POST |
| ****Body Params**** | **Optional:**<br /> `filename: string` - file for deleting. <br /> *WARNING! Without this parameter, all files will be deleted* |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `{ "success": true }` |
| **Sample** | **Delete one file:**<br />`curl -X POST http://localhost/delete -d '{"filename": "filename.docx"}'`<br />**Delete all files:**<br />`curl -X POST http://localhost/delete`<br /> |
### GET `/files`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Get information about all files |
| **URL** | /files |
| **Method** | GET |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}, ..., {...}]` |
| **Sample** | `curl -X GET http://localhost/files` |
## Important security info
Please keep in mind the following security aspects when you are using test examples:

View File

@ -68,7 +68,7 @@ public class ExampleData {
"Can view chat",
"Has an avatar",
"Can submit forms",
"Has role 'Anyone'",
"Has no roles",
"Can start filling"
);
@ -85,7 +85,7 @@ public class ExampleData {
"Can view chat",
"Has an avatar",
"Can't submit forms",
"Has role 'role'",
"Has role 'Anyone'",
"Can start filling"
);
@ -105,7 +105,7 @@ public class ExampleData {
"Can't close history",
"Can't restore the file version",
"Can't submit forms",
"Has no roles",
"Has role 'role'",
"Can start filling"
);
@ -114,19 +114,19 @@ public class ExampleData {
"", List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), false, true, true, true,
new Goback(null, false), new Close(null, false), List.of("Anyone"), true);
new Goback(null, false), new Close(null, false), null, true);
// create user 2 with the specified parameters
userService.createUser("Mark Pottato", "pottato@example.com", descriptionUserSecond,
"group-2", List.of("", "group-2"), List.of(FilterState.NULL.toString()),
List.of("group-2", ""), List.of("group-2"), List.of("group-2", ""), true, true,
true, true, new Goback("Go to Documents", null), new Close(null, true), List.of("role"), false);
true, true, new Goback("Go to Documents", null), new Close(null, true), List.of("Anyone"), false);
// create user 3 with the specified parameters
userService.createUser("Hamish Mitchell", null, descriptionUserThird,
"group-3", List.of("group-2"), List.of("group-2", "group-3"), List.of("group-2"),
new ArrayList<>(), List.of("group-2"), null, true, true, false,
null, new Close(null, true), null, false);
null, new Close(null, true), List.of("role"), false);
// create user 0 with the specified parameters
userService.createUser("Anonymous", null, descriptionUserZero, "",

View File

@ -207,10 +207,8 @@ public class EditorController {
@SneakyThrows
private String getInsertImage() { // get an image that will be inserted into the document
Map<String, Object> dataInsertImage = new HashMap<>();
Map<String, Object>[] images = new HashMap[1];
images[0].put("fileType", "svg");
images[0].put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.svg");
dataInsertImage.put("images", images);
dataInsertImage.put("fileType", "svg");
dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.svg");
// check if the document token is enabled
if (settingsManager.isSecurityEnabled()) {

View File

@ -33,8 +33,8 @@ spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
hibernate.ddl-auto
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB
spring.servlet.multipart.max-file-size=5MB
spring.servlet.multipart.max-request-size=5MB
url.index=/
url.converter=/converter

View File

@ -51,8 +51,8 @@
.tableHeader td:last-child, .tableRow td:last-child {
width: 10%;
text-align: right;
display: revert;
text-align: center;
padding: 0 !important;
}
.tableHeader {
@ -81,11 +81,6 @@ menu.links {
.scroll-table-body {
overflow-y: auto;
width: 100%;
}
.scroll-table-body td {
padding: 0 !important;
}
.stored-list {

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 6H5L5 15H19V6ZM5 4C3.89543 4 3 4.89543 3 6V15C3 16.1046 3.89543 17 5 17H10V18H6V20H18V18H14V17H19C20.1046 17 21 16.1046 21 15V6C21 4.89543 20.1046 4 19 4H5Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 331 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 19H8.11111L8.84845 18.2627L5.73734 15.1516L5 15.8889V19ZM10.2627 16.8484L19 8.11111V6.55556H17.4444V5H15.8889L7.15155 13.7373L10.2627 16.8484Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 316 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="4" y="6" width="16" height="13" rx="1" stroke="#444444" stroke-width="2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.148 8.69651C13.8858 8.43384 13.4601 8.43384 13.1979 8.69651V8.69651C12.9362 8.95858 12.9362 9.38302 13.1979 9.64509L15.3401 11.7908C15.7296 12.1809 15.7299 12.8126 15.3409 13.2031L13.1967 15.3554C12.9357 15.6173 12.9357 16.041 13.1967 16.3029V16.3029C13.4591 16.5663 13.8855 16.5663 14.1478 16.3029L17.3302 13.1086V13.1086C17.668 12.7702 17.668 12.2222 17.3302 11.8838L14.148 8.69651Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.85199 16.3035C10.1142 16.5662 10.5399 16.5662 10.8021 16.3035V16.3035C11.0638 16.0414 11.0638 15.617 10.8021 15.3549L8.65987 13.2092C8.2704 12.8191 8.27006 12.1874 8.65911 11.7969L10.8033 9.64461C11.0643 9.38266 11.0643 8.959 10.8033 8.69706V8.69706C10.5409 8.43371 10.1145 8.43371 9.85218 8.69706L6.66983 11.8914V11.8914C6.33201 12.2298 6.33201 12.7778 6.66983 13.1162L9.85199 16.3035Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.326 18.6739C13.8912 18.2391 13.8912 17.5342 14.326 17.0994L20.0993 11.3261C20.5341 10.8913 21.239 10.8913 21.6738 11.3261C22.1086 11.7609 22.1086 12.4658 21.6738 12.9006L15.9006 18.6739C15.4658 19.1087 14.7608 19.1087 14.326 18.6739Z" fill="#444444"/>
<path d="M14.326 5.3261C14.7608 4.8913 15.4658 4.8913 15.9006 5.3261L21.6738 11.0994C22.1086 11.5342 22.1086 12.2391 21.6738 12.6739C21.239 13.1087 20.5341 13.1087 20.0993 12.6739L14.326 6.90063C13.8912 6.46583 13.8912 5.76089 14.326 5.3261Z" fill="#444444"/>
<path d="M9.67385 5.3261C10.1086 5.76089 10.1086 6.46583 9.67385 6.90063L3.90061 12.6739C3.46582 13.1087 2.76088 13.1087 2.32609 12.6739C1.8913 12.2391 1.8913 11.5342 2.32609 11.0994L8.09933 5.3261C8.53412 4.8913 9.23905 4.8913 9.67385 5.3261Z" fill="#444444"/>
<path d="M9.67385 18.6739C9.23905 19.1087 8.53412 19.1087 8.09933 18.6739L2.32609 12.9006C1.8913 12.4658 1.8913 11.7609 2.32609 11.3261C2.76088 10.8913 3.46582 10.8913 3.90061 11.3261L9.67385 17.0994C10.1086 17.5342 10.1086 18.2391 9.67385 18.6739Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 379 B

View File

@ -1,3 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 5C17.6569 5 19 6.34315 19 8V16C19 17.6569 17.6569 19 16 19H8C6.34315 19 5 17.6569 5 16V8C5 6.34315 6.34315 5 8 5H16ZM11 7V17H16L16.1025 16.9951C16.573 16.9472 16.9472 16.573 16.9951 16.1025L17 16V8C17 7.48232 16.6067 7.05621 16.1025 7.00488L16 7H11Z" fill="#EFEFEF"/>
</svg>
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="2" rx="1" fill="white"/>
<rect y="6" width="20" height="2" rx="1" fill="white"/>
<rect y="12" width="20" height="2" rx="1" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 278 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C6.89543 3 6 3.89543 6 5V19C6 20.1046 6.89543 21 8 21H16C17.1046 21 18 20.1046 18 19V5C18 3.89543 17.1046 3 16 3H8ZM16.8462 6H7.15385V18H16.8462V6ZM10.3846 4H13.6154V5H10.3846V4ZM12 20C12.2974 20 12.5385 19.7761 12.5385 19.5C12.5385 19.2239 12.2974 19 12 19C11.7026 19 11.4615 19.2239 11.4615 19.5C11.4615 19.7761 11.7026 20 12 20Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 506 B

View File

@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 5C4 3.89543 4.89543 3 6 3H15C16.1046 3 17 3.89543 17 5V7H16V6H5V18H16V17H17V19C17 20.1046 16.1046 21 15 21H6C4.89543 21 4 20.1046 4 19V5ZM12 4H9V5H12V4ZM11 19.5C11 19.7761 10.7761 20 10.5 20C10.2239 20 10 19.7761 10 19.5C10 19.2239 10.2239 19 10.5 19C10.7761 19 11 19.2239 11 19.5Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 16H14L14.6464 15.3536L12.6464 13.3536L12 14V16ZM15.3536 14.6464L21 9V8H20V7H19L13.3536 12.6464L15.3536 14.6464Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 638 B

View File

@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 5C4 3.89543 4.89543 3 6 3H15C16.1046 3 17 3.89543 17 5V7H16V6H5V18H16V17H17V19C17 20.1046 16.1046 21 15 21H6C4.89543 21 4 20.1046 4 19V5ZM12 4H9V5H12V4ZM11 19.5C11 19.7761 10.7761 20 10.5 20C10.2239 20 10 19.7761 10 19.5C10 19.2239 10.2239 19 10.5 19C10.7761 19 11 19.2239 11 19.5Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 8C11.3252 8 8.89946 9.40288 7.10954 11.6815C6.96349 11.8682 6.96349 12.129 7.10954 12.3157C8.89946 14.5971 11.3252 16 14 16C16.6748 16 19.1005 14.5971 20.8905 12.3185C21.0365 12.1318 21.0365 11.871 20.8905 11.6843C19.1005 9.40288 16.6748 8 14 8ZM14.1955 14.9939C12.3863 15.1077 10.8923 13.6166 11.0061 11.8045C11.0995 10.3105 12.3105 9.09949 13.8045 9.00611C15.6137 8.89231 17.1077 10.3834 16.9939 12.1955C16.8976 13.6866 15.6866 14.8976 14.1955 14.9939ZM14.0641 12.998C13.4609 13.0359 12.9625 12.5392 13.0022 11.9359C13.0329 11.4373 13.4375 11.0346 13.9359 11.002C14.5391 10.9641 15.0375 11.4608 14.9978 12.0641C14.9653 12.5645 14.5607 12.9673 14.0641 12.998Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.33331 10C4.22665 10 3.33331 10.8933 3.33331 12C3.33331 13.1067 4.22665 14 5.33331 14C6.43998 14 7.33331 13.1067 7.33331 12C7.33331 10.8933 6.43998 10 5.33331 10ZM18.6666 10C17.56 10 16.6666 10.8933 16.6666 12C16.6666 13.1067 17.56 14 18.6666 14C19.7733 14 20.6666 13.1067 20.6666 12C20.6666 10.8933 19.7733 10 18.6666 10ZM12 10C10.8933 10 9.99998 10.8933 9.99998 12C9.99998 13.1067 10.8933 14 12 14C13.1066 14 14 13.1067 14 12C14 10.8933 13.1066 10 12 10Z" fill="#808080"/>
</svg>

Before

Width:  |  Height:  |  Size: 588 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C8.17879 6 4.71351 8.10432 2.15649 11.5223C1.94784 11.8023 1.94784 12.1935 2.15649 12.4736C4.71351 15.8957 8.17879 18 12 18C15.8212 18 19.2865 15.8957 21.8435 12.4777C22.0522 12.1977 22.0522 11.8065 21.8435 11.5264C19.2865 8.10432 15.8212 6 12 6ZM12.2607 15.9919C9.84844 16.1436 7.8564 14.1554 8.00813 11.7393C8.13264 9.74729 9.74728 8.13265 11.7393 8.00815C14.1516 7.85641 16.1436 9.84456 15.9919 12.2607C15.8635 14.2488 14.2488 15.8635 12.2607 15.9919ZM12.1282 13.9959C10.9219 14.0718 9.92498 13.0783 10.0044 11.8718C10.0658 10.8747 10.8749 10.0691 11.8718 10.0041C13.0781 9.92821 14.075 10.9217 13.9956 12.1282C13.9305 13.1289 13.1215 13.9345 12.1282 13.9959Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 838 B

View File

@ -16,15 +16,15 @@
}
.tableHeaderCellFileName {
width: 29%;
width: 25%;
}
.tableHeaderCellEditors {
width: 12%;
width: 13%;
}
.tableHeaderCellViewers {
width: 15%;
width: 18%;
text-align: right;
}
@ -66,7 +66,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 90%;
}
@ -130,7 +129,6 @@
.scroll-table-body {
top: 31px;
height: calc(100% - 34px);
}
footer {
@ -175,14 +173,9 @@
@media (max-width: 715px) {
.tableRow,
.storedHeader,
menu.links {
width: 45%;
}
.storedHeaderClearAll {
padding-right: 24px;
}
}
@media (max-width: 670px) and (min-width: 620px){
/*.main-panel{*/
@ -218,15 +211,15 @@
.tableRow td:first-child {
flex-grow: 0;
width: 26%;
}
.tableHeaderCellFileName {
width: 15%;
}
.tableHeaderCellFileName {
width: 9%;
}
.tableHeaderCellEditors {
width: 3%;
width: 13%;
}
.tableHeaderCellViewers {
@ -250,12 +243,12 @@
}
.tableHeaderCellEditors {
width: 13%;
width: 15%;
text-align: left;
}
.tableHeaderCellFileName {
width: 29%;
width: 28%;
}
.tableHeaderCellViewers {
@ -278,7 +271,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 75%;
}
@ -300,10 +292,6 @@
.firstContentCellViewers {
margin-left: 0;
}
.storedHeaderClearAll {
padding-right: 39px;
}
}
@media (max-width: 890px) and (min-width: 769px ) {
@ -319,7 +307,6 @@
}
.tableRow,
.storedHeader,
menu.links {
width: 95%;
}
@ -340,7 +327,7 @@
}
.tableHeaderCellFileName {
width: 22%;
width: 20%;
}
.tableHeaderCellEditors {
@ -349,22 +336,18 @@
}
.tableHeaderCellViewers {
width: 15%;
width: 19%;
}
.tableHeaderCellAction {
width: 19%;
padding-right: 45px;
}
.storedHeaderClearAll {
padding-right: 30px;
}
}
@media (max-width: 890px) {
.tableRow td:first-child {
max-width: 22%;
max-width: 17%;
}
}
@ -440,6 +423,61 @@
padding: 16px 0 6px;
}
.tableRow,
menu.links {
width: 40%;
}
.tableRow td {
border: none;
}
.firstContentCellShift {
border: none;
flex-basis: 10%;
flex-grow: 1;
}
.downloadContentCellShift {
max-width: 7%;
margin-right: 24px;
margin-left: 0;
}
.contentCells-icon {
width: 13%;
}
.tableRow td:last-child {
width: 7%;
padding-right: 0px;
border: none;
}
.contentCells-shift {
padding-right: 0px;
}
.downloadContentCellShift:after {
width: 85%;
}
.firstContentCellViewers {
margin-left: 0;
border-bottom: 1px solid #e5e5e5 !important;
}
.firstContentCellViewers ~ td {
border-bottom: 1px solid #e5e5e5;
}
.tableRow td:first-child{
border: none;
width: 85%;
}
.contentCellsEmpty{
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
@ -514,7 +552,104 @@
}
}
@media (max-width: 560px) and (min-width: 510px) {
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
padding-right: 16px;
max-width: 4%;
}
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow,
menu.links {
width: 35%;
}
.tableRow td:first-child{
width: 83%;
}
.contentCells-icon {
width: 13%;
}
.downloadContentCellShift {
max-width: 6%;
padding-right: 6px;
}
.firstContentCellShift {
flex-basis: 9%;
}
.tableRow td:last-child {
padding-right: 28px;
}
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow,
menu.links {
width: 30%;
}
.tableRow td:first-child{
width: 85%;
}
.contentCells-icon {
width: 11%;
}
.downloadContentCellShift {
max-width: 3%;
padding-right: 0px;
padding-left: 0;
}
.firstContentCellShift {
margin-left: 2px;
flex-basis: 14%;
}
.tableRow td:last-child {
width: 5%;
padding-right: 63px;
}
.firstContentCellViewers{
padding-right: 2px;
width: 12%;
}
.contentCellsEmpty{
display: none;
}
}
@media (max-width: 420px) {
.tableRow,
menu.links {
width: 25%;
}
.tableRow td:last-child {
width: 6%;
padding-right: 16px;
}
.downloadContentCellShift {
max-width: 4%;
margin-right: 18px;
margin-left: -1px;
}
.firstContentCellShift {
flex-basis: 2%;
}
.contentCells-icon{
width: 12%;
}
footer table td {
margin: 0;
padding-right: 5px;
@ -525,6 +660,10 @@
padding-right: 5px;
margin: 0;
}
.firstContentCellViewers{
padding-right: 2px;
width: 11%;
}
}
@media (max-width: 1160px) {
@ -533,16 +672,16 @@
}
}
@media (min-width: 593px) {
.contentCellsEmpty {
display: none;
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow,
.storedHeader,
menu.links {
width: 50%;
}
.storedHeaderClearAll {
padding-right: 26px;
}
}
@media(max-width: 1080px) and (min-width: 986px){
.tableHeaderCellRemove{
@ -630,8 +769,8 @@
margin: 0;
position: fixed;
left: 0;
height: calc(100% - 44px);
z-index: 101;
height: calc(100% - 124px);
z-index:99;
}
.left-panel.active {
@ -741,7 +880,6 @@
.scroll-table-body {
top: 36px;
height: calc(100% - 34px);
}
.scroll-table-body tr:first-child {
@ -750,37 +888,16 @@
.tableRow {
border-bottom: 1px solid #e5e5e5;
padding: 12px 0;
padding: 16px 0;
width: 100%;
flex-wrap: nowrap;
}
.tableRow td:first-child {
width: 100%;
}
.tableRow td:last-child {
display: block;
width: 24px;
}
.contentCells {
padding: 0;
font-size: 13px;
}
.contentCells-icon {
width: auto;
display: none;
}
.stored-edit {
height: 12px;
padding: 6px 0 6px 34px;
}
.stored-edit span {
font-size: 13px;
font-size: 14px;
}
.header-list {
@ -788,7 +905,7 @@
}
.firstContentCellViewers {
margin: 0;
border-bottom: none !important;
}
.firstContentCellViewers ~ td {
@ -823,19 +940,4 @@
.user-block-table {
height: auto;
}
.upload-panel {
padding: 12px 0;
}
.user-block-table td select {
height: 48px;
padding-left: 12px;
border-radius: 6px;
border-color: #aaaaaa;
}
.user-block-table tr:last-child {
display: none;
}
}

View File

@ -750,6 +750,7 @@ footer table tr td:first-child {
.contentCells {
display: block;
border-bottom: 1px solid #e5e5e5;
font-family: 'Open Sans', sans-serif;
font-size: 16px;
padding: 4px;
@ -846,7 +847,6 @@ footer table tr td:first-child {
position: absolute;
right: 0;
top: 71px;
height: calc(100% - 130px);
scrollbar-color: #D0D5DA transparent;
scrollbar-width: thin;
}
@ -919,15 +919,15 @@ html {
.tableRow td:first-child {
display: flex;
flex-grow: 1;
max-width: 29%;
max-width: 25%;
}
.tableHeaderCellFileName {
width: 24%;
width: 20%;
}
.tableHeaderCellEditors {
width: 17%;
width: 20%;
}
.tableHeaderCellViewers {
@ -991,103 +991,3 @@ html {
top: 50%;
transform: translate(-50%, -50%);
}
.tableRow td:last-child {
display: none;
}
#mobileContextMenu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(51, 51, 51, 0.3);
display: flex;
justify-content: center;
align-items: flex-end;
z-index: 100;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0s linear 0.4s;
}
#mobileContextMenu.active {
visibility: visible;
opacity: 1;
transition: opacity 0.3s ease;
}
#mobileContextMenu .context-body {
width: 100%;
max-height: 100%;
transform: translateY(100%);
transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
}
#mobileContextMenu.active .context-body {
transform: translateY(0);
}
#mobileContextMenu table {
background-color: white;
width: 100%;
margin-top: 150px;
padding-bottom: 96px;
}
#mobileContextMenu thead {
padding: 12px 16px 0;
height: 48px;
position: sticky;
top: -1px;
display: flex;
align-items: center;
background-color: white;
}
#mobileContextMenu thead:not(.is-pinned)::after {
content: '';
position: absolute;
left: 16px;
right: 16px;
bottom: 0px;
height: 1px;
background: #e2e2e2;
}
#mobileContextMenu thead.is-pinned {
box-shadow: 0px 4px 6px 0px #CCCCCC4D;
transition: all 0.4s ease-out;
}
#mobileContextMenu tbody {
padding: 0 16px;
display: block
}
#mobileContextMenu tr {
display: block;
padding: 12px;
}
.context-section {
padding: 24px 0 6px !important;
font-size: 13px;
font-weight: 600;
color: #808080;
}
#mobileContextMenu a:not(.stored-edit) {
display: flex;
flex-direction: row;
align-items: center;
text-decoration: none;
}
#mobileContextMenu img {
margin-right: 8px;
}

View File

@ -559,76 +559,4 @@ function toggleUserDescr(event) {
if (list.classList.contains("active")) list.classList.remove("active");
else list.classList.add("active");
}
}
function toggleContextMenu(event) {
let contextMenu = document.querySelector("#mobileContextMenu");
let target = event.currentTarget.parentNode.parentNode.cloneNode(true);
const closeContextMenu = () => {
contextMenu.classList.remove("active");
}
if (contextMenu.classList.contains("active") || !target.classList.contains("tableRow")) {
if (event.target.id == "mobileContextMenuBody") closeContextMenu();
return;
}
let contextBody = document.querySelector("#mobileContextMenuBody");
contextBody.innerHTML = "";
let startY = 0;
let startScroll = 0;
contextBody.addEventListener('touchstart', (e) => {
startY = e.touches[0].clientY;
startScroll = contextBody.scrollTop;
});
contextBody.addEventListener('touchmove', (e) => {
const currentY = e.touches[0].clientY;
const diff = currentY - startY;
if (diff > 10 && (contextBody.scrollTop === 0 || contextBody.scrollTop === startScroll)) {
closeContextMenu();
}
});
let thead = document.createElement("thead");
thead.appendChild(target.children[0]);
const observer = new IntersectionObserver(
([e]) => e.target.classList.toggle("is-pinned", e.intersectionRatio < 1),
{ threshold: [1] }
);
observer.observe(thead);
let tbody = document.createElement("tbody");
for (let td of Array.from(target.children).slice(0, -1)){
if (td.getAttribute("data-section")){
let section = document.createElement("tr");
section.innerText = td.getAttribute("data-section");
section.classList.add("context-section");
tbody.appendChild(section);
}
if (td.children.length == 0) continue;
let action = document.createElement("div");
action.innerText = td.children[0].children[0].getAttribute("title");
td.children[0].appendChild(action);
td.children[0].onclick = () => {
setTimeout(() => window.location.reload(), 0);
}
td.style.display = "block";
td.classList.remove("downloadContentCellShift");
td.classList.remove("firstContentCellViewers");
let tr = document.createElement("tr");
tr.appendChild(td);
tbody.appendChild(tr);
}
let table = document.createElement("table");
table.appendChild(thead);
table.appendChild(tbody);
contextBody.appendChild(table);
contextMenu.classList.add("active");
}

View File

@ -36,16 +36,16 @@
</a>
</div>
<menu class="responsive-nav">
<li>
<a href="./">
<img src ="css/img/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="#" onclick="toggleSidePanel(event)">
<img src="css/img/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="./">
<img src ="css/img/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
</header>
@ -109,7 +109,6 @@
</select>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
@ -174,112 +173,109 @@
<span th:text="${files[iState.index].getName()}"></span>
</a>
</td>
<!-- 1-2 -->
<th:block th:if="${filesEditable[iState.index]}">
<td class="contentCells contentCells-icon" data-section="EDITOR">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='edit')}" target="_blank">
<img src="css/img/edit.svg" alt="Open for full size screens" title="Open for full size screens"/>
<img src="css/img/desktop.svg" alt="Open in editor for full size screens" title="Open in editor for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='mobile',action='edit')}" target="_blank">
<img src="css/img/mobileEdit.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
<img src="css/img/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
</a>
</td>
<div th:if="not ${docTypes[iState.index]} eq 'pdf'">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='comment')}" target="_blank">
<img src="css/img/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
</div>
<div th:if="${docTypes[iState.index]} eq 'word'">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='review')}" target="_blank">
<img src="css/img/review.svg" alt="Open in editor for review" title="Open in editor for review"/>
</a>
</td>
</div>
<div th:if="${docTypes[iState.index]} eq 'cell'">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='filter')}" target="_blank">
<img src="css/img/filter.svg" alt="Open in editor without access to change the filter" title="Open in editor without access to change the filter" />
</a>
</td>
</div>
<div th:if="${docTypes[iState.index]} eq 'word'">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='blockcontent')}" target="_blank">
<img src="css/img/block-content.svg" alt="Open in editor without content control modification" title="Open in editor without content control modification"/>
</a>
</td>
</div>
<div th:if="not (${docTypes[iState.index]} eq 'word')">
<td class="contentCells contentCells-icon"></td>
</div>
<div th:if="${docTypes[iState.index]} eq 'slide'">
<td class="contentCells contentCells-icon "></td>
</div>
<div th:if="${isFillFormDoc[iState.index]}">
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='fillForms')}" target="_blank">
<img src="css/img/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
</div>
<div th:if="${not isFillFormDoc[iState.index]}">
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
</div>
</th:block>
<th:block th:if="${isFillFormDoc[iState.index] and not filesEditable[iState.index]}">
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='mobile',action='fillForms')}" target="_blank">
<img src="css/img/mobile-fill-forms.svg" alt="Open in editor for filling in forms for mobile devices" title="Open in editor for filling in forms for mobile devices" />
</a>
</td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='fillForms')}" target="_blank">
<img src="css/img/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
</th:block>
<div th:unless="${filesEditable[iState.index]}">
<td class="contentCells contentCells-icon" data-section="EDITOR"></td>
<td class="contentCells contentCells-icon"></td>
</div>
<!-- 3 -->
<div th:if="${docTypes[iState.index]} != 'pdf'">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='comment')}" target="_blank">
<img src="css/img/comment.svg" alt="Open for comment" title="Open for comment"/>
</a>
</td>
</div>
<div th:unless="${docTypes[iState.index]} != 'pdf'">
<td class="contentCells contentCells-icon"></td>
</div>
<!-- 4-5 -->
<div th:if="${isFillFormDoc[iState.index]}">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='fillForms')}" target="_blank">
<img src="css/img/formsubmit.svg" alt="Open for filling in forms" title="Open for filling in forms"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='mobile',action='fillForms')}" target="_blank">
<img src="css/img/mobile-fill-forms.svg" alt="Open for filling in forms for mobile devices" title="Open for filling in forms for mobile devices" />
</a>
</td>
</div>
<div th:unless="${isFillFormDoc[iState.index]}">
<!-- 4 -->
<div th:if="${docTypes[iState.index]} eq 'word'">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='review')}" target="_blank">
<img src="css/img/review.svg" alt="Open for review" title="Open for review"/>
</a>
</td>
</div>
<div th:if="${docTypes[iState.index]} eq 'cell'">
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='filter')}" target="_blank">
<img src="css/img/filter.svg" alt="Open without access to change the filter" title="Open without access to change the filter" />
</a>
</td>
</div>
<div th:unless="${docTypes[iState.index]} eq 'cell' or ${docTypes[iState.index]} eq 'word'">
<td class="contentCells contentCells-icon"></td>
</div>
<!-- 5 -->
<div th:if="${docTypes[iState.index]} eq 'word'">
<td class="contentCells contentCells-icon contentCells-shift">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='blockcontent')}" target="_blank">
<img src="css/img/block-content.svg" alt="Open without content control modification" title="Open without content control modification"/>
</a>
</td>
</div>
<div th:unless="${docTypes[iState.index]} eq 'word'">
<td class="contentCells contentCells-icon contentCells-shift"></td>
</div>
</div>
<td class="contentCells contentCells-icon firstContentCellViewers" data-section="VIEWERS">
<th:block th:if="${not filesEditable[iState.index]}">
<td class="contentCells contentCells-shift contentCells-icon contentCellsEmpty" colspan="6"></td>
</th:block>
<td class="contentCells contentCells-icon firstContentCellViewers">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='view')}" target="_blank">
<img src="css/img/view.svg" alt="Open for full size screens" title="Open for full size screens"/>
<img src="css/img/desktop.svg" alt="Open in viewer for full size screens" title="Open in viewer for full size screens"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='mobile',action='view')}" target="_blank">
<img src="css/img/mobileView.svg" alt="Open for mobile devices" title="Open for mobile devices"/>
<img src="css/img/mobile.svg" alt="Open in viewer for mobile devices" title="Open in viewer for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a
th:href="@{/editor(fileName=${files[iState.index].getName()},type='embedded',action='embedded')}" target="_blank">
<img src="css/img/embedview.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
<img src="css/img/embeded.svg" alt="Open in embedded mode" title="Open in embedded mode"/>
</a>
</td>
<td class="contentCells contentCells-icon" data-section="ACTIONS">
<td class="contentCells contentCells-icon">
<a class="convert-file" th:data="${files[iState.index].getName()}" th:data-type="${docTypes[iState.index]}">
<img class="icon-action" src="css/img/convert.svg" alt="Convert" title="Convert" /></a>
</td>
@ -293,11 +289,6 @@
<img class="icon-action" src="css/img/delete.svg" alt="Delete" title="Delete" />
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="#" onclick="toggleContextMenu(event)">
<img src="css/img/open-context.svg" alt="Open context menu" title="Open context menu" />
</a>
</td>
</tr>
</tbody>
</table>
@ -408,11 +399,6 @@
</div>
</footer>
<div id="mobileContextMenu" onclick="toggleContextMenu(event)">
<div class="context-body" id="mobileContextMenuBody">
</div>
</div>
<script type="text/javascript" src="scripts/jquery-3.6.4.min.js"></script>
<script type="text/javascript" src="scripts/jquery-migrate-3.4.1.min.js"></script>
<script type="text/javascript" src="scripts/jquery-ui.js"></script>

View File

@ -312,45 +312,6 @@ In case the example and Document Server are installed on different computers, ma
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## File API methods used in this example
The methods described below are available for Java test example.
### POST `/IndexServlet?type=upload`
| | |
| ---------------------- | ------------------------------------------------------------ |
| **Summary** | Upload file to test example via request |
| **URL** | /IndexServlet?type=upload |
| **Method** | POST |
| **Request<br>Headers** | `Content-Type: multipart/form-data` |
| **Request<br>Body** | `uploadedFile=@<filepath>`<br> `filepath` - file for uploading<br />Multipart body with the file binary contents |
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `{ "filename": <filename>}`<br />**Content on error:**<br /> `{ "error": "File type is not supported" }` <br /> Or <br /> `{ "error": "File size is incorrect" }` |
| **Sample** | `curl -X POST -F uploadedFile=@filename.docx http://localhost/IndexServlet?type=upload` |
### GET `/IndexServlet?type=remove`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Delete one file or all files |
| **URL** | /IndexServlet?type=remove |
| **Method** | GET |
| ****URL Params**** | **Optional:**<br /> `filename=[string]` - file for deleting. <br /> *WARNING! Without this parameter, all files will be deleted* |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `{ "success": true }` |
| **Sample** | **Delete one file:**<br />`curl -X GET http://localhost/IndexServlet?type=remove&filename=filename.docx`<br />**Delete all files:**<br />`curl -X GET http://localhost/IndexServlet?type=remove`<br /> |
### GET `/IndexServlet?type=files`
| | |
| ------------------ | ------------------------------------------------------------ |
| **Summary** | Get information about all files |
| **URL** | /IndexServlet?type=files |
| **Method** | GET |
| **Response** | **Code:** 200 OK <br /> **Success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}, ..., {...}]` |
| **Sample** | `curl -X GET http://localhost/IndexServlet?type=files` |
## Important security info
Please keep in mind the following security aspects when you are using test examples:

View File

@ -78,14 +78,11 @@ public class EditorServlet extends HttpServlet {
// an image that will be inserted into the document
Map<String, Object> dataInsertImage = new HashMap<>();
Map<String, Object>[] images = new HashMap[1];
images[0] = new HashMap<>();
images[0].put("fileType", "svg");
images[0].put("url", DocumentManager.getServerUrl(true) + "/css/img/logo.svg");
dataInsertImage.put("fileType", "svg");
dataInsertImage.put("url", DocumentManager.getServerUrl(true) + "/css/img/logo.svg");
if (isEnableDirectUrl) {
images[0].put("directUrl", DocumentManager.getServerUrl(false) + "/css/img/logo.svg");
dataInsertImage.put("directUrl", DocumentManager.getServerUrl(false) + "/css/img/logo.svg");
}
dataInsertImage.put("images", images);
// a document that will be compared with the current document
Map<String, Object> dataDocument = new HashMap<>();

View File

@ -44,16 +44,6 @@ public final class FormatManager {
return this.formats;
}
public List<String> getFormatActions(final String ext) {
return this
.all()
.stream()
.filter(format -> format.getName().equals(ext))
.findFirst()
.get()
.getActions();
}
public List<Format> getFormatsByAction(final String action) {
return this
.all()

View File

@ -107,11 +107,6 @@ public final class DocumentManager {
return DocumentManager.formatManager.autoConvertExtensions();
}
// get actions for the file extension
public static List<String> getFormatActions(final String ext) {
return DocumentManager.formatManager.getFormatActions(ext);
}
// get current user host address
public static String curUserHostAddress(final String userAddress) {
String userAddr = userAddress;

View File

@ -1,6 +1,6 @@
version=1.15.0
filesize-max=104857600
filesize-max=5242880
storage-folder=app_data
filename-max=50
enable-forgotten=TRUE

Some files were not shown because too many files have changed in this diff Show More