Compare commits

...

207 Commits

Author SHA1 Message Date
1ef1987010 refactor(php): use file-row component in files table 2024-05-22 16:21:24 +05:00
e9f298d073 feat: file-table web component 2024-04-18 14:49:19 +03:00
e89eee7e28 Merge pull request #560 from ONLYOFFICE/bump-some-gems
build(ruby): bump gem versions as directed by dependabot
2024-04-09 11:20:35 +03:00
6a4b79fb54 build(ruby): bump gem versions as directed by dependabot 2024-04-05 17:39:48 +07:00
b1dd965590 Merge pull request #559 from ONLYOFFICE/fix/nodejs-dependencies-overrides
build(nodejs): add overrides in package.json
2024-04-05 10:25:35 +03:00
208bf086d8 Merge pull request #558 from ONLYOFFICE/feature/nodejs-navbar-update
feature/nodejs navbar update
2024-04-05 10:18:19 +03:00
ebb1179190 build(nodejs): add overrides in package.json 2024-04-04 17:32:09 +07:00
3375315cc0 feature(nodejs): show navigation bar at top even if there are no files in user directory 2024-04-04 13:08:47 +05:00
a070b6e82b nodejs: rename back (eda1876f59) 2024-04-03 14:27:57 +03:00
43d260cd7a Merge pull request #534 from ONLYOFFICE/feature/nodejs-forced-conversion
Feature/nodejs forced conversion
2024-04-03 14:05:24 +03:00
14bb9fc8a4 Merge pull request #556 from ONLYOFFICE/fix/wopi-mobile-default-action
fix(nodejs): mobileEdit default action for mobile wopi page. Fix Bug 65920
2024-04-03 13:07:02 +03:00
57ca15153f Merge pull request #551 from ONLYOFFICE/feature/fetching-formats
Feature/fetching formats
2024-04-03 12:31:53 +03:00
bbde4dc87b Merge pull request #525 from ONLYOFFICE/nodejs-update-dependencies
build(nodejs): updated dependencies
2024-04-03 12:19:33 +03:00
5b46195f72 fix(nodejs): mobileEdit default action for mobile wopi page. Fix Bug 65920 2024-04-02 12:55:33 +07:00
81c94c9fbd refactor(nodejs): load formats script and remove redundant variables 2024-04-01 12:24:14 +05:00
cc3c640868 refactor: merge format and format-manager files into formats file 2024-04-01 12:21:18 +05:00
20e6664a6b nodejs: absolute url in request to discovery (1e72167e7d)
Revert "nodejs: absolute host is not needed with urllib" (2460f2c7ac)
2024-03-28 13:35:50 +03:00
61af52a534 nodejs: fix favicon on wopi action 2024-03-28 10:53:12 +03:00
6236f90a50 Merge pull request #554 from ONLYOFFICE/feature/for-bug-59054
Feature/for bug 59054
2024-03-27 13:00:27 +03:00
5118352714 nodejs: debug mobile editors opening (Fix Bug 59054) 2024-03-27 12:57:58 +03:00
aa5a660001 nodejs: fix wopi editor size (Fix Bug 59054) 2024-03-27 12:57:52 +03:00
bf1f987333 nodejs: wopi refactoring 2024-03-27 12:56:08 +03:00
f1f834fb0c refactor: create and use new method for finding formats by extension 2024-03-26 17:57:52 +05:00
53c3e97b5c fix(nodejs): linter offence 2024-03-25 14:25:03 +05:00
eda1876f59 refactor(nodejs): rename convext variable and remove redundant internalext variable 2024-03-25 14:18:55 +05:00
64eab6c4a2 refactor(nodejs): add flag for keeping original file and replace conditional expression with it 2024-03-25 14:09:36 +05:00
acb9a0e4c9 refactor(java-spring): add formatslist dto object and replace jsonobject with it 2024-03-25 12:51:13 +05:00
909f638a92 Merge pull request #552 from ONLYOFFICE/fix/nodejs-wopi-putfile
fix(nodejs): handle document creation in putFile. Fix Bug 66817
2024-03-22 10:02:57 +03:00
6d28e3f8d8 Merge branch 'release/v8.1.0' into develop
# Conflicts:
#	CHANGELOG.md
2024-03-21 14:23:41 +03:00
12ad0d9e7e fix(nodejs): handle document creation in putFile. Fix Bug 66817 2024-03-21 17:18:58 +07:00
f3b35a878c refactor(java-spring): move formats method to indexcontroller and change return type to responseentity 2024-03-21 13:23:31 +05:00
c712f596e1 Merge remote-tracking branch 'remotes/origin/release/v8.1.0' into develop
# Conflicts:
#	CHANGELOG.md
2024-03-20 12:52:55 +03:00
7d2eb086ce Merge pull request #545 from ONLYOFFICE/feature/delete-all-files
Feature/delete all files
2024-03-20 11:01:40 +03:00
0a61708f67 Merge remote-tracking branch 'remotes/origin/develop' into feature/delete-all-files
# Conflicts:
#	CHANGELOG.md
2024-03-20 10:58:41 +03:00
389198aec6 Merge pull request #544 from ONLYOFFICE/feature/auto-conversion-error
Feature/auto conversion error
2024-03-20 10:02:53 +03:00
0d302ee8f6 nodejs: error message when error:1 2024-03-19 18:06:43 +03:00
d3a548bf3f fix(ruby): conversion error code to integer 2024-03-19 17:19:48 +07:00
fadae60e89 fix: linter offenses 2024-03-19 13:43:17 +05:00
426b15b8f1 Merge remote-tracking branch 'origin/develop' into feature/fetching-formats 2024-03-19 13:01:48 +05:00
601146c847 refactor(nodejs): change formats retrieval method on frontend 2024-03-19 12:59:54 +05:00
c4980c19e7 Revert "docxf and oform since v7.0"
This reverts commit beb9885b03.

# Conflicts:
#	web/documentserver-example/php/doceditor.php
2024-03-18 18:24:47 +03:00
0bfb036be6 refactor(csharp-mvc): change formats retrieval method on frontend 2024-03-18 18:03:10 +05:00
88b36049d2 refactor(csharp): change formats retrieval method on frontend 2024-03-18 18:02:29 +05:00
f1a1ec15ad Merge branch 'release/v8.1.0' into develop
# Conflicts:
#	CHANGELOG.md
#	web/documentserver-example/nodejs/app.js
#	web/documentserver-example/nodejs/helpers/users.js
2024-03-18 14:38:55 +03:00
683f1d33c4 nodejs: close editor 2024-03-18 14:30:25 +03:00
e8c98ba12a nodejs: format max length 2024-03-18 14:28:30 +03:00
e389cf41b8 fix(ruby): linter offence 2024-03-18 16:27:59 +05:00
80291baa40 goback: change state for users (408d80fff6) 2024-03-18 14:21:12 +03:00
b9113f93f6 fix: linter offenses 2024-03-18 16:03:00 +05:00
af778a8636 fix(ruby): linter offenses 2024-03-18 15:26:22 +05:00
47f4f022aa Merge remote-tracking branch 'remotes/origin/develop' into feature/delete-all-files
# Conflicts:
#	CHANGELOG.md
2024-03-15 16:48:58 +03:00
b2202111ac fix changelog 2024-03-15 16:47:29 +03:00
1da215b1eb Merge remote-tracking branch 'remotes/origin/develop' into feature/auto-conversion-error
# Conflicts:
#	CHANGELOG.md
2024-03-15 16:46:37 +03:00
8c8d14b48c refactor(java-spring): change formats retrieval method on frontend 2024-03-15 15:50:14 +05:00
5217a64e83 refactor(java): change formats retrieval method on frontend 2024-03-15 15:38:14 +05:00
456789191d build(nodejs): returned some dependencies versions with breaking changes 2024-03-15 17:33:00 +07:00
e1e9efa305 refactor(ruby): change formats retrieval method on frontend 2024-03-15 15:29:58 +05:00
a3016f3f96 Merge remote-tracking branch 'remotes/origin/master' into develop 2024-03-15 13:18:37 +03:00
cee60a340a nodejs: code alert 177 (e85cb5137b) 2024-03-15 12:55:59 +03:00
6c09b3f62a nodejs: wopi formsubmit icon 2024-03-15 11:18:45 +03:00
4b7ba35f83 nodejs: send email and image for protect request 2024-03-15 11:06:48 +03:00
abab30176f refactor(python): change formats retrieval method on frontend 2024-03-14 19:11:37 +05:00
1abcf78b85 refactor(php): change formats retrieval method on frontend 2024-03-14 19:08:12 +05:00
a952858ab8 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-03-14 15:07:47 +03:00
5258fd0674 feat(csharp-mvc): handling auto-conversion error(-9) 2024-03-13 15:39:42 +05:00
ca274bc465 feat(csharp): handling auto-conversion error(-9) 2024-03-13 15:39:07 +05:00
b1d66e16a5 feat(java-spring): handling auto-conversion error(-9) 2024-03-13 15:38:24 +05:00
359cda0f67 feat(java): handling auto-conversion error(-9) 2024-03-13 15:37:13 +05:00
24a3441b1e feat(ruby): handling auto-conversion error(-9) 2024-03-13 15:36:13 +05:00
a7fca1a53b feat(python): handling auto-conversion error(-9) 2024-03-13 15:35:06 +05:00
5b6a2ba318 refactor(csharp): remove console.log 2024-03-13 13:44:47 +05:00
bb4aed6efb fix(python): uncontrolled data used in path expression 2024-03-13 13:38:53 +05:00
01d8c0acde Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/ruby/Gemfile.lock
2024-03-12 11:22:07 +03:00
31cf6ca486 Merge pull request #529 from ONLYOFFICE/fix/ruby-gemfile-lock
build(ruby): updated gemfile.lock to 0 vulnerabilities
2024-03-12 11:20:10 +03:00
fbe24234d2 refactor(python): create method for deleting user folder and call it inside remove http method 2024-03-12 12:15:22 +05:00
ac894171fb changelog: delete all files 2024-03-12 11:23:53 +05:00
0f000c1457 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-03-11 13:28:12 +03:00
1699dc22b5 nodejs: fix rename var (9048082cb7) 2024-03-09 16:54:56 +03:00
cc62ff8a61 Merge pull request #531 from ONLYOFFICE/feature/php-forced-conversion
Feature/php forced conversion
2024-03-07 15:59:54 +03:00
fd21292dbd refactor(nodejs): change parameter name and remove redundant checking 2024-03-07 16:24:51 +05:00
d43294bd8a feat(csharp-mvc): implement delete all files method 2024-03-07 15:56:02 +05:00
81f5bdd528 feat(csharp): implement delete all files method 2024-03-07 15:42:23 +05:00
c1da8e14c3 feat(java-spring): implement delete all files method 2024-03-06 14:41:29 +05:00
767b5588ab feat(java): implement delete all files method 2024-03-06 14:27:21 +05:00
8858c3c256 feat(ruby): implement delete all files method 2024-03-06 14:24:52 +05:00
89f1c18d06 feat(python): implement delete all files method 2024-03-06 13:52:06 +05:00
81ad7f7a64 feat(php): implement delete all files method 2024-03-06 13:42:41 +05:00
23ba4ff5b3 Merge pull request #541 from ONLYOFFICE/feature/fix-domain
Feature/fix domain
2024-03-06 09:32:36 +03:00
423233e93f update submodule 2024-03-05 16:42:41 +03:00
5f3eaa05f9 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/php/assets/js/jscript.js
2024-03-05 16:33:14 +03:00
283d93667e ruby: change document-server to documentserver 2024-03-05 16:24:39 +03:00
158ac4161c python: change document-server to documentserver 2024-03-05 16:24:27 +03:00
bf3df5c89d php: change document-server to documentserver 2024-03-05 16:24:04 +03:00
d8251f3280 fix config paths 2024-03-05 16:16:31 +03:00
e4db31fbd5 Merge remote-tracking branch 'remotes/origin/feature/readme' into develop
# Conflicts:
#	Readme.md
2024-03-05 16:04:45 +03:00
b633f5ff19 Merge pull request #536 from Afrowave/python-example-update
CHORE: Add the Python example reference on the README.
2024-03-05 15:24:12 +03:00
0f0549c535 Merge remote-tracking branch 'origin/python-example-update' into python-example-update 2024-03-02 15:53:10 +03:00
e896f03acc CHORE: Add the Python example reference on the README. 2024-03-02 15:53:06 +03:00
a74d6b8676 CHORE: Add the Python example reference on the README. 2024-03-02 15:39:19 +03:00
672aae3791 refactor(nodejs): rename variables, ids, and classes regarding forced conversion 2024-03-01 16:29:04 +05:00
999e147539 fix(nodejs): disable file type buttons after selection 2024-03-01 15:25:14 +05:00
e57ad73d4f feat(php): allow to explicitly select output file type when getting auto-conversion error(-9) 2024-03-01 13:03:59 +05:00
690ab5471b Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-02-28 17:40:09 +03:00
2460f2c7ac nodejs: absolute host is not needed with urllib (1e72167e7d) 2024-02-28 17:22:31 +03:00
e3342a030c nodejs: fix mobile size (Fix Bug 34620) 2024-02-28 14:40:21 +03:00
e7630f516d build(ruby): updated gemfile.lock to 0 vulnerabilities 2024-02-27 16:47:26 +07:00
19a38df423 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/nodejs/app.js
2024-02-26 12:39:33 +03:00
67a21fbe35 Merge pull request #524 from ONLYOFFICE/ruby-update-gemfile-lock
build(ruby): update gemfile.lock
2024-02-26 12:13:04 +03:00
08dc8ae6a7 build(ruby): updating gemfile.lock for containers 2024-02-22 17:28:13 +07:00
dcf2fb43e0 build(nodejs): updated dependencies (found 0 vulnerabilities) 2024-02-22 15:47:38 +07:00
dca6f4173e build(ruby): update gemfile.lock 2024-02-22 15:23:07 +07:00
9f2a72aafa Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/php/templates/docEditor.tpl
2024-02-20 15:04:31 +03:00
d8cb434ad2 Merge pull request #521 from ONLYOFFICE/feat/php-make-restart
feat(php): make restart
2024-02-20 14:55:33 +03:00
96af86846b feat(php): make restart 2024-02-20 17:26:40 +07:00
fa5fb2f182 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-02-19 13:56:26 +03:00
f154ffc981 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/php/src/helpers/Users.php
2024-02-16 18:50:23 +03:00
90142299e5 Merge pull request #516 from ONLYOFFICE/feature/tabs-menu
feat(nodejs): move links to header
2024-02-15 15:12:37 +03:00
0f288d539e feat(nodejs): move links to header 2024-02-15 12:35:12 +03:00
2ead6e1f7e feat(nodejs): move links to header 2024-02-15 11:23:34 +03:00
ea9ac4bb42 Merge pull request #506 from ONLYOFFICE/feature/delete-all-files
feat(nodejs): add a button to clear all files
2024-02-14 22:27:36 +03:00
5775f44f27 Merge remote-tracking branch 'remotes/origin/develop' into feature/delete-all-files
# Conflicts:
#	CHANGELOG.md
2024-02-14 22:26:45 +03:00
4ce10d82a1 Merge pull request #513 from ONLYOFFICE/python-reference-fix
fix(python): link in reference body
2024-02-14 22:22:38 +03:00
3e9e4281c5 Merge pull request #515 from ONLYOFFICE/fix/wopi-edit
fix(nodejs): correct edited exts from discovery info
2024-02-14 22:22:10 +03:00
3eac4912e1 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-02-14 22:19:11 +03:00
e8df1c2821 fix(nodejs): correct edited exts from discovery info 2024-02-14 15:29:27 +07:00
da3224de7b Merge pull request #514 from ONLYOFFICE/fix/client-max-body-size
Fix/client max body size
2024-02-13 16:00:52 +03:00
819aa2b03f fix(python): nginx body size 2024-02-13 17:52:28 +07:00
f1aafa5fd6 fix(php): nginx body size 2024-02-13 17:44:05 +07:00
ff2bcd0ef6 feat(nodejs): add a button to clear all files 2024-02-13 11:12:36 +03:00
a17c349fb8 Merge pull request #512 from ONLYOFFICE/feature/rename-lock-file
Rename lock file
2024-02-13 09:53:36 +03:00
2268bd1cf4 nodejs: refactoring creating file 2024-02-12 13:37:26 +03:00
605c21c0be fix(python): link in reference body 2024-02-12 16:30:50 +07:00
3f0495321c Rename npm-shrinkwrap.json to package-lock.json 2024-02-09 12:35:25 +03:00
18fd30700f copyright 2024 2024-02-09 12:22:50 +03:00
9721187083 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-02-09 12:21:37 +03:00
bce5e3760a do not convert to oform 2024-02-09 12:21:24 +03:00
e4d43eda2a Revert "Remove and make"
This reverts commit ac6632d25b.
2024-02-09 08:56:51 +00:00
ac6632d25b Remove and make 2024-02-09 08:51:58 +00:00
dab4841c1d inserting svg 2024-02-01 12:35:46 +03:00
a7cf7ae378 Merge branch 'release/1.8.0' into develop
# Conflicts:
#	CHANGELOG.md
2024-01-30 18:12:51 +03:00
e85cb5137b nodejs: fix serbian lang 2024-01-23 16:22:41 +03:00
163daa37c9 Merge pull request #508 from ONLYOFFICE/fix/send-notify
fix(php): correct sendNotify agrument
2024-01-23 14:01:56 +03:00
541a1e55b4 Merge pull request #507 from ONLYOFFICE/fix/edit-converted
fix(php): correct ext substring
2024-01-23 13:39:14 +03:00
d692abda4b fix(php): correct sendNotify agrument 2024-01-19 18:08:02 +07:00
f0d7892526 fix(php): correct ext substring 2024-01-19 17:59:18 +07:00
3a2f30bfcd Merge branch 'release/v8.0.0' into develop
# Conflicts:
#	CHANGELOG.md
#	web/documentserver-example/csharp-mvc/web.appsettings.config
#	web/documentserver-example/csharp/settings.config
#	web/documentserver-example/java-spring/src/main/resources/application.properties
#	web/documentserver-example/java/src/main/resources/settings.properties
2024-01-19 12:27:44 +03:00
03cc008de8 Merge pull request #505 from ONLYOFFICE/fix/saveas-exception
fix(python): correct saveAs url  (Fix Bug 65801)
2024-01-16 12:36:00 +03:00
5e76f08c83 fix(python): correct saveAs url 2024-01-16 14:50:46 +07:00
4ca824f1d7 Merge branch 'release/v8.0.0' into develop 2024-01-15 15:07:42 +03:00
ec268cacf7 nodejs: wopi frame without sandbox attribute (Fix Bug 65575) 2024-01-09 17:22:18 +03:00
c683d17bda Merge pull request #496 from ONLYOFFICE/feature/force-converting
Force converting problem files
2024-01-09 15:41:10 +03:00
7918671725 nodejs: handling conversion -9 error 2024-01-09 11:08:15 +03:00
408d80fff6 Merge pull request #502 from ONLYOFFICE/feature/users-different-goback
Users different goback
2024-01-09 11:04:15 +03:00
1b0e8df99f Merge remote-tracking branch 'remotes/origin/develop' into feature/users-different-goback
# Conflicts:
#	CHANGELOG.md
2024-01-09 11:01:08 +03:00
50104f1122 different goback to changelog 2024-01-09 11:00:16 +03:00
b90f333fdd csharp-mvc: add goback Users.cs 2023-12-29 12:47:37 +07:00
9e2aae1658 csharp: add goback Users.cs 2023-12-29 12:23:39 +07:00
0168355600 Merge pull request #494 from ONLYOFFICE/feature/converting
Converting
2023-12-28 12:26:02 +03:00
480b8af172 converting to changelog 2023-12-28 11:58:06 +03:00
f5d767e59d nodejs: wopi layout fix 2023-12-28 11:58:06 +03:00
62ad307327 nodejs: converting dialog window 2023-12-28 11:58:05 +03:00
b3b605230f nodejs: convert button on index page 2023-12-28 11:57:14 +03:00
ae2425f7e4 Merge pull request #503 from ONLYOFFICE/feature/formats-request
Getiing formats object on node
2023-12-28 10:45:30 +03:00
5849c9bb69 nodejs: getiing formats object 2023-12-27 13:35:03 +03:00
8ba1d5e8d7 update formats (add missed records) 2023-12-26 12:32:27 +03:00
91f3bda0b4 ruby: add goback users.rb 2023-12-22 15:15:26 +03:00
185605a1eb python: add goback users.py 2023-12-22 15:15:08 +03:00
6563a26d2d php: add goback users.php 2023-12-22 15:14:49 +03:00
d9061c57a3 nodejs: add goback users.js 2023-12-22 15:09:37 +03:00
b9c2c2e770 java: add goback user.java 2023-12-22 15:08:35 +03:00
a55d7b2d9d java-spring : add goback user.java 2023-12-22 15:08:09 +03:00
e0489a6922 Merge pull request #499 from ONLYOFFICE/feature/remove-history-close-restore
Remove Close History and Restore
2023-12-19 12:30:44 +03:00
dc14a9aa90 csharp-mvc: remove historyClose and restore 2023-12-19 15:41:22 +07:00
92206ed637 csharp: remove historyClose and restore 2023-12-19 15:31:28 +07:00
09f6ba00b2 ruby: add changes after pr #501 2023-12-18 10:09:54 +03:00
43f1555c68 python: add changes after pr #501 2023-12-18 10:09:47 +03:00
83535632bb php: add changes after pr #501 2023-12-18 10:09:40 +03:00
f1d41a4bf2 java: add changes after pr #501 2023-12-18 10:09:19 +03:00
f43e7414bb java-spring: add changes after pr #501 2023-12-18 10:09:11 +03:00
4455521e00 nodejs: add changes after pr #501 2023-12-18 10:08:32 +03:00
7b91694107 Merge branch 'develop' into feature/remove-history-close-restore 2023-12-15 18:16:04 +03:00
8edb65692a Merge pull request #501 from ONLYOFFICE/feature/fix-editros-files
Remove history methods for anonymous users
2023-12-15 17:55:20 +03:00
a36f270829 Merge remote-tracking branch 'remotes/origin/develop' into feature/fix-editros-files
# Conflicts:
#	web/documentserver-example/php/templates/docEditor.tpl
2023-12-15 17:54:25 +03:00
f726ae534c Merge pull request #500 from ONLYOFFICE/feature/add-onRequestUsers-onRequestSendNotify
Add functions RequestUsers and RequestSendNotify
2023-12-15 17:50:31 +03:00
69b266489f csharp-mvc: add onRequestUsers and onRequestSendNotify in Editor.aspx 2023-12-15 20:03:15 +07:00
7c18d08bc6 csharp: add onRequestUsers and onRequestSendNotify in DocEditor.aspx 2023-12-15 19:57:55 +07:00
6717612fc1 ruby: add onRequestUsers and onRequestSendNotify in editor.html.erb 2023-12-14 12:09:32 +03:00
7f678c9ed8 ruby: remove history methods for anonymous users (fe352ebad1)
old commit:
fe352ebad1
2023-12-12 10:35:35 +03:00
ee951fbfbc python: remove history methods for anonymous users (18cf21efe4)
old commit:
18cf21efe4
2023-12-12 10:32:42 +03:00
91f32c1387 php: remove history methods for anonymous users (39820cec0a)
old commit:
39820cec0a
2023-12-12 10:30:42 +03:00
7051437928 java: remove history methods for anonymous users (52a722cf89)
old commit:
52a722cf89
2023-12-12 10:25:45 +03:00
0967c1c3ac java-spring: remove history methods for anonymous users (bc5393e28c)
old commit:
bc5393e28c
2023-12-12 10:19:25 +03:00
cf097501c6 Fix Bug 34620 - resize on mobile
This reverts commit d3a08acec3.
2023-12-11 15:33:07 +03:00
0b0e0dad8c python: add onRequestUsers and onRequestSendNotify in editor.html 2023-12-11 12:55:06 +03:00
d97291719a php: add onRequestUsers and onRequestSendNotify in docEditor.tpl 2023-12-11 12:41:40 +03:00
75ca703f8a java-spring: add onRequestUsers and onRequestSendNotify in editor.html 2023-12-11 11:59:52 +03:00
01618fee17 java: add onRequestUsers and onRequestSendNotify in editor.jsp 2023-12-11 11:54:36 +03:00
78a8b56b48 java: delete spaces from editor.jsp 2023-12-07 13:47:25 +03:00
3b9bad4a26 Merge branch 'develop' into feature/remove-history-close-restore 2023-12-07 11:34:27 +03:00
435b8013f6 style: updates to styling 2023-12-07 10:58:41 +03:00
a9063af6e1 fix sr-Latn-RS 2023-12-06 12:56:12 +03:00
bde236075c ruby: remove historyClose and restore 2023-12-05 16:08:45 +03:00
f74f34504f python: remove historyClose and restore 2023-12-05 16:08:29 +03:00
3243a04a1b php: remove historyClose and restore 2023-12-05 15:25:20 +03:00
6598aa585a java: remove historyClose and restore 2023-12-05 15:25:05 +03:00
e02744e56b nodejs: remove historyClose and restore 2023-12-05 14:59:14 +03:00
ec596753c6 java-spring: remove historyClose and restore 2023-12-05 14:58:24 +03:00
159 changed files with 5955 additions and 3692 deletions

View File

@ -1,7 +1,13 @@
# Change Log
- fill permission in embedded mode
- delete all files
- handling conversion -9 error
- nodejs: wopi formsubmit icon
- nodejs: tabs menu
- change insert image
- different goback for users
- nodejs: converting function on index page
- nodejs: close editor
## 1.8.0
@ -9,7 +15,7 @@
- nodejs: filling pdf
- version number to page meta
- ar skin languages
- sr-Latn-CS skin languages
- sr-Latn-RS skin languages
- getting history via api
- using a repo with a list of formats
- convert after uploading only tagged formats

View File

@ -1,11 +1,11 @@
## Integration examples
Test examples are simple document management systems that can be built into your application for testing.
These test examples are simple document management systems that can be built into your application for testing.
Do NOT use these integration examples on your own server without proper code modifications!
In case you enabled any of the test examples, disable it before going for production.
These examples show the way to integrate [ONLYOFFICE Docs][2] into your own website or application using one of the programming languages.
The package contains examples written in .Net (C# MVC), .Net (C#), Java, Node.js, PHP and Ruby.
The package contains examples written in .Net (C# MVC), .Net (C#), Java, Java Spring, Node.js, PHP, Python and Ruby.
You should change `http://documentserver` to your server address in these files:
* [.Net (C# MVC)](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/csharp-mvc) - `web/documentserver-example/csharp-mvc/web.appsettings.config`
@ -13,9 +13,9 @@ You should change `http://documentserver` to your server address in these files:
* [Java](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/java) - `web/documentserver-example/java/src/main/resources/settings.properties`
* [Java Spring](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/java-spring) - `web/documentserver-example/java-spring/src/main/resources/application.properties`
* [Node.js](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/nodejs) - `web/documentserver-example/nodejs/config/default.json`
* [PHP](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/php) - `web/documentserver-example/php/config.json`
* [Python](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/python) - `web/documentserver-example/python/config.py`
* [Ruby](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/ruby) - `web/documentserver-example/ruby/config/application.rb`
* [PHP](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/php) - `web/documentserver-example/php/src/configuration/ConfigurationManager.php`
* [Python](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/python) - `web/documentserver-example/python/src/configuration/configuration.py`
* [Ruby](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/ruby) - `web/documentserver-example/ruby/app/configuration/configuration.rb`
More information on how to use these examples can be found here: [http://api.onlyoffice.com/editors/demopreview](http://api.onlyoffice.com/editors/demopreview "http://api.onlyoffice.com/editors/demopreview")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -502,6 +502,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -592,6 +619,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -741,6 +791,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -229,6 +229,10 @@ namespace OnlineEditorsExampleMVC.Helpers
switch (errorCode)
{
case -9:
// public const int c_nErrorConversionOutputFormatError = -9;
errorMessage = String.Format(errorMessageTemplate, "Error conversion output format");
break;
case -8:
// public const int c_nErrorFileVKey = -8;
errorMessage = String.Format(errorMessageTemplate, "Error document VKey");

View File

@ -59,7 +59,9 @@ namespace OnlineEditorsExampleMVC.Helpers
"Cant print the file",
"Can create new files from the editor",
"Can see the information about Group2 users",
"Cant submit forms"
"Cant submit forms",
"Can't close history",
"Can't restore the file version"
};
static List<string> descr_user_0 = new List<string>()
@ -92,7 +94,8 @@ namespace OnlineEditorsExampleMVC.Helpers
new List<string>(),
descr_user_1,
true,
true
true,
new Goback(null, false)
),
new User(
"uid-2",
@ -111,7 +114,8 @@ namespace OnlineEditorsExampleMVC.Helpers
new List<string>(),
descr_user_2,
false,
true
true,
new Goback("Go to Documents", null)
),
new User(
"uid-3",
@ -130,7 +134,8 @@ namespace OnlineEditorsExampleMVC.Helpers
new List<string>() { "copy", "download", "print" },
descr_user_3,
false,
false
false,
null
),
new User(
"uid-0",
@ -144,7 +149,8 @@ namespace OnlineEditorsExampleMVC.Helpers
new List<string>() { "protect" },
descr_user_0,
false,
false
false,
null
)
};
@ -235,7 +241,9 @@ namespace OnlineEditorsExampleMVC.Helpers
public List<string> userInfoGroups;
public bool avatar;
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar)
public Goback goback;
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar, Goback goback)
{
this.id = id;
this.name = name;
@ -249,6 +257,21 @@ namespace OnlineEditorsExampleMVC.Helpers
this.templates = templates;
this.userInfoGroups = userInfoGroups;
this.avatar = avatar;
this.goback = goback;
}
}
public class Goback
{
public string text;
public bool? blank;
public Goback(){}
public Goback(string text, bool? blank)
{
this.text = text;
this.blank = blank;
}
}
}

View File

@ -214,10 +214,12 @@ namespace OnlineEditorsExampleMVC.Models
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
{
"goback", new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
"goback", user.goback != null ? new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
{
{ "url", DocManagerHelper.GetServerUrl(false) } // the absolute URL to the website address which will be opened when clicking the Open file location menu button
}
{ "url", DocManagerHelper.GetServerUrl(false) }, // the absolute URL to the website address which will be opened when clicking the Open file location menu button
{ "text", user.goback.text },
{ "blank", user.goback.blank }
} : new Dictionary<string, object>{}
}
}
}
@ -289,20 +291,20 @@ namespace OnlineEditorsExampleMVC.Models
{
Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "Content\\images\\logo.png"
+ "Content\\images\\logo.svg"
};
var directMailMergeUrl = new UriBuilder(DocManagerHelper.GetServerUrl(false))
{
Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "Content\\images\\logo.png"
+ "Content\\images\\logo.svg"
};
// create a logo config
var logoConfig = new Dictionary<string, object>
{
{ "fileType", "png"},
{ "fileType", "svg"},
{ "url", mailMergeUrl.ToString()}
};

View File

@ -145,7 +145,6 @@
<Content Include="Content\images\icon_xlsx.svg" />
<Content Include="Content\images\info.svg" />
<Content Include="Content\images\loader16.gif" />
<Content Include="Content\images\logo.png" />
<Content Include="Content\images\logo.svg" />
<Content Include="Content\images\mobile-fill-forms.svg" />
<Content Include="Content\images\mobile.svg" />

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch("webeditor.ashx?type=formats")
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.Name,
format.Type,
format.Actions,
format.Convert,
format.Mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery != "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery != "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (ConverExtList.indexOf(posExt) == -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -116,7 +137,7 @@ if (typeof jQuery != "undefined") {
contentType: "text/xml",
type: "post",
dataType: "json",
data: JSON.stringify({ filename: fileName, filePass: filePass }),
data: JSON.stringify({ filename: fileName, filePass: filePass, fileExt: fileType }),
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -132,6 +153,12 @@ if (typeof jQuery != "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")) {
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder", filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -143,7 +170,7 @@ if (typeof jQuery != "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -178,10 +205,10 @@ if (typeof jQuery != "undefined") {
jq("#beginView, #beginEmbedded").removeClass("disable");
var fileName = jq("#hiddenFileName").val();
var posExt = fileName.lastIndexOf('.');
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1 || FillExtList.indexOf(posExt) != -1) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -213,6 +240,15 @@ if (typeof jQuery != "undefined") {
});
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var filePass = jq("#filePass").val();
if (filePass) {
@ -294,6 +330,23 @@ if (typeof jQuery != "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
var requestAddress = "webeditor.ashx"
+ "?type=remove";
jq.ajax({
async: true,
contentType: "text/xml",
url: requestAddress,
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

@ -259,6 +259,48 @@
}
}
<% string usersForMentions; %>
<% Model.GetUsersMentions(Request, out usersForMentions); %>
<% string usersInfo; %>
<% Model.GetUsersInfo(Request, out usersInfo); %>
<% string usersForProtect; %>
<% Model.GetUsersProtect(Request, out usersForProtect); %>
var onRequestUsers = function (event) {
if (event && event.data){
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = <%= usersInfo %>;
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = <%= usersForProtect %>;
break;
default:
users = <%= usersForMentions %>;
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
var onRequestSendNotify = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config = <%= Model.GetDocConfig(Request, Url) %>;
config.width = "100%";
@ -276,63 +318,27 @@
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet,
};
<% string usersForMentions; %>
<% Model.GetUsersMentions(Request, out usersForMentions); %>
<% string usersInfo; %>
<% Model.GetUsersInfo(Request, out usersInfo); %>
<% string usersForProtect; %>
<% Model.GetUsersProtect(Request, out usersForProtect); %>
if (config.editorConfig.user.id) {
// the user is trying to show the document version history
config.events['onRequestHistory'] = onRequestHistory;
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = onRequestHistoryData;
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose'] = function () {
document.location.reload();
};
config.events['onRequestRestore'] = onRequestRestore;
if (config.editorConfig.user.id !== "uid-3") {
config.events['onRequestHistoryClose'] = function () {
document.location.reload();
};
config.events['onRequestRestore'] = onRequestRestore;
}
// add mentions for not anonymous users
<% if (!string.IsNullOrEmpty(usersForMentions))
{ %>
config.events['onRequestUsers'] = function (event) {
if (event && event.data){
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = <%= usersInfo %>;
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = <%= usersForProtect %>;
break;
default:
users = <%= usersForMentions %>;
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
config.events['onRequestUsers'] = onRequestUsers;
<% } %>
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config.events['onRequestSendNotify'] = onRequestSendNotify;
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
config.events['onRequestReferenceData'] = onRequestReferenceData;
@ -346,12 +352,6 @@
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -151,7 +151,14 @@
if (storedFiles.Any())
{ %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -295,6 +302,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -357,9 +373,6 @@
<%: Scripts.Render("~/bundles/jquery", "~/bundles/scripts") %>
<script language="javascript" type="text/javascript">
var FillExtList = '<%= string.Join(",", DocManagerHelper.FillFormExts.ToArray()) %>';
var ConverExtList = '<%= string.Join(",", DocManagerHelper.ConvertExts.ToArray()) %>';
var EditedExtList = '<%= string.Join(",", DocManagerHelper.EditedExts.ToArray()) %>';
var UrlConverter = '<%= Url.Content("~/webeditor.ashx?type=convert") %>';
var UrlEditor = '<%= Url.Action("editor", "Home") %>';
</script>

View File

@ -87,6 +87,9 @@ namespace OnlineEditorsExampleMVC
case "reference":
Reference(context);
break;
case "formats":
Formats(context);
break;
}
}
@ -240,7 +243,13 @@ namespace OnlineEditorsExampleMVC
var fileUri = DocManagerHelper.GetDownloadUrl(fileName);
var extension = (Path.GetExtension(fileName).ToLower() ?? "").Trim('.');
var internalExtension = "ooxml";
string conversionExtension = "ooxml";
object fileExt;
if (body.TryGetValue("fileExt", out fileExt) && !String.IsNullOrEmpty(fileExt.ToString()))
{
conversionExtension = fileExt.ToString();
}
// check if the file with such an extension can be converted
if (DocManagerHelper.ConvertExts.Contains("." + extension))
@ -258,7 +267,7 @@ namespace OnlineEditorsExampleMVC
// get the url and file type of the converted file
Dictionary<string, string> newFileData;
var result = ServiceConverter.GetConvertedData(downloadUri.ToString(), extension, internalExtension, key, true, out newFileData, filePass, lang);
var result = ServiceConverter.GetConvertedData(downloadUri.ToString(), extension, conversionExtension, key, true, out newFileData, filePass, lang);
if (result != 100)
{
context.Response.Write("{ \"step\" : \"" + result + "\", \"filename\" : \"" + fileName + "\"}");
@ -393,8 +402,17 @@ namespace OnlineEditorsExampleMVC
context.Response.ContentType = "text/plain";
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
Remove(fileName); // remove a file and its history if it exists
string fileName = context.Request["fileName"];
if (!String.IsNullOrEmpty(fileName))
{
fileName = Path.GetFileName(context.Request["fileName"]);
Remove(fileName); // remove a file and its history if it exists
}
else
{
RemoveUserDirectory(); // remove the user's directory
}
context.Response.Write("{ \"success\": true }");
}
@ -414,6 +432,14 @@ namespace OnlineEditorsExampleMVC
if (Directory.Exists(histDir)) Directory.Delete(histDir, true);
}
// remove the user's directory
private static void RemoveUserDirectory()
{
var path = DocManagerHelper.StoragePath("", null); // get the path to the user directory
if (Directory.Exists(path)) Directory.Delete(path, true);
}
// get files information
private static void Files(HttpContext context)
{
@ -951,6 +977,25 @@ namespace OnlineEditorsExampleMVC
return history;
}
// return all the supported formats
private static void Formats(HttpContext context)
{
try
{
Dictionary<string, object> data = new Dictionary<string, object>
{
{ "formats", FormatManager.All() }
};
context.Response.ContentType = "application/json";
var jss = new JavaScriptSerializer();
context.Response.Write(jss.Serialize(data));
}
catch (Exception e)
{
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
}
}

View File

@ -15,7 +15,7 @@
<add key="files.docservice.verify-peer-off" value="true"/>
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-RS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -502,6 +502,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -596,6 +623,29 @@ footer a:hover {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -745,6 +795,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -153,7 +153,14 @@
if (storedFiles.Any())
{ %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr >
@ -297,6 +304,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -364,12 +380,8 @@
<script language="javascript" type="text/javascript" src="script/jquery.iframe-transport.js"></script>
<script language="javascript" type="text/javascript" src="script/jquery.fileupload.js"></script>
<script language="javascript" type="text/javascript" src="script/jquery.dropdownToggle.js"></script>
<script language="javascript" type="text/javascript" src="script/formats.js"></script>
<script language="javascript" type="text/javascript" src="script/jscript.js"></script>
<script language="javascript" type="text/javascript">
var FillFormExtList = '<%= string.Join(",", FillFormsExts.ToArray()) %>';
var ConverExtList = '<%= string.Join(",", ConvertExts.ToArray()) %>';
var EditedExtList = '<%= string.Join(",", EditedExts.ToArray()) %>';
</script>
</body>
</html>

View File

@ -437,7 +437,14 @@ namespace OnlineEditorsExample
var lang = context.Request.Cookies.GetOrDefault("ulang", null);
var extension = (Path.GetExtension(_fileName).ToLower() ?? "").Trim('.');
var internalExtension = "ooxml";
string conversionExtension = "ooxml"; // set the default conversion extension as ooxml
object fileExt;
// change the conversion extension if it was provided in the request body
if (body.TryGetValue("fileExt", out fileExt) && !String.IsNullOrEmpty(fileExt.ToString()))
{
conversionExtension = fileExt.ToString();
}
// check if the file with such an extension can be converted
if (ConvertExts.Contains("." + extension))
@ -454,7 +461,7 @@ namespace OnlineEditorsExample
// get the url and file type of the converted file
Dictionary<string, string> newFileData;
var result = ServiceConverter.GetConvertedData(fileUrl.ToString() , extension, internalExtension, key, true, out newFileData, filePass, lang);
var result = ServiceConverter.GetConvertedData(fileUrl.ToString() , extension, conversionExtension, key, true, out newFileData, filePass, lang);
if (result != 100)
{
return "{ \"step\" : \"" + result + "\", \"filename\" : \"" + _fileName + "\"}";

View File

@ -233,6 +233,41 @@
}
};
var onRequestUsers = function (event) {
if (event && event.data){
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = <%= UsersInfo %>;
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = <%= UsersForProtect %>;
break;
default:
users = <%= UsersForMentions %>;
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
var onRequestSendNotify = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config = <%= DocConfig %>;
config.width = "100%";
@ -275,65 +310,36 @@
docEditor.setHistoryData(JSON.parse(xhr.responseText)); // send the link to the document for viewing the version history
}
};
config.events['onRequestHistoryClose'] = function () { // the user is trying to go back to the document from viewing the document version history
document.location.reload();
};
config.events['onRequestRestore'] = function (event) {
var fileName = "<%= FileName %>";
var version = event.data.version;
var data = {
fileName: fileName,
version: version
if (config.editorConfig.user.id !== "uid-3") {
config.events['onRequestHistoryClose'] = function () { // the user is trying to go back to the document from viewing the document version history
document.location.reload();
};
config.events['onRequestRestore'] = function (event) {
var fileName = "<%= FileName %>";
var version = event.data.version;
var data = {
fileName: fileName,
version: version
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=restore&directUrl=" + !!config.document.directUrl);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
docEditor.refreshHistory(JSON.parse(xhr.responseText));
}
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=restore&directUrl=" + !!config.document.directUrl);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
docEditor.refreshHistory(JSON.parse(xhr.responseText));
}
};
}
// add mentions for not anonymous users
<% if (!string.IsNullOrEmpty(UsersForMentions))
{ %>
config.events['onRequestUsers'] = function (event) {
if (event && event.data){
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = <%= UsersInfo %>;
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = <%= UsersForProtect %>;
break;
default:
users = <%= UsersForMentions %>;
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
config.events['onRequestUsers'] = onRequestUsers;
<% } %>
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config.events['onRequestSendNotify'] = onRequestSendNotify;
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
config.events['onRequestReferenceData'] = onRequestReferenceData;
@ -347,12 +353,6 @@
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -282,10 +282,12 @@ namespace OnlineEditorsExample
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
{
"goback", new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
"goback", user.goback != null ? new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
{
{ "url", _Default.GetServerUrl(false) + "default.aspx" } // the absolute URL to the website address which will be opened when clicking the Open file location menu button
}
{ "url", _Default.GetServerUrl(false) + "default.aspx" }, // the absolute URL to the website address which will be opened when clicking the Open file location menu button
{ "text", user.goback.text },
{ "blank", user.goback.blank }
} : new Dictionary<string, object>{}
}
}
}
@ -338,17 +340,17 @@ namespace OnlineEditorsExample
var InsertImageUrl = new UriBuilder(_Default.GetServerUrl(true));
InsertImageUrl.Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "App_Themes\\images\\logo.png";
+ "App_Themes\\images\\logo.svg";
var DirectImageUrl = new UriBuilder(_Default.GetServerUrl(false));
DirectImageUrl.Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "App_Themes\\images\\logo.png";
+ "App_Themes\\images\\logo.svg";
// create a logo config
Dictionary<string, object> logoConfig = new Dictionary<string, object>
{
{ "fileType", "png"},
{ "fileType", "svg"},
{ "url", InsertImageUrl.ToString()}
};

View File

@ -231,6 +231,10 @@ namespace ASC.Api.DocumentConverter
switch (errorCode)
{
case -9:
// public const int c_nErrorConversionOutputFormatError = -9;
errorMessage = String.Format(errorMessageTemplate, "Error conversion output format");
break;
case -8:
// public const int c_nErrorFileVKey = -8;
errorMessage = String.Format(errorMessageTemplate, "Error document VKey");

View File

@ -145,7 +145,6 @@
</ItemGroup>
<ItemGroup>
<Content Include="App_Themes\images\loader16.gif" />
<Content Include="App_Themes\images\logo.png" />
<Content Include="App_Themes\jquery-ui.css" />
<Content Include="App_Themes\stylesheet.css" />
<Content Include="DocEditor.aspx" />

View File

@ -58,7 +58,9 @@ namespace OnlineEditorsExample
"Cant print the file",
"Can create new files from the editor",
"Can see the information about Group2 users",
"Cant submit forms"
"Cant submit forms",
"Can't close history",
"Can't restore the file version"
};
static List<string> descr_user_0 = new List<string>()
@ -91,7 +93,8 @@ namespace OnlineEditorsExample
new List<string>(),
descr_user_1,
true,
true
true,
new Goback(null, false)
),
new User(
"uid-2",
@ -110,7 +113,8 @@ namespace OnlineEditorsExample
new List<string>(),
descr_user_2,
false,
true
true,
new Goback("Go to Documents",null)
),
new User(
"uid-3",
@ -129,7 +133,8 @@ namespace OnlineEditorsExample
new List<string>() { "copy", "download", "print" },
descr_user_3,
false,
false
false,
null
),
new User(
"uid-0",
@ -143,7 +148,8 @@ namespace OnlineEditorsExample
new List<string>() { "protect" },
descr_user_0,
false,
false
false,
null
)
};
@ -235,8 +241,9 @@ namespace OnlineEditorsExample
public bool templates;
public List<string> userInfoGroups;
public bool avatar;
public Goback goback;
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar)
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar, Goback goback)
{
this.id = id;
this.name = name;
@ -250,6 +257,21 @@ namespace OnlineEditorsExample
this.templates = templates;
this.userInfoGroups = userInfoGroups;
this.avatar = avatar;
this.goback = goback;
}
}
public class Goback
{
public string text;
public bool? blank;
public Goback(){}
public Goback(string text, bool? blank)
{
this.text = text;
this.blank = blank;
}
}
}

View File

@ -87,6 +87,9 @@ namespace OnlineEditorsExample
case "reference":
Reference(context);
break;
case "formats":
Formats(context);
break;
}
}
@ -222,12 +225,22 @@ namespace OnlineEditorsExample
context.Response.ContentType = "text/plain";
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var path = _Default.StoragePath(fileName, HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)));
var histDir = _Default.HistoryDir(path);
string fileName = context.Request["fileName"];
string userAddress = HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress));
if (File.Exists(path)) File.Delete(path); // delete file
if (Directory.Exists(histDir)) Directory.Delete(histDir, true); // delete file history
if (!String.IsNullOrEmpty(fileName))
{
fileName = Path.GetFileName(fileName);
var path = _Default.StoragePath(fileName, userAddress);
var histDir = _Default.HistoryDir(path);
if (File.Exists(path)) File.Delete(path); // delete file
if (Directory.Exists(histDir)) Directory.Delete(histDir, true); // delete file history
} else
{
string userDir = _Default.StoragePath("", userAddress);
if (Directory.Exists(userDir)) Directory.Delete(userDir, true); // delete the user's directory
}
context.Response.Write("{ \"success\": true }");
}
@ -778,5 +791,25 @@ namespace OnlineEditorsExample
+ userAddress;
return fileUrl.ToString();
}
// return all the supported formats
private static void Formats(HttpContext context)
{
try
{
Dictionary<string, object> data = new Dictionary<string, object>
{
{ "formats", FormatManager.All() }
};
context.Response.ContentType = "application/json";
var jss = new JavaScriptSerializer();
context.Response.Write(jss.Serialize(data));
}
catch (Exception e)
{
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
}
}

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch("webeditor.ashx?type=formats")
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.Name,
format.Type,
format.Actions,
format.Convert,
format.Mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery != "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery != "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (ConverExtList.indexOf(posExt) == -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -116,7 +137,7 @@ if (typeof jQuery != "undefined") {
contentType: "text/xml",
type: "post",
dataType: "json",
data: JSON.stringify({ filename: fileName, filePass: filePass }),
data: JSON.stringify({ filename: fileName, filePass: filePass, fileExt: fileType }),
url: requestAddress,
complete: function (data) {
var responseText = data.responseText;
@ -132,6 +153,12 @@ if (typeof jQuery != "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")) {
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder", filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -143,7 +170,7 @@ if (typeof jQuery != "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -178,10 +205,10 @@ if (typeof jQuery != "undefined") {
jq("#beginView, #beginEmbedded").removeClass("disable");
var fileName = jq("#hiddenFileName").val();
var posExt = fileName.lastIndexOf('.');
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1 || FillFormExtList.indexOf(posExt) != -1) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -213,6 +240,15 @@ if (typeof jQuery != "undefined") {
});
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var filePass = jq("#filePass").val();
if (filePass) {
@ -293,6 +329,24 @@ if (typeof jQuery != "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
var requestAddress = "webeditor.ashx"
+ "?type=remove";
jq.ajax({
async: true,
contentType: "text/xml",
url: requestAddress,
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

@ -14,7 +14,7 @@
<add key="files.docservice.token.useforrequest" value="true" />
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-RS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>

View File

@ -19,6 +19,7 @@
package com.onlyoffice.integration;
import com.onlyoffice.integration.documentserver.serializers.FilterState;
import com.onlyoffice.integration.entities.Goback;
import com.onlyoffice.integration.services.UserServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -92,30 +93,32 @@ public class ExampleData {
"Can create a file from an editor",
"Can see the information about Group2 users",
"Can view chat",
"Cant submit forms"
"Cant submit forms",
"Can't close history",
"Can't restore the file version"
);
// create user 1 with the specified parameters
userService.createUser("John Smith", "smith@example.com", descriptionUserFirst,
"", 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()), null, true, true, true);
List.of(FilterState.NULL.toString()), null, true, true, true, new Goback(null, false));
// 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);
true, true, new Goback("Go to Documents", null));
// 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"), false, true, true, false);
new ArrayList<>(), List.of("group-2"), false, true, true, false, null);
// create user 0 with the specified parameters
userService.createUser("Anonymous", null, descriptionUserZero, "",
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
new ArrayList<>(), null, false, false, false);
new ArrayList<>(), null, false, false, false, null);
}
}

View File

@ -212,11 +212,11 @@ public class EditorController {
@SneakyThrows
private String getInsertImage(final Boolean directUrl) { // get an image that will be inserted into the document
Map<String, Object> dataInsertImage = new HashMap<>();
dataInsertImage.put("fileType", "png");
dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.png");
dataInsertImage.put("fileType", "svg");
dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.svg");
if (directUrl) {
dataInsertImage.put("directUrl", storagePathBuilder
.getServerUrl(false) + "/css/img/logo.png");
.getServerUrl(false) + "/css/img/logo.svg");
}
// check if the document token is enabled

View File

@ -248,15 +248,15 @@ public class FileController {
// get document type (word, cell or slide)
DocumentType type = fileUtility.getDocumentType(fileName);
// convert to .ooxml
String internalFileExt = "ooxml";
// get an auto-conversion extension from the request body or set it to the ooxml extension
String conversionExtension = body.getFileExt() != null ? body.getFileExt() : "ooxml";
try {
// check if the file with such an extension can be converted
if (fileUtility.getConvertExts().contains(fileExt)) {
String key = serviceConverter.generateRevisionId(fileUri); // generate document key
ConvertedData response = serviceConverter // get the URL to the converted file
.getConvertedData(fileUri, fileExt, internalFileExt, key, filePass, true, lang);
.getConvertedData(fileUri, fileExt, conversionExtension, key, filePass, true, lang);
String newFileUri = response.getUri();
String newFileType = "." + response.getFileType();
@ -291,24 +291,33 @@ public class FileController {
return createUserMetadata(uid, fileName);
} catch (Exception e) {
e.printStackTrace();
// if the operation of file converting is unsuccessful, an error occurs
return "{ \"error\": \"" + e.getMessage() + "\"}";
}
// if the operation of file converting is unsuccessful, an error occurs
return "{ \"error\": \"" + "The file can't be converted.\"}";
}
@PostMapping("/delete")
@ResponseBody
public String delete(@RequestBody final Converter body) { // delete a file
try {
String fullFileName = fileUtility.getFileName(body.getFileName()); // get full file name
String filename = body.getFileName();
boolean success = false;
// delete a file from the storage and return the status of this operation (true or false)
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
if (filename != null) {
String fullFileName = fileUtility.getFileName(filename); // get full file name
// delete file history and return the status of this operation (true or false)
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
// delete a file from the storage and return the status of this operation (true or false)
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
return "{ \"success\": \"" + (fileSuccess && historySuccess) + "\"}";
// delete file history and return the status of this operation (true or false)
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
success = fileSuccess && historySuccess;
} else {
// delete the user's folder and return the boolean status
success = storageMutator.deleteUserFolder();
}
return "{ \"success\": \"" + (success) + "\"}";
} catch (Exception e) {
// if the operation of file deleting is unsuccessful, an error occurs
return "{ \"error\": \"" + e.getMessage() + "\"}";

View File

@ -22,8 +22,10 @@ import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.Misc;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.FormatService;
import com.onlyoffice.integration.entities.User;
import com.onlyoffice.integration.services.UserServices;
import com.onlyoffice.integration.dto.FormatsList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
@ -33,6 +35,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.http.ResponseEntity;
import java.util.ArrayList;
import java.util.Arrays;
@ -61,6 +64,9 @@ public class IndexController {
@Autowired
private UserServices userService;
@Autowired
private FormatService formatService;
@Value("${files.docservice.url.site}")
private String docserviceSite;
@ -136,16 +142,16 @@ public class IndexController {
@ResponseBody
public HashMap<String, String> configParameters() { // get configuration parameters
HashMap<String, String> configuration = new HashMap<>();
configuration.put("FillExtList", String.join(",", fileUtility
.getFillExts())); // put a list of the extensions that can be filled to config
configuration.put("ConverExtList", String.join(",", fileUtility
.getConvertExts())); // put a list of the extensions that can be converted to config
configuration.put("EditedExtList", String.join(",", fileUtility
.getEditedExts())); // put a list of the extensions that can be edited to config
configuration.put("UrlConverter", urlConverter);
configuration.put("UrlEditor", urlEditor);
return configuration;
}
@GetMapping("/formats")
@ResponseBody
public ResponseEntity<FormatsList> formats() { // return all the supported formats
FormatsList list = new FormatsList(formatService.getFormats());
return ResponseEntity.ok(list);
}
}

View File

@ -20,6 +20,7 @@ package com.onlyoffice.integration.documentserver.models.configurations;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
@ -38,9 +39,18 @@ public class Goback { // the settings for the Open file location menu button an
private String indexMapping;
@Getter
@Setter
private String url; /* the absolute URL to the website address which will be opened
when clicking the Open file location menu button */
@Getter
@Setter
private String text;
@Getter
@Setter
private Boolean blank;
@PostConstruct
private void init() {
this.url = storagePathBuilder.getServerUrl(false) + indexMapping;

View File

@ -27,7 +27,8 @@ public enum ConvertErrorType {
UNEXPECTED_GUID_ERROR(-5, "Error unexpected guid"),
DATABASE_ERROR(-6, "Error database"),
DOCUMENT_REQUEST_ERROR(-7, "Error document request"),
DOCUMENT_VKEY_ERROR(-8, "Error document VKey");
DOCUMENT_VKEY_ERROR(-8, "Error document VKey"),
DOCUMENT_CONVERSION_OUTPUT_ERROR(-9, "Error conversion output format");
private final int code;
private final String label;

View File

@ -31,6 +31,7 @@ public interface FileStorageMutator {
boolean createFile(Path path, InputStream stream); // create a new file if it does not exist
boolean deleteFile(String fileName); // delete a file
boolean deleteFileHistory(String fileName); // delete file history
boolean deleteUserFolder(); // delete the user's folder recursively
String updateFile(String fileName, byte[] bytes); // update a file
boolean writeToFile(String pathName, String payload); // write the payload to the file
boolean moveFile(Path source, Path destination); // move a file to the specified destination

View File

@ -202,6 +202,11 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return historyDeleted || historyWithoutExtDeleted;
}
// delete the user's folder recursively
public boolean deleteUserFolder() {
return FileSystemUtils.deleteRecursively(new File(getStorageLocation()));
}
// update a file
public String updateFile(final String fileName, final byte[] bytes) {
Path path = fileUtility

View File

@ -31,6 +31,8 @@ public class Converter {
private String fileName;
@JsonProperty("filePass")
private String filePass;
@JsonProperty("fileExt")
private String fileExt;
@JsonProperty("lang")
private String lang;
}

View File

@ -0,0 +1,32 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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 com.onlyoffice.integration.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import com.onlyoffice.integration.documentserver.models.Format;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
public class FormatsList {
private List<Format> formats;
}

View File

@ -0,0 +1,38 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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 com.onlyoffice.integration.entities;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "`goback`")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Goback extends AbstractEntity {
private String text;
private Boolean blank;
}

View File

@ -47,4 +47,5 @@ public class User extends AbstractEntity {
private List<String> descriptions;
private Boolean avatar;
private String image;
private Goback goback;
}

View File

@ -18,6 +18,7 @@
package com.onlyoffice.integration.services;
import com.onlyoffice.integration.entities.Goback;
import com.onlyoffice.integration.entities.Group;
import com.onlyoffice.integration.entities.Permission;
import com.onlyoffice.integration.entities.User;
@ -59,7 +60,8 @@ public class UserServices {
final List<String> userInfoGroups, final Boolean favoriteDoc,
final Boolean chat,
final Boolean protect,
final Boolean avatar) {
final Boolean avatar,
final Goback goback) {
User newUser = new User();
newUser.setName(name); // set the user name
newUser.setEmail(email); // set the user email
@ -88,6 +90,8 @@ public class UserServices {
protect); // specify permissions for the current user
newUser.setPermissions(permission);
newUser.setGoback(goback);
userRepository.save(newUser); // save a new user
return newUser;

View File

@ -34,5 +34,11 @@ public class DefaultCustomizationConfigurer implements CustomizationConfigurer<D
public void configure(final Customization customization, final DefaultCustomizationWrapper wrapper) {
Action action = wrapper.getAction(); // get the action parameter from the customization wrapper
User user = wrapper.getUser();
if (user != null && user.getGoback() != null) {
customization.getGoback().setText(user.getGoback().getText());
customization.getGoback().setBlank(user.getGoback().getBlank());
} else {
customization.getGoback().setUrl("");
}
}
}

View File

@ -25,7 +25,7 @@ files.docservice.token-use-for-request=true
files.docservice.verify-peer-off=true
files.docservice.languages=en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
files.docservice.languages=en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-RS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
spring.datasource.url=jdbc:h2:mem:usersdb
spring.datasource.driverClassName=org.h2.Driver

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -489,6 +489,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -595,6 +622,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -752,6 +802,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -16,18 +16,12 @@
*
*/
var ConverExtList;
var EditedExtList;
var UrlConverter;
var UrlEditor;
var FillExtList;
if (typeof jQuery !== "undefined") {
jQuery.post('/config',
function(data) {
FillExtList = data.FillExtList.split(',');
ConverExtList = data.ConverExtList.split(',');
EditedExtList = data.EditedExtList.split(',');
UrlConverter = data.UrlConverter;
UrlEditor = data.UrlEditor;
});

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch('/formats')
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.name,
format.type,
format.actions,
format.convert,
format.mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery !== "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery !== "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer !== null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (ConverExtList.includes(posExt) === -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -115,7 +136,7 @@ if (typeof jQuery !== "undefined") {
contentType: "application/json",
type: "post",
dataType: "json",
data: JSON.stringify({filename: fileName, filePass: filePass}),
data: JSON.stringify({filename: fileName, filePass: filePass, fileExt: fileType}),
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -131,6 +152,12 @@ if (typeof jQuery !== "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")){
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder",filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -142,7 +169,7 @@ if (typeof jQuery !== "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -180,7 +207,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (EditedExtList.includes(posExt) !== -1 || FillExtList.includes(posExt) !== -1) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -218,6 +245,15 @@ if (typeof jQuery !== "undefined") {
}
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var pass = jq("#filePass").val();
if (pass) {
@ -299,6 +335,24 @@ if (typeof jQuery !== "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
jq.ajax({
async: true,
contentType: "application/json",
type: "post",
dataType: "json",
data: JSON.stringify({filename: null, filePass: null}),
url: "/delete",
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

@ -262,7 +262,44 @@
innerAlert(response.error);
}
}
}
};
var onRequestUsers = function (event) {
if (event && event.data) {
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = [[${usersInfo}]];
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = [[${usersForProtect}]];
break;
default:
users = [[${usersForMentions}]];
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
var onRequestSendNotify = function(event) { // the user is mentioned in a comment
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config.width = "100%";
config.height = "100%";
@ -275,59 +312,26 @@
"onMetaChange": onMetaChange,
"onRequestInsertImage": onRequestInsertImage,
"onRequestSelectDocument": onRequestSelectDocument,
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet,
"onRequestRestore": onRequestRestore,
"onRequestHistory": onRequestHistory,
"onRequestHistoryData": onRequestHistoryData,
"onRequestHistoryClose": onRequestHistoryClose
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet
};
var usersForMentions = [[${usersForMentions}]];
var usersInfo = [[${usersInfo}]];
var usersForProtect = [[${usersForProtect}]];
if (config.editorConfig.user.id != 4) {
// add mentions for not anonymous users
config.events['onRequestUsers'] = function (event) {
if (event && event.data){
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = usersInfo;
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = usersForProtect;
break;
default:
users = usersForMentions;
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
config.events['onRequestUsers'] = onRequestUsers;
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config.events['onRequestSendNotify'] = onRequestSendNotify;
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
config.events['onRequestReferenceData'] = onRequestReferenceData;
// prevent switch the document from the viewing into the editing mode for anonymous users
config.events['onRequestEditRights'] = onRequestEditRights;
config.events['onRequestOpen'] = onRequestOpen;
config.events['onRequestHistory'] = onRequestHistory;
config.events['onRequestHistoryData'] = onRequestHistoryData;
if (config.editorConfig.user.id != 3) {
config.events['onRequestHistoryClose'] = onRequestHistoryClose;
config.events['onRequestRestore'] = onRequestRestore;
}
}
if (config.editorConfig.createUrl) {
@ -335,12 +339,6 @@
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -123,7 +123,14 @@
</div>
<th:block th:if="${not #lists.isEmpty(files)}">
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -275,6 +282,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -341,6 +357,7 @@
<script type="text/javascript" src="scripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="scripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="scripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="scripts/formats.js"></script>
<script type="text/javascript" src="scripts/jscript.js"></script>
<script type="text/javascript" src="scripts/converter.js"></script>
<script type="text/javascript">

View File

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

View File

@ -29,6 +29,7 @@ import helpers.FileUtility;
import helpers.ServiceConverter;
import helpers.TrackManager;
import helpers.Users;
import format.FormatManager;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
@ -139,6 +140,9 @@ public class IndexServlet extends HttpServlet {
case "historydata":
historyData(request, response, writer);
break;
case "formats":
formats(request, response, writer);
break;
default:
break;
}
@ -283,7 +287,8 @@ public class IndexServlet extends HttpServlet {
String fileUri = DocumentManager.getDownloadUrl(fileName, true);
String fileExt = FileUtility.getFileExtension(fileName);
FileType fileType = FileUtility.getFileType(fileName);
String internalFileExt = "ooxml";
// get an auto-conversion extension from the request body or set it to the ooxml extension
String conversionExtension = body.get("fileExt") != null ? (String) body.get("fileExt") : "ooxml";
// check if the file with such an extension can be converted
if (DocumentManager.getConvertExts().contains(fileExt)) {
@ -292,7 +297,7 @@ public class IndexServlet extends HttpServlet {
// get the url and file type to the converted file
Map<String, String> newFileData = ServiceConverter
.getConvertedData(fileUri, fileExt, internalFileExt, key, filePass, true, lang);
.getConvertedData(fileUri, fileExt, conversionExtension, key, filePass, true, lang);
String newFileUri = newFileData.get("fileUrl");
String newFileType = "." + newFileData.get("fileType");
@ -416,17 +421,23 @@ public class IndexServlet extends HttpServlet {
final HttpServletResponse response,
final PrintWriter writer) {
try {
String fileName = FileUtility.getFileName(request.getParameter("filename"));
String path = DocumentManager.storagePath(fileName, null);
String fileName = request.getParameter("filename");
if (fileName != null && !fileName.isEmpty()) {
fileName = FileUtility.getFileName(fileName);
String path = DocumentManager.storagePath(fileName, null);
// delete file
File f = new File(path);
delete(f);
// delete file history
File hist = new File(DocumentManager.historyDir(path));
delete(hist);
// delete file
File f = new File(path);
delete(f);
// delete file history
File hist = new File(DocumentManager.historyDir(path));
delete(hist);
} else {
// delete the user's folder and all the containing files
File userFolder = new File(DocumentManager.storagePath(null, null));
delete(userFolder);
}
writer.write("{ \"success\": true }");
} catch (Exception e) {
writer.write("{ \"error\": \"" + e.getMessage() + "\"}");
@ -1039,6 +1050,16 @@ public class IndexServlet extends HttpServlet {
writer.write("{}");
}
private static void formats(final HttpServletRequest request,
final HttpServletResponse response,
final PrintWriter writer) {
Map<String, Object> data = new HashMap<String, Object>();
data.put("formats", (new FormatManager()).getFormats());
response.setContentType("application/json");
Gson gson = new Gson();
writer.write(gson.toJson(data));
}
// process get request
@Override
protected void doGet(final HttpServletRequest request,

View File

@ -114,9 +114,15 @@ public class FileModel {
editorConfig.getUser().setImage(user.getAvatar() ? DocumentManager.getServerUrl(false)
+ "/css/img/" + user.getId() + ".png" : null);
// write the absolute URL to the file location
editorConfig.getCustomization().getGoback()
if (user.getGoback() != null) {
// write the absolute URL to the file location
editorConfig.getCustomization().getGoback()
.setUrl(DocumentManager.getServerUrl(false) + "/IndexServlet");
editorConfig.getCustomization().getGoback()
.setText(user.getGoback().getText());
editorConfig.getCustomization().getGoback()
.setBlank(user.getGoback().getBlank());
}
changeType(mode, type, user, fileName);
}
@ -601,6 +607,8 @@ public class FileModel {
public class Goback {
private String url;
private String text;
private Boolean blank;
public String getUrl() {
return url;
@ -609,6 +617,22 @@ public class FileModel {
public void setUrl(final String urlParam) {
this.url = urlParam;
}
public String getText() {
return text;
}
public void setText(final String textParam) {
this.text = textParam;
}
public Boolean getBlank() {
return blank;
}
public void setBlank(final Boolean blankParam) {
this.blank = blankParam;
}
}
}

View File

@ -0,0 +1,39 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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 entities;
public class Goback {
private String text;
private Boolean blank;
public Goback() { }
public Goback(final String textParam, final Boolean blankParam) {
this.text = textParam;
this.blank = blankParam;
}
public String getText() {
return text;
}
public Boolean getBlank() {
return blank;
}
}

View File

@ -33,12 +33,13 @@ public class User {
private final Boolean templates;
private final List<String> userInfoGroups;
private final Boolean avatar;
private final Goback goback;
public User(final String idParam, final String nameParam, final String emailParam, final String groupParam,
final List<String> reviewGroupsParam, final CommentGroups commentGroupsParam,
final List<String> userInfoGroupsParam, final Boolean favoriteParam,
final List<String> deniedPermissionsParam, final List<String> descriptionsParam,
final Boolean templatesParam, final Boolean avatarParam) {
final Boolean templatesParam, final Boolean avatarParam, final Goback gobackParam) {
this.id = idParam;
this.name = nameParam;
this.email = emailParam;
@ -51,6 +52,7 @@ public class User {
this.templates = templatesParam;
this.userInfoGroups = userInfoGroupsParam;
this.avatar = avatarParam;
this.goback = gobackParam;
}
public String getId() {
@ -100,4 +102,8 @@ public class User {
public Boolean getAvatar() {
return avatar;
}
public Goback getGoback() {
return goback;
}
}

View File

@ -19,6 +19,7 @@
package helpers;
import entities.CommentGroups;
import entities.Goback;
import entities.User;
import java.util.ArrayList;
@ -64,6 +65,8 @@ public final class Users {
add("Can create new files from the editor");
add("Can see the information about Group2 users");
add("Cant submit forms");
add("Can't close history");
add("Can't restore the file version");
}};
private static List<String> descriptionUserZero = new ArrayList<String>() {{
@ -85,19 +88,20 @@ public final class Users {
private static List<User> users = new ArrayList<User>() {{
add(new User("uid-1", "John Smith", "smith@example.com",
"", null, new CommentGroups(), null,
null, new ArrayList<String>(), descriptionUserFirst, true, true));
null, new ArrayList<String>(), descriptionUserFirst, true, true, new Goback(null, false)));
add(new User("uid-2", "Mark Pottato", "pottato@example.com",
"group-2", Arrays.asList("group-2", ""), new CommentGroups(null,
Arrays.asList("group-2", ""), Arrays.asList("group-2")), Arrays.asList("group-2", ""),
true, new ArrayList<String>(), descriptionUserSecond, false, true));
true, new ArrayList<String>(), descriptionUserSecond, false, true,
new Goback("Go to Documents", null)));
add(new User("uid-3", "Hamish Mitchell", null,
"group-3", Arrays.asList("group-2"), new CommentGroups(Arrays.asList("group-3", "group-2"),
Arrays.asList("group-2"), null), Arrays.asList("group-2"),
false, Arrays.asList("copy", "download", "print"),
descriptionUserThird, false, false));
descriptionUserThird, false, false, null));
add(new User("uid-0", null, null,
"", null, null, null,
null, Arrays.asList("protect"), descriptionUserZero, false, false));
null, Arrays.asList("protect"), descriptionUserZero, false, false, null));
}};
private Users() { }

View File

@ -27,7 +27,8 @@ public enum ConvertErrorType {
UNEXPECTED_GUID_ERROR(-5, "Error unexpected guid"),
DATABASE_ERROR(-6, "Error database"),
DOCUMENT_REQUEST_ERROR(-7, "Error document request"),
DOCUMENT_VKEY_ERROR(-8, "Error document VKey");
DOCUMENT_VKEY_ERROR(-8, "Error document VKey"),
CONVERSION_OUTPUT_FORMAT_ERROR(-9, "Error conversion output format");
private final int code;
private final String label;

View File

@ -13,7 +13,7 @@ files.docservice.url.api=web-apps/apps/api/documents/api.js
files.docservice.url.preloader=web-apps/apps/api/documents/cache-scripts.html
files.docservice.url.example=
files.docservice.languages=en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
files.docservice.languages=en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-RS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
files.docservice.secret=
files.docservice.header=Authorization

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -488,6 +488,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -595,6 +622,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -748,6 +798,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -262,6 +262,43 @@
document.location.reload();
};
var onRequestUsers = function (event) {
if (event && event.data) {
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = <%=(String) request.getAttribute("usersInfo")%>;
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = <%=(String) request.getAttribute("usersForProtect")%>;
break;
default:
users = <%=(String) request.getAttribute("usersForMentions")%>;
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
var onRequestSendNotify = function(event) { // the user is mentioned in a comment
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config = JSON.parse('<%= FileModel.serialize(Model) %>');
config.width = "100%";
config.height = "100%";
@ -274,61 +311,26 @@
"onMetaChange": onMetaChange,
"onRequestInsertImage": onRequestInsertImage,
"onRequestSelectDocument": onRequestSelectDocument,
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet,
"onRequestRestore": onRequestRestore,
"onRequestHistory": onRequestHistory,
"onRequestHistoryData": onRequestHistoryData,
"onRequestHistoryClose": onRequestHistoryClose
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet
};
<%
String usersForMentions = (String) request.getAttribute("usersForMentions");
String usersInfo = (String) request.getAttribute("usersInfo");
String usersForProtect = (String) request.getAttribute("usersForProtect");
%>
if (config.editorConfig.user.id) {
// add mentions for not anonymous users
config.events['onRequestUsers'] = function (event) {
if (event && event.data){
var c = event.data.c;
}
switch (c) {
case "info":
users = [];
var allUsers = <%=usersInfo%>;
for (var i = 0; i < event.data.id.length; i++) {
for (var j = 0; j < allUsers.length; j++) {
if (allUsers[j].id == event.data.id[i]) {
users.push(allUsers[j]);
break;
}
}
}
break;
case "protect":
var users = <%=usersForProtect%>;
break;
default:
users = <%=usersForMentions%>;
}
docEditor.setUsers({
"c": c,
"users": users,
});
};
config.events['onRequestUsers'] = onRequestUsers;
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
config.events['onRequestSendNotify'] = onRequestSendNotify;
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
config.events['onRequestReferenceData'] = onRequestReferenceData;
// prevent switch the document from the viewing into the editing mode for anonymous users
config.events['onRequestEditRights'] = onRequestEditRights;
config.events['onRequestOpen'] = onRequestOpen;
config.events['onRequestHistory'] = onRequestHistory;
config.events['onRequestHistoryData'] = onRequestHistoryData;
if (config.editorConfig.user.id != "uid-3") {
config.events['onRequestHistoryClose'] = onRequestHistoryClose;
config.events['onRequestRestore'] = onRequestRestore;
}
}
if (config.editorConfig.createUrl) {
@ -336,12 +338,6 @@
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -146,7 +146,14 @@
</div>
<% if (files.length > 0) { %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -299,6 +306,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -365,12 +381,10 @@
<script type="text/javascript" src="scripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="scripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="scripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="scripts/formats.js"></script>
<script type="text/javascript" src="scripts/jscript.js"></script>
<script language="javascript" type="text/javascript">
var FillExtList = "<%= String.join(",", DocumentManager.getFillExts()) %>".split(",");
var ConverExtList = "<%= String.join(",", DocumentManager.getConvertExts()) %>".split(",");
var EditedExtList = "<%= String.join(",", DocumentManager.getEditedExts()) %>".split(",");
var UrlConverter = "IndexServlet?type=convert";
var UrlEditor = "EditorServlet";

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch('IndexServlet?type=formats')
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.name,
format.type,
format.actions,
format.convert,
format.mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery !== "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery !== "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer !== null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (!ConverExtList.includes(posExt)) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -115,7 +136,7 @@ if (typeof jQuery !== "undefined") {
contentType: "text/xml",
type: "post",
dataType: "json",
data: JSON.stringify({filename: fileName, filePass: filePass}),
data: JSON.stringify({filename: fileName, filePass: filePass, fileExt: fileType}),
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -131,6 +152,12 @@ if (typeof jQuery !== "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")){
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder",filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -142,7 +169,7 @@ if (typeof jQuery !== "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -180,7 +207,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (EditedExtList.includes(posExt) || FillExtList.includes(posExt)) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -212,6 +239,15 @@ if (typeof jQuery !== "undefined") {
});
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var pass = jq("#filePass").val();
if (pass) {
@ -290,6 +326,21 @@ if (typeof jQuery !== "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
jq.ajax({
async: true,
contentType: "text/xml",
url: "IndexServlet?type=remove",
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

@ -93,8 +93,6 @@ app.get('/', (req, res) => { // define a handler for default page
res.render('index', { // render index template with the parameters specified
preloaderUrl: siteUrl + configServer.get('preloaderUrl'),
convertExts: fileUtility.getConvertExtensions(),
editedExts: fileUtility.getEditExtensions(),
fillExts: fileUtility.getFillExtensions(),
storedFiles: req.DocManager.getStoredFiles(),
params: req.DocManager.getCustomParams(),
@ -333,6 +331,8 @@ app.post('/convert', (req, res) => { // define a handler for converting files
const fileUri = req.DocManager.getDownloadUrl(fileName, true);
const fileExt = fileUtility.getFileExtension(fileName, true);
const internalFileExt = 'ooxml';
const convExt = req.body.fileExt ? req.body.fileExt : internalFileExt;
const { keepOriginal } = req.body;
const response = res;
const writeResult = function writeResult(filename, step, error) {
@ -380,38 +380,50 @@ app.post('/convert', (req, res) => { // define a handler for converting files
if (status !== 200) throw new Error(`Conversion service returned status: ${status}`);
// write a file with a new extension, but with the content from the origin file
fileSystem.writeFileSync(req.DocManager.storagePath(correctName), data);
fileSystem.unlinkSync(req.DocManager.storagePath(fileName)); // remove file with the origin extension
if (fileUtility.getFileType(correctName) !== null) {
fileSystem.writeFileSync(req.DocManager.storagePath(correctName), data);
} else {
writeResult(newFileUri, result, 'FileTypeIsNotSupported');
return;
}
// remove file with the origin extension
if (!keepOriginal) fileSystem.unlinkSync(req.DocManager.storagePath(fileName));
const userAddress = req.DocManager.curUserHostAddress();
const historyPath = req.DocManager.historyPath(fileName, userAddress, true);
// get the history path to the file with a new extension
const correctHistoryPath = req.DocManager.historyPath(correctName, userAddress, true);
fileSystem.renameSync(historyPath, correctHistoryPath); // change the previous history path
if (!keepOriginal) {
fileSystem.renameSync(historyPath, correctHistoryPath); // change the previous history path
fileSystem.renameSync(
path.join(correctHistoryPath, `${fileName}.txt`),
path.join(correctHistoryPath, `${correctName}.txt`),
); // change the name of the .txt file with document information
fileSystem.renameSync(
path.join(correctHistoryPath, `${fileName}.txt`),
path.join(correctHistoryPath, `${correctName}.txt`),
); // change the name of the .txt file with document information
} else if (newFileType !== null) {
const user = users.getUser(req.query.userid);
req.DocManager.saveFileData(correctName, user.id, user.name);
}
writeResult(correctName, result, null); // write a file with a new name to the result object
} catch (e) {
console.log(e); // display error message in the console
if (!e.message.includes('-9')) console.log(e); // display error message in the console
writeResult(null, null, e.message);
}
};
try {
// check if the file with such an extension can be converted
if (fileUtility.getConvertExtensions().indexOf(fileExt) !== -1) {
if ((fileUtility.getConvertExtensions().indexOf(fileExt) !== -1) || ('fileExt' in req.body)) {
const storagePath = req.DocManager.storagePath(fileName);
const stat = fileSystem.statSync(storagePath);
let key = fileUri + stat.mtime.getTime();
key = documentService.generateRevisionId(key); // get document key
// get the url to the converted file
documentService.getConvertedUri(fileUri, fileExt, internalFileExt, key, true, callback, filePass, lang);
documentService.getConvertedUri(fileUri, fileExt, convExt, key, true, callback, filePass, lang);
} else {
// if the file with such an extension can't be converted, write the origin file to the result object
writeResult(fileName, null, null);
@ -643,7 +655,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
const zip = await urllib.request(downloadZip, { method: 'GET' });
const statusZip = zip.status;
const dataZip = zip.data;
if (status === 200) {
if (statusZip === 200) {
fileSystem.writeFileSync(pathChanges, dataZip); // write the document version differences to the archive
} else {
emitWarning(`Document editing service returned status: ${statusZip}`);
@ -674,7 +686,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
}
} catch (ex) {
console.log(ex);
response.write('{"error":1}');
response.write(`{"error":1,"message":${JSON.stringify(ex)}}`);
response.end();
return;
}
@ -686,7 +698,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
// file saving process
const processSave = async function processSave(downloadUri, body, fileName, userAddress) {
if (!downloadUri) {
response.write('{"error":1}');
response.write('{"error":1,"message":"save uri is empty"}');
response.end();
return;
}
@ -797,7 +809,8 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
}
}
} catch (ex) {
response.write('{"error":1}');
console.log(ex);
response.write(`{"error":1,"message":${JSON.stringify(ex)}}`);
response.end();
return;
}
@ -809,7 +822,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
// file force saving process
const processForceSave = async function processForceSave(downloadUri, body, fileName, userAddress) {
if (!downloadUri) {
response.write('{"error":1}');
response.write('{"error":1,"message":"forcesave uri is empty"}');
response.end();
return;
}
@ -901,7 +914,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
}
}
if (!body) {
res.write('{"error":1}');
res.write('{"error":1,"message":"body is empty"}');
res.end();
return;
}
@ -920,15 +933,27 @@ app.get('/editor', (req, res) => { // define a handler for editing document
try {
req.DocManager = new DocManager(req, res);
const fileName = fileUtility.getFileName(req.query.fileName);
let { fileExt } = req.query;
const lang = req.DocManager.getLang();
const user = users.getUser(req.query.userid);
const userDirectUrl = req.query.directUrl === 'true';
const userid = user.id;
const { name } = user;
if (fileExt) {
fileExt = fileUtility.getFileExtension(fileUtility.getFileName(fileExt), true);
// create demo document of a given extension
const fName = req.DocManager.createDemo(!!req.query.sample, fileExt, userid, name, false);
// get the redirect path
const redirectPath = `${req.DocManager.getServerUrl()}/editor?fileName=`
+ `${encodeURIComponent(fName)}${req.DocManager.getCustomParams()}`;
res.redirect(redirectPath);
return;
}
const fileName = fileUtility.getFileName(req.query.fileName);
const lang = req.DocManager.getLang();
const userDirectUrl = req.query.directUrl === 'true';
let actionData = 'null';
if (req.query.action) {
try {
@ -970,25 +995,21 @@ app.get('/editor', (req, res) => { // define a handler for editing document
const { userInfoGroups } = user;
const usersInfo = [];
const usersForProtect = [];
if (user.id !== 'uid-0') {
users.getAllUsers().forEach((userInfo) => {
const u = userInfo;
u.image = userInfo.avatar ? `${req.DocManager.getServerUrl()}/images/${userInfo.id}.png` : null;
usersInfo.push(u);
}, usersInfo);
users.getUsersForProtect(user.id).forEach((userInfo) => {
const u = userInfo;
u.image = userInfo.avatar ? `${req.DocManager.getServerUrl()}/images/${userInfo.id}.png` : null;
usersForProtect.push(u);
}, usersForProtect);
}
if (fileExt) {
fileExt = fileUtility.getFileExtension(fileUtility.getFileName(fileExt), true);
// create demo document of a given extension
const fName = req.DocManager.createDemo(!!req.query.sample, fileExt, userid, name, false);
// get the redirect path
const redirectPath = `${req.DocManager.getServerUrl()}/editor?fileName=`
+ `${encodeURIComponent(fName)}${req.DocManager.getCustomParams()}`;
res.redirect(redirectPath);
return;
}
fileExt = fileUtility.getFileExtension(fileName);
const userAddress = req.DocManager.curUserHostAddress();
@ -1016,6 +1037,10 @@ app.get('/editor', (req, res) => { // define a handler for editing document
submitForm = userid === 'uid-1';
}
if (user.goback != null) {
user.goback.url = `${req.DocManager.getServerUrl()}`;
}
// file config data
const argss = {
apiUrl: siteUrl + configServer.get('apiUrl'),
@ -1049,7 +1074,6 @@ app.get('/editor', (req, res) => { // define a handler for editing document
print: !user.deniedPermissions.includes('print'),
mode: mode !== 'view' ? 'edit' : 'view',
canBackToFolder: type !== 'embedded',
backUrl: `${req.DocManager.getServerUrl()}/`,
curUserHostAddress: req.DocManager.curUserHostAddress(),
lang,
userid: userid !== 'uid-0' ? userid : null,
@ -1067,12 +1091,13 @@ app.get('/editor', (req, res) => { // define a handler for editing document
? JSON.stringify({ fileName, userAddress: req.DocManager.curUserHostAddress() }) : null,
instanceId: userid !== 'uid-0' ? req.DocManager.getInstanceId() : null,
protect: !user.deniedPermissions.includes('protect'),
goback: user.goback != null ? user.goback : '',
close: user.close,
},
dataInsertImage: {
fileType: 'png',
url: `${req.DocManager.getServerUrl(true)}/images/logo.png`,
directUrl: !userDirectUrl ? null : `${req.DocManager.getServerUrl()}/images/logo.png`,
fileType: 'svg',
url: `${req.DocManager.getServerUrl(true)}/images/logo.svg`,
directUrl: !userDirectUrl ? null : `${req.DocManager.getServerUrl()}/images/logo.svg`,
},
dataDocument: {
fileType: 'docx',
@ -1087,7 +1112,7 @@ app.get('/editor', (req, res) => { // define a handler for editing document
directUrl: !userDirectUrl ? null : `${req.DocManager.getServerUrl()}/csv`,
},
usersForMentions: user.id !== 'uid-0' ? users.getUsersForMentions(user.id) : null,
usersForProtect: user.id !== 'uid-0' ? users.getUsersForProtect(user.id) : null,
usersForProtect,
usersInfo,
};
@ -1171,6 +1196,19 @@ app.post('/historyObj', (req, res) => {
res.end();
});
app.get('/formats', (req, res) => {
try {
const formats = fileUtility.getFormats();
res.json({
formats,
});
} catch (ex) {
console.log(ex); // display error message in the console
res.status(500); // write status parameter to the response
res.render('error', { message: 'Server error' }); // render error template with the message parameter specified
}
});
wopiApp.registerRoutes(app);
// "Not found" error with 404 status

View File

@ -70,7 +70,7 @@
"pt-PT": "Portuguese (Portugal)",
"ro": "Romanian",
"ru": "Russian",
"sr-Latn-CS": "Serbian",
"sr-Latn-RS": "Serbian",
"si": "Sinhala (Sri Lanka)",
"sk": "Slovak",
"sl": "Slovenian",

View File

@ -51,7 +51,7 @@ DocManager.prototype.createDirectory = function createDirectory(directory) {
// get the language from the request
DocManager.prototype.getLang = function getLang() {
if (/^[a-z]{2}(-[A-z]{4})?(-[A-Z]{2})?$/.test(this.req.query.lang)) {
if (/^[a-z]{2}(-[a-zA-z]{4})?(-[A-Z]{2})?$/.test(this.req.query.lang)) {
return this.req.query.lang;
} // the default language value is English
return 'en';

View File

@ -20,6 +20,10 @@ const supportedFormats = require('../public/assets/document-formats/onlyoffice-d
const fileUtility = {};
fileUtility.getFormats = function getFormats() {
return supportedFormats;
};
// get file name from the given url
fileUtility.getFileName = function getFileName(url, withoutExtension) {
if (!url) return '';
@ -54,10 +58,10 @@ fileUtility.getFileType = function getFileType(url) {
const ext = fileUtility.getFileExtension(url, true); // get the file extension from the given url
for (let i = 0; i < supportedFormats.length; i++) {
if (supportedFormats[i].name === ext) return supportedFormats[i].type;
if (supportedFormats[i].name === ext && supportedFormats[i].type !== '') return supportedFormats[i].type;
}
return fileUtility.fileType.word; // the default file type is word
return null; // the default file type is null
};
fileUtility.fileType = {

View File

@ -30,6 +30,7 @@ class User {
descriptions,
templates,
avatar,
goback,
close,
) {
this.id = id;
@ -44,6 +45,7 @@ class User {
this.descriptions = descriptions;
this.templates = templates;
this.avatar = avatar;
this.goback = goback;
this.close = close;
}
}
@ -82,6 +84,8 @@ const descrUser3 = [
'Can create new files from the editor',
'Can see the information about Group2 users',
'Cant submit forms',
'Cant close history',
'Cant restore the file version',
];
const descrUser0 = [
@ -114,6 +118,7 @@ const users = [
descrUser1,
true,
true,
{ blank: false },
{ visible: false },
),
new User(
@ -133,6 +138,7 @@ const users = [
descrUser2,
false,
true,
{ text: 'Go to Documents' },
{},
),
new User(
@ -152,9 +158,10 @@ const users = [
descrUser3,
false,
false,
null,
{},
),
new User('uid-0', null, null, null, null, {}, [], null, ['protect'], descrUser0, false, false, null),
new User('uid-0', null, null, null, null, {}, [], null, ['protect'], descrUser0, false, false, null, null),
];
// get a list of all the users
@ -192,10 +199,7 @@ users.getUsersForProtect = function getUsersForProtect(id) {
const result = [];
this.forEach((user) => {
if (user.id !== id && user.name != null) {
result.push({
id: user.id,
name: user.name,
});
result.push(user);
}
});
return result;

View File

@ -187,13 +187,12 @@ const putFile = function putFile(wopi, req, res, userHost) {
const userAddress = req.DocManager.curUserHostAddress(userHost);
const storagePath = req.DocManager.storagePath(wopi.id, userAddress);
const fileSize = fileSystem.statSync(storagePath).size;
if (!lockManager.hasLock(storagePath)) {
// ToDo: if body length is 0 bytes => handle document creation
if (!lockManager.hasLock(storagePath) && fileSize !== 0) {
// file isn't locked => mismatch
returnLockMismatch(res, '', 'File isn\'t locked');
} else if (lockManager.getLock(storagePath) === requestLock) {
} else if (lockManager.getLock(storagePath) === requestLock || fileSize === 0) {
// lock matches current lock => put file
saveFileFromBody(req, wopi.id, userAddress, true, (err, version) => {
if (!err) {

View File

@ -27,57 +27,72 @@ const siteUrl = configServer.get('siteUrl'); // the path to the editors installa
let cache = null;
const requestDiscovery = async function requestDiscovery(url) {
const requestDiscovery = async function requestDiscovery(DocManager) {
let absSiteUrl = siteUrl;
if (absSiteUrl.indexOf('/') === 0) {
absSiteUrl = DocManager.getServerHost() + siteUrl;
}
// eslint-disable-next-line no-unused-vars
return new Promise((resolve, reject) => {
const uri = absSiteUrl + configServer.get('wopi.discovery');
const actions = [];
urllib.request(urlModule.parse(url + configServer.get('wopi.discovery')), { method: 'GET' }, (err, data) => {
if (data) {
// create the discovery XML file with the parameters from the response
const xmlParseOptions = {
attributeNamePrefix: '',
ignoreAttributes: false,
parseAttributeValue: true,
attrValueProcessor: (val) => he.decode(val, { isAttributeValue: true }),
};
const parser = new xmlParser.XMLParser(xmlParseOptions);
// create the discovery XML file with the parameters from the response
const discovery = parser.parse(data.toString());
if (discovery['wopi-discovery']) {
discovery['wopi-discovery']['net-zone'].app.forEach((app) => {
let appAction = app.action;
if (!Array.isArray(appAction)) {
appAction = [appAction];
}
appAction.forEach((action) => {
actions.push({ // write all the parameters to the actions element
app: app.name,
favIconUrl: app.favIconUrl,
checkLicense: app.checkLicense === 'true',
name: action.name,
ext: action.ext || '',
progid: action.progid || '',
isDefault: !!action.default,
urlsrc: action.urlsrc,
requires: action.requires || '',
// parse url to allow request by relative url after
// https://github.com/node-modules/urllib/pull/321/commits/514de1924bf17a38a6c2db2a22a6bc3494c0a959
urllib.request(
urlModule.parse(uri),
{
method: 'GET',
},
(err, data) => {
if (data) {
// create the discovery XML file with the parameters from the response
const xmlParseOptions = {
attributeNamePrefix: '',
ignoreAttributes: false,
parseAttributeValue: true,
attrValueProcessor: (val) => he.decode(val, { isAttributeValue: true }),
};
const parser = new xmlParser.XMLParser(xmlParseOptions);
// create the discovery XML file with the parameters from the response
const discovery = parser.parse(data.toString());
if (discovery['wopi-discovery']) {
discovery['wopi-discovery']['net-zone'].app.forEach((app) => {
let appAction = app.action;
if (!Array.isArray(appAction)) {
appAction = [appAction];
}
appAction.forEach((action) => {
actions.push({ // write all the parameters to the actions element
app: app.name,
favIconUrl: app.favIconUrl,
checkLicense: app.checkLicense === 'true',
name: action.name,
ext: action.ext || '',
progid: action.progid || '',
isDefault: !!action.default,
urlsrc: action.urlsrc,
requires: action.requires || '',
});
});
});
});
}
}
}
resolve(actions);
});
resolve(actions);
},
);
});
};
// get the wopi discovery information
const getDiscoveryInfo = async function getDiscoveryInfo(url) {
const getDiscoveryInfo = async function getDiscoveryInfo(DocManager) {
let actions = [];
if (cache) return cache;
try {
actions = await requestDiscovery(url);
actions = await requestDiscovery(DocManager);
} catch (e) {
return actions;
}
@ -91,19 +106,9 @@ const getDiscoveryInfo = async function getDiscoveryInfo(url) {
return actions;
};
const initWopi = async function initWopi(DocManager) {
let absSiteUrl = siteUrl;
if (absSiteUrl.indexOf('/') === 0) {
absSiteUrl = DocManager.getServerHost() + siteUrl;
}
// get the wopi discovery information
await getDiscoveryInfo(absSiteUrl);
};
// get actions of the specified extension
const getActions = async function getActions(ext) {
const actions = await getDiscoveryInfo(); // get the wopi discovery information
const getActions = async function getActions(DocManager, ext) {
const actions = await getDiscoveryInfo(DocManager); // get the wopi discovery information
const filtered = [];
actions.forEach((action) => { // and filter it by the specified extention
@ -116,8 +121,8 @@ const getActions = async function getActions(ext) {
};
// get an action for the specified extension and name
const getAction = async function getAction(ext, name) {
const actions = await getDiscoveryInfo();
const getAction = async function getAction(DocManager, ext, name) {
const actions = await getDiscoveryInfo(DocManager);
let act = null;
actions.forEach((action) => {
@ -130,8 +135,8 @@ const getAction = async function getAction(ext, name) {
};
// get the default action for the specified extension
const getDefaultAction = async function getDefaultAction(ext) {
const actions = await getDiscoveryInfo();
const getDefaultAction = async function getDefaultAction(DocManager, ext) {
const actions = await getDiscoveryInfo(DocManager);
let act = null;
actions.forEach((action) => {
@ -149,7 +154,6 @@ const getActionUrl = function getActionUrl(host, userAddress, action, filename)
return `${action.urlsrc.replace(/<.*&>/g, '')}WOPISrc=${encodeURIComponent(WOPISrc)}`;
};
exports.initWopi = initWopi;
exports.getDiscoveryInfo = getDiscoveryInfo;
exports.getAction = getAction;
exports.getActions = getActions;

View File

@ -45,15 +45,13 @@ exports.registerRoutes = function registerRoutes(app) {
app.get('/wopi', async (req, res) => {
req.DocManager = new DocManager(req, res);
await utils.initWopi(req.DocManager);
// get the wopi discovery information
const actions = await utils.getDiscoveryInfo();
const actions = await utils.getDiscoveryInfo(req.DocManager);
const wopiEnable = actions.length !== 0;
const docsExtEdit = []; // Supported extensions for WOPI
actions.forEach((el) => {
if (el.name === 'edit') docsExtEdit.push(`.${el.ext}`);
if (el.name === 'edit') docsExtEdit.push(`${el.ext}`);
});
// Checking supported extensions
@ -67,11 +65,13 @@ exports.registerRoutes = function registerRoutes(app) {
// run through all the files and write the corresponding information to each file
// eslint-disable-next-line no-restricted-syntax
for (const file of files) {
const mobile = new RegExp(configServer.get('mobileRegEx'), 'i').test(req.get('User-Agent'));
const ext = fileUtility.getFileExtension(file.name, true); // get an extension of each file
// eslint-disable-next-line no-await-in-loop
file.actions = await utils.getActions(ext); // get actions of the specified extension
file.actions = await utils.getActions(req.DocManager, ext); // get actions of the specified extension
// eslint-disable-next-line no-await-in-loop
file.defaultAction = await utils.getDefaultAction(ext);// get the default action of the specified extension
file.defaultAction = await utils.getDefaultAction(req.DocManager, ext);// get the default action for extension
if (mobile) file.actions.forEach((act) => { if (act.name === 'mobileEdit') file.defaultAction = act; });
}
// render wopiIndex template with the parameters specified
@ -111,14 +111,12 @@ exports.registerRoutes = function registerRoutes(app) {
try {
req.DocManager = new DocManager(req, res);
await utils.initWopi(req.DocManager);
let fileName = req.DocManager.getCorrectName(req.params.id);
const fileExt = fileUtility.getFileExtension(fileName, true); // get the file extension from the request
const user = users.getUser(req.query.userid); // get a user by the id
// get an action for the specified extension and name
const action = await utils.getAction(fileExt, req.query.action);
const action = await utils.getAction(req.DocManager, fileExt, req.query.action);
if (action && req.query.action === 'editnew') {
fileName = req.DocManager.requestEditnew(req, fileName, user);

View File

@ -17,17 +17,17 @@
"url": "https://github.com/ONLYOFFICE/document-server-integration/issues"
},
"dependencies": {
"body-parser": "^1.19.0",
"config": "^3.3.2",
"debug": "^4.2.0",
"ejs": "^3.1.5",
"express": "^4.17.1",
"fast-xml-parser": "^4.3.1",
"body-parser": "^1.20.2",
"config": "^3.3.11",
"debug": "^4.3.4",
"ejs": "^3.1.9",
"express": "^4.18.2",
"fast-xml-parser": "^4.3.4",
"formidable": "^1.2.2",
"he": "^1.2.0",
"jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.2",
"jwa": "^2.0.0",
"log4js": "^6.3.0",
"log4js": "^6.9.1",
"mime": "^2.4.6",
"serve-favicon": "^2.5.0",
"urllib": "^2.36.1"
@ -44,8 +44,16 @@
]
},
"devDependencies": {
"eslint": "^8.28.0",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.26.0"
"eslint-plugin-import": "^2.29.1"
},
"overrides": {
"semver": "7.5.2",
"word-wrap": "1.2.4",
"pac-resolver": "7.0.0",
"degenerator": "3.0.1",
"qs": "6.7.3",
"json5": "2.2.3"
}
}

View File

@ -0,0 +1,4 @@
<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="M14.4285 13C14.4102 13 14 13 14 13.5V15H6C5.44772 15 5 15.4477 5 16V17C5 17.5523 5.44771 18 6 18H14V19.5C14 20 14.3816 20 14.4285 20C14.6359 20 15.0099 19.9113 15.2172 19.7363L18.6207 17.0833C19.1264 16.6566 19.1264 16.3434 18.6207 15.9167L15.2172 13.2637C15.0099 13.0887 14.6359 13 14.4285 13Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.5715 4C9.58984 4 10 4 10 4.50002V6H18C18.5523 6 19 6.44772 19 7V8C19 8.55228 18.5523 9 18 9H10V10.5C10 11 9.61841 11 9.57151 11C9.36409 11 8.99012 10.9113 8.78279 10.7363L5.37934 8.08333C4.87356 7.65662 4.87356 7.34338 5.37934 6.91667L8.78279 4.26366C8.99012 4.08874 9.36409 4 9.5715 4Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 821 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 17V11H12V17H17V9H20L10 0L0 9H3V17H8Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* 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.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -19,6 +19,27 @@
var language;
var userid;
var directUrl;
var formatManager;
window.onload = function () {
fetch('formats')
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.name,
format.type,
format.actions,
format.convert,
format.mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery != "undefined") {
jq = jQuery.noConflict();
@ -100,7 +121,7 @@ if (typeof jQuery != "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
@ -116,7 +137,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (ConverExtList.indexOf(posExt) == -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -128,7 +149,7 @@ if (typeof jQuery != "undefined") {
async: true,
type: "post",
dataType: "json",
data: {filename: fileName, filePass: filePass, lang: language},
data: {filename: fileName, filePass: filePass, lang: language, fileExt: fileType},
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -148,6 +169,12 @@ if (typeof jQuery != "undefined") {
}
return;
} else {
if (response.error.includes("-9")){
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder",filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -159,7 +186,7 @@ if (typeof jQuery != "undefined") {
jq("#hiddenFileName").val(response.filename);
if (typeof response.step != "undefined" && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -197,14 +224,20 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
var checkEdited = EditedExtList.split(",").filter(function(ext) { return ext == posExt;});
var checkFilled = FilledExtList.split(",").filter(function(ext) { return ext == posExt;});
if (checkEdited != "" || checkFilled != "") {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq(".file-type").addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var pass = jq("#filePass").val();
if (pass) {
@ -272,6 +305,38 @@ if (typeof jQuery != "undefined") {
jq("#uploadSteps").after('<iframe id="embeddedView" src="' + url + '" height="345px" width="432px" frameborder="0" scrolling="no" allowtransparency></iframe>');
});
jq(document).on("click", "#beginEditConverted:not(.disable)", function () {
var fileId = encodeURIComponent(jq('#hiddenFileName').attr("data"));
if (UrlEditor == "wopi-action"){
var url = UrlEditor + "/" + fileId + "?action=edit" + collectParams(true);
}else{
var url = UrlEditor + "?fileName=" + fileId + collectParams(true);
}
window.open(url, "_blank");
jq('#hiddenFileName').val("");
jq.unblockUI();
window.location = collectParams();
});
jq(document).on("click", "#beginViewConverted:not(.disable)", function () {
var fileId = encodeURIComponent(jq('#hiddenFileName').attr("data"));
if (UrlEditor == "wopi-action"){
var url = UrlEditor + "/" + fileId + "?action=view" + collectParams(true);
}else{
var url = UrlEditor + "?mode=view&fileName=" + fileId + collectParams(true);
}
window.open(url, "_blank");
jq('#hiddenFileName').val("");
jq.unblockUI();
window.location = collectParams();
});
jq(document).on("click", "#downloadConverted:not(.disable)", function () {
var fileId = jq('#hiddenFileName').attr("data");
if (jq("#downloadConverted").attr("data") == "fromConverter") window.location.assign(fileId);
else window.location.href = "download?fileName=" + encodeURIComponent(fileId);
});
jq(document).on("click", ".reload-page", function () {
setTimeout(function () { window.location = collectParams(); }, 1000);
return true;
@ -293,6 +358,101 @@ if (typeof jQuery != "undefined") {
}
});
jq(document).on("click", ".convert-file", function () {
const currentElement = jq(this);
var fileName = currentElement.attr("data");
var type = currentElement.attr("data-type");
jq.blockUI({
theme: true,
title: "Converting file" + "<div class=\"dialog-close\"></div>",
message: jq("#convertingProgress"),
overlayCSS: { "background-color": "#aaa" },
themedCSS: { width: "539px", top: "20%", left: "50%", marginLeft: "-269px" }
});
jq("#convertFileName").text(decodeURIComponent(fileName));
jq("#convertFileName").removeClass("word slide cell");
jq("#convertFileName").addClass(type);
jq("#convTypes").empty();
let format = formatManager.findByExtension(fileName.split('.').pop());
if (format) {
format.convert.forEach(ext => {
jq("#convTypes").append(jq(`<td name="convertingTypeButton" id="wordTo${ext}" class="button hoar" data="${ext}">${ext}</td>`));
});
}
jq("#hiddenFileName").val(fileName);
jq("#convertStep1").addClass("done");
jq("#convertStep2").addClass("waiting");
});
jq(document).on("click", "td[name='convertingTypeButton']:not(.disable, .orange)", function () {
const currentElement = jq(this);
let id = currentElement[0].id;
let fileExt = jq(`#${id}`).attr("data");
jq(`#${id}`).addClass("orange");
jq("td[name='convertingTypeButton']").addClass("disable");
jq("#convertStep2").removeClass("waiting").removeClass("done").addClass("current");
jq("#convertStep2").text('2. File conversion');
jq("#convert-descr").removeClass("disable");
jq("#convertPercent").text("0 %");
jq("#hiddenFileName").attr("placeholder",fileExt);
jq("#downloadConverted").addClass("disable");
jq("#beginEditConverted").addClass("disable");
jq("#beginViewConverted").addClass("disable");
mustReload = true;
convertFile();
});
function convertFile (filePass) {
let fileName = decodeURIComponent(jq("#hiddenFileName").val());
let fileExt = jq("#hiddenFileName").attr("placeholder");
if (timer != null) {
clearTimeout(timer);
}
timer = setTimeout(function () {
jq.ajaxSetup({ cache: false });
jq.ajax({
async: true,
type: "post",
dataType: "json",
data: {filename: fileName, filePass: filePass, lang: language, fileExt: fileExt, keepOriginal: true},
url: UrlConverter,
complete: function (data) {
try {
var response = jq.parseJSON(data.responseText);
} catch (e) {
response = { error: e };
}
if(response.step !==100) {
jq("#convertPercent").text(`${response.step} %`);
convertFile();
} else {
jq("#convertPercent").text(`${response.step} %`);
jq("#convertStep2").removeClass("current").addClass("done");
jq("#convertStep2").text(`2. File conversion to ${fileExt}`);
jq("#downloadConverted").removeClass("disable");
if (response.error !== "FileTypeIsNotSupported") {
jq("#hiddenFileName").attr("data",response.filename);
jq("#beginEditConverted").removeClass("disable");
jq("#beginViewConverted").removeClass("disable");
jq("#downloadConverted").attr("data","fromStorage");
} else {
let newFilename = fileName.split('.').slice(0,-1).join('.')
jq("#hiddenFileName").attr("data",response.filename.split("&filename=download").join(`&filename=${newFilename}`));
jq("#downloadConverted").attr("data","fromConverter");
}
jq("td[name='convertingTypeButton']").removeClass("disable orange");
}
}
});
}, 1000);
}
jq(document).on("click", ".delete-file", function () {
const currentElement = jq(this);
var fileName = currentElement.attr("data");
@ -319,6 +479,22 @@ if (typeof jQuery != "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
jq.ajax({
async: true,
contentType: "text/xml",
type: "delete",
url: "file",
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location = collectParams();
}
}
});
}
});
jq("#createSample").click(function () {
jq(".try-editor").each(function () {
var href = jq(this).attr("href");

View File

@ -33,6 +33,15 @@
position: absolute;
width: 100%;
}
.tableHeaderCellFileName{
width: 30%;
}
@media (max-width: 1280px) and (min-width: 1080px) {
.tableHeaderCellViewers {
width: 24%;
}
}
@media (min-width: 1280px) {
.tableHeaderCellRemove{
@ -40,6 +49,7 @@
text-align: center;
}
.tableHeaderCellDownload{
width: 13%;
padding-right: 11px;
}
.tableHeaderCellViewers{
@ -58,6 +68,9 @@
.tableRow td:first-child {
max-width: 45%;
}
.tableHeaderCellViewers {
width: 23%;
}
}
@media (max-width: 986px) and (min-width: 890px){
.tableHeaderCellRemove{
@ -68,12 +81,15 @@
padding-right: 0;
}
.tableHeaderCellViewers{
width: 24%;
width: 22%;
padding-right: 0;
}
.tableRow td:first-child {
max-width: 40%;
}
.contentCells-wopi {
padding-right: 114px;
}
}
@media (max-width: 890px) and (min-width: 769px){
.tableRow td:first-child{
@ -85,6 +101,9 @@
.contentCells-wopi{
width: unset;
}
.tableHeaderCellRemove {
width: 5%;
}
}
@media (max-width: 769px) {
.tableRow td{
@ -112,7 +131,7 @@
}
@media (max-width: 769px) and (min-width: 320px){
.contentCells-icon {
width: 1%;
width: 9%;
}
}
@media (max-width: 508px) {

View File

@ -42,10 +42,14 @@
}
.tableHeaderCellViewers {
width: 29%;
width: 18%;
text-align: right;
}
.tableHeaderCellAction {
width: 23%;
}
.tableHeaderCellDownload {
width: 21%;
padding-right: 18px;
@ -79,7 +83,9 @@
margin-left: 0;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 90%;
}
@ -102,6 +108,10 @@
.tableHeaderCellRemove {
padding-left: 0px;
}
.storedHeaderClearAll {
padding-right: 48px;
}
}
@media (max-width: 1008px) {
@ -119,7 +129,8 @@
.contentCells-icon{
width: 5%;
}
.tableRow {
.tableRow,
menu.links {
width: 55%;
}
@ -135,7 +146,7 @@
}
.scroll-table-body {
top: 31px;
top: 33px;
}
footer {
@ -175,7 +186,9 @@
}
@media (max-width: 715px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 45%;
}
}
@ -217,7 +230,7 @@
}
.tableHeaderCellFileName {
width: 16%;
width: 9%;
}
.tableHeaderCellEditors {
@ -226,7 +239,12 @@
.tableHeaderCellViewers {
text-align: right;
width: 37%;
width: 9%;
}
.tableHeaderCellAction{
width: 11%;
padding-right: 82px;
}
.tableHeaderCellDownload {
@ -241,19 +259,24 @@
}
.tableHeaderCellEditors {
width: 26%;
width: 15%;
text-align: left;
}
.tableHeaderCellFileName {
width: 17%;
width: 28%;
}
.tableHeaderCellViewers {
width: 27%;
width: 6%;
text-align: right;
}
.tableHeaderCellAction{
width: 18%;
padding-right: 54px;
}
.tableHeaderCellDownload {
padding-right: 18px;
width: 20%;
@ -263,7 +286,9 @@
padding-left: 0;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 75%;
}
@ -273,12 +298,21 @@
.tableRow td:first-child {
flex-grow: 0;
width: 15%;
width: 25%;
margin-right: auto;
}
.contentCells-icon {
width: 3%;
}
.firstContentCellViewers {
margin-left: 0;
}
.storedHeaderClearAll {
padding-right: 18px;
}
}
@media (max-width: 890px) and (min-width: 769px ) {
@ -286,14 +320,16 @@
width: 20%;
}
.contentCells-shift {
padding-right: 28px;
padding-right: 27px;
}
.main-panel {
width: 580px;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 95%;
}
@ -318,11 +354,20 @@
.tableHeaderCellEditors {
text-align: left;
width: 31%;
width: 1%;
}
.tableHeaderCellViewers {
width: 18%;
width: 19%;
}
.tableHeaderCellAction {
width: 19%;
padding-right: 45px;
}
.storedHeaderClearAll {
padding-right: 8px;
}
}
@ -349,6 +394,10 @@
.tableRow td:first-child {
max-width: 100%;
}
.storedHeaderClearAll {
padding-right: 0px;
}
}
@ -367,7 +416,7 @@
}
.scroll-table-body {
top: 31px;
top: 33px;
}
footer table tr {
@ -407,7 +456,9 @@
padding: 16px 0 6px;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 40%;
}
@ -423,8 +474,8 @@
.downloadContentCellShift {
max-width: 7%;
margin-right: -11px;
margin-left: auto;
margin-right: 24px;
margin-left: 0;
}
.contentCells-icon {
@ -432,13 +483,13 @@
}
.tableRow td:last-child {
width: 12%;
padding-right: 40px;
width: 7%;
padding-right: 0px;
border: none;
}
.contentCells-shift {
padding-right: 35px;
padding-right: 0px;
}
.downloadContentCellShift:after {
@ -502,6 +553,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}
@ -513,6 +575,15 @@
height: 56px;
margin-bottom: 24px !important;
}
.button.hoar{
width: 18%;
height: 27px;
margin-bottom: 7px !important;
}
.button.converting{
width: 126px;
margin-top: 0;
}
}
@media (max-width: 560px) and (min-width: 510px) {
@ -521,13 +592,15 @@
}
.downloadContentCellShift {
padding-right: 45px;
padding-right: 16px;
max-width: 4%;
}
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 35%;
}
@ -540,7 +613,7 @@
.downloadContentCellShift {
max-width: 6%;
padding-right: 37px;
padding-right: 6px;
}
.firstContentCellShift {
@ -553,7 +626,9 @@
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 30%;
}
.tableRow td:first-child{
@ -565,12 +640,12 @@
.downloadContentCellShift {
max-width: 3%;
padding-right: 37px;
padding-right: 0px;
padding-left: 0;
}
.firstContentCellShift {
margin-left: 1px;
margin-left: 2px;
flex-basis: 14%;
}
@ -588,7 +663,9 @@
}
@media (max-width: 420px) and (min-width: 320px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 25%;
}
@ -599,7 +676,7 @@
.downloadContentCellShift {
max-width: 4%;
margin-right: -18px;
margin-right: 18px;
margin-left: -1px;
}
@ -608,7 +685,7 @@
}
.contentCells-icon{
width: 10%;
width: 12%;
}
footer table td {
margin: 0;
@ -624,6 +701,10 @@
padding-right: 2px;
width: 11%;
}
.header-list {
font-size: 12px;
}
}
@media (max-width: 1160px) {
@ -638,7 +719,9 @@
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow{
.tableRow,
.storedHeader,
menu.links {
width: 50%;
}
}

View File

@ -228,6 +228,79 @@ label .checkbox {
color: #FF6F3D;
}
.button.converting {
margin-top: -20px;
padding: 16px 16px;
}
.button.converting.wide {
padding: 16px 29px;
}
.button.hoar {
background: #EFEFEF;
border: 1px solid #EFEFEF;
margin-right: 7px;
margin-bottom: 7px;
width: 13%;
padding-left: 0;
padding-right: 0;
font-size: 11px;
}
.button.hoar.disable {
opacity: 30%;
cursor: default;
}
.button.hoar:not(.disable):hover {
background: #FF6F3D;
border: 1px solid #FF6F3D;
color: #FFFFFF;
}
.button.hoar.orange {
background: #FF6F3D;
border: 1px solid #FF6F3D;
color: #FFFFFF;
cursor: default;
}
.button.hoar.orange.disable {
background: #444444;
border: 1px solid #444444;
color: #FFFFFF;
cursor: default;
opacity: 100%;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -258,24 +331,64 @@ label .checkbox {
width: 192px;
}
.create-panel,
.links-panel {
.create-panel {
float: left;
padding: 16px 0;
}
.links {
display: flex;
padding: 0;
column-gap: 30px;
align-items: center;
list-style: none;
border-bottom: 1px solid #E2E2E2;
margin: 0;
margin-bottom: 24px;
}
.links li {
padding: 4px;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.links li.active {
border-bottom: 2px solid #FF6F3D;
}
.links li.active a {
color: #FF6F3D;
}
.links li.active a img {
filter: invert(55%) sepia(67%) saturate(2727%) hue-rotate(335deg) brightness(104%) contrast(101%);
}
.links a {
display: inline-block;
padding: 2px 0;
line-height: 20px;
font-size: 13px;
text-decoration: none;
}
.home-link {
height: 24px;
padding: 0 2px 8px !important;
}
.home-link a {
padding: 0;
padding-top: 7px;
}
.upload-panel,
.create-panel {
width: 100%;
border-bottom: 1px solid #D0D5DA;
}
.links-panel-border {
margin-top: 24px;
width: 100%;
border-top: 1px solid #D0D5DA;
}
#mainProgress {
color: #333333;
display: none;
@ -313,6 +426,32 @@ label .checkbox {
display: none;
}
#convertingProgress {
color: #333333;
display: none;
font-size: 12px;
margin: 30px 35px;
}
#convertingProgress .convertFileName{
background-position: left center;
background-repeat: no-repeat;
display: block;
font-size: 14px;
line-height: 160%;
overflow: hidden;
padding-left: 28px;
margin-bottom: 16px;
text-overflow: ellipsis;
white-space: nowrap;
}
#convertingProgress .describeUpload {
line-height: 150%;
letter-spacing: -0.02em;
padding: 16px 0;
}
.error-message {
background: url(../images/error.svg) no-repeat scroll 4px 10px;
color: #CB0000;
@ -334,6 +473,10 @@ label .checkbox {
padding-left: 35px;
}
.waiting {
opacity: 30%;
}
.current {
background-image: url("../images/loader16.gif");
}
@ -346,6 +489,12 @@ label .checkbox {
background-image: url("../images/notdone.svg");
}
.convertPercent {
color: #FF6F3D;
font-weight: 700;
display: inline;
}
.step-descr {
display: block;
margin-left: 35px;
@ -353,6 +502,10 @@ label .checkbox {
line-height: 188%;
}
.step-descr.disable {
display: none;
}
.progress-descr {
letter-spacing: -0.02em;
line-height: 150%;
@ -455,16 +608,19 @@ footer table tr td:first-child {
white-space: nowrap;
}
.convertFileName.word,
.stored-edit.word,
.uploadFileName.word {
background-image: url("../images/icon_docx.svg");
}
.convertFileName.cell,
.stored-edit.cell,
.uploadFileName.cell {
background-image: url("../images/icon_xlsx.svg");
}
.convertFileName.slide,
.stored-edit.slide,
.uploadFileName.slide {
background-image: url("../images/icon_pptx.svg");
@ -526,6 +682,11 @@ footer table tr td:first-child {
visibility: hidden;
}
.convertTable {
margin-top: 10px;
margin-left: 35px;
}
.tableRow {
background: transparent;
-moz-transition: all 0.2s ease-in-out;
@ -572,6 +733,12 @@ footer table tr td:first-child {
width: 11%;
}
.tableHeaderCellAction{
width: 13%;
text-align: right;
padding-right: 88px;
}
.tableHeaderCellDownload{
width: 13%;
text-align: right;
@ -595,7 +762,7 @@ footer table tr td:first-child {
}
.contentCells-shift {
padding-right: 44px;
padding-right: 43px;
}
.contentCells-icon {
@ -613,6 +780,28 @@ footer table tr td:first-child {
margin-right: 8px;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -672,7 +861,7 @@ footer table tr td:first-child {
width: 100%;
}
.icon-delete {
.icon-action {
cursor: pointer;
}
@ -688,7 +877,7 @@ footer table tr td:first-child {
overflow-x: auto;
position: absolute;
right: 0;
top: 71px;
top: 75px;
scrollbar-color: #D0D5DA transparent;
scrollbar-width: thin;
}
@ -751,6 +940,14 @@ html {
position: relative;
}
.typeButtonsRow {
width: 100%;
display: flex;
flex-wrap: wrap;
flex-direction: row;
position: relative;
}
.tableRow td:first-child {
display: flex;
@ -759,11 +956,11 @@ html {
}
.tableHeaderCellFileName {
width: 30%;
width: 20%;
}
.tableHeaderCellEditors {
width: 28%;
width: 20%;
}
.tableHeaderCellViewers {
@ -789,3 +986,13 @@ html {
.user-descr > b {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}

View File

@ -42,9 +42,7 @@
"close": <%- JSON.stringify(editor.close) %>,
"feedback": true,
"forcesave": false,
"goback": {
"url": "<%- editor.backUrl %>"
},
"goback": <%- JSON.stringify(editor.goback) %>,
"submitForm": <%- editor.submitForm %>
},
"embedded": {

View File

@ -354,9 +354,7 @@
};
var onDocumentReady = function(){
if (config.type === "mobile") {
document.getElementsByTagName("iframe")[0].style.height = window.innerHeight + "px";
}
fixSize();
};
config = {
@ -381,13 +379,15 @@
config.events.onRequestEditRights = onRequestEditRights;
config.events.onRequestHistory = onRequestHistory;
config.events.onRequestHistoryData = onRequestHistoryData;
config.events.onRequestHistoryClose = onRequestHistoryClose;
config.events.onRequestRestore = onRequestRestore;
config.events.onRequestRename = onRequestRename;
config.events.onRequestUsers = onRequestUsers;
config.events.onRequestSendNotify = onRequestSendNotify;
config.events.onRequestReferenceData = onRequestReferenceData;
config.events.onRequestReferenceSource = onRequestReferenceSource;
if (<%- JSON.stringify(editor.userid) %> != "uid-3") {
config.events.onRequestHistoryClose = onRequestHistoryClose;
config.events.onRequestRestore = onRequestRestore;
}
}
if (config.editorConfig.createUrl) {
@ -403,14 +403,21 @@
}
var connectEditor = function () {
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
fixSize();
};
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
// get the editor sizes
var fixSize = function () {
if (config.type !== "mobile") {
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
var wrapEl = document.getElementsByTagName("iframe");
if (wrapEl.length) {
wrapEl[0].style.height = screen.availHeight + "px";
window.scrollTo(0, -1);
wrapEl[0].style.height = window.innerHeight + "px";
}
};
const getFileExt = function (fileName) {
@ -422,8 +429,12 @@
if (window.addEventListener) {
window.addEventListener("load", connectEditor);
window.addEventListener("resize", fixSize);
window.addEventListener("orientationchange", fixSize);
} else if (window.attachEvent) {
window.attachEvent("onload", connectEditor);
window.attachEvent("onresize", fixSize);
window.attachEvent("orientationchange", fixSize);
}
</script>

View File

@ -106,15 +106,21 @@
</tr>
</tbody>
</table>
<div class="links-panel links-panel-border clearFix">
<a href="wopi" class="">Go to WOPI page</a>
</div>
</div>
</div>
</td>
<td class="section">
<div class="main-panel">
<menu class="links">
<li class="home-link active" >
<a href="./">
<img src="images/home.svg" alt="Home"/>
</a>
</li>
<li>
<a href="wopi">Wopi</a>
</li>
</menu>
<div id="portal-info" style="display: <%= storedFiles.length > 0 ? "none" : "table-cell" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
@ -137,15 +143,21 @@
<%if (storedFiles.length > 0)
{%>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
<td class="tableHeaderCell tableHeaderCellFileName">Filename</td>
<td class="tableHeaderCell tableHeaderCellEditors contentCells-shift">Editors</td>
<td class="tableHeaderCell tableHeaderCellViewers">Viewers</td>
<td class="tableHeaderCell tableHeaderCellDownload">Download</td>
<td class="tableHeaderCell tableHeaderCellRemove">Remove</td>
<td class="tableHeaderCell tableHeaderCellAction">Action</td>
</tr>
</thead>
</table>
@ -230,13 +242,21 @@
<a class="action-link" href="editor?type=embedded&mode=embedded&fileName=<%= encodeURIComponent(storedFiles[i].name) %>" target="_blank">
<img src="images/embeded.svg" alt="Open in embedded mode" title="Open in embedded mode" /></a>
</td>
<td class="contentCells contentCells-icon contentCells-shift downloadContentCellShift">
<% if (storedFiles[i].documentType != null ) {%>
<td class="contentCells contentCells-icon">
<a class="convert-file" data="<%= encodeURIComponent(storedFiles[i].name) %>" data-type="<%= storedFiles[i].documentType %>">
<img class="icon-action" src="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="download?fileName=<%= encodeURIComponent(storedFiles[i].name) %>">
<img class="icon-download" src="images/download.svg" alt="Download" title="Download" /></a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a class="delete-file" data="<%= encodeURIComponent(storedFiles[i].name) %>">
<img class="icon-delete" src="images/delete.svg" alt="Delete" title="Delete" /></a>
<img class="icon-action" src="images/delete.svg" alt="Delete" title="Delete" /></a>
</td>
</tr>
<% } %>
@ -258,6 +278,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -294,6 +323,31 @@
</div>
</div>
<div id="convertingProgress">
<div id="convertingSteps">
<span id="convertFileName" class="convertFileName"></span>
<span id="convertStep1" class="step">1. Select a format file to convert</span>
<span class="step-descr">The converting speed depends on file size and additional elements it contains.</span>
<table cellspacing="0" cellpadding="0" width="100%" class="convertTable">
<tbody>
<tr class="typeButtonsRow" id="convTypes"></tr>
</tbody>
</table>
<br />
<span id="convertStep2" class="step">2. File conversion</span>
<span class="step-descr disable" id="convert-descr">The file is converted <div class="convertPercent" id="convertPercent">0 %</div></span>
<div class="describeUpload">Note the speed of all operations depends on your connection quality and server location.</div>
<input type="hidden" name="hiddenFileName" id="hiddenFileName" />
</div>
<br />
<div class="buttonsMobile">
<div id="downloadConverted" class="button converting orange disable">DOWNLOAD</div>
<div id="beginViewConverted" class="button converting wide gray disable">VIEW</div>
<div id="beginEditConverted" class="button converting wide gray disable">EDIT</div>
<div id="cancelEdit" class="button converting gray">CANCEL</div>
</div>
</div>
<span id="loadScripts" data-docs="<%= preloaderUrl %>"></span>
<footer>
@ -323,12 +377,10 @@
<script type="text/javascript" src="javascripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="javascripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="javascripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="javascripts/formats.js"></script>
<script type="text/javascript" src="javascripts/jscript.js"></script>
<script type="text/javascript">
var ConverExtList = "<%= convertExts %>";
var EditedExtList = "<%= editedExts %>";
var FilledExtList = "<%= fillExts %>";
var UrlConverter = "convert";
var UrlEditor = "editor";
</script>

View File

@ -23,7 +23,7 @@
*
-->
<title>ONLYOFFICE Document Editors</title>
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<style type="text/css">
body {
@ -32,7 +32,7 @@
overflow: hidden;
-ms-content-zooming: none;
}
#office_frame {
width: 100%;
height: 100%;
@ -66,11 +66,33 @@
office_frame.title = 'Office Frame';
office_frame.setAttribute('allowfullscreen', 'true');
office_frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups allow-top-navigation allow-popups-to-escape-sandbox allow-downloads allow-modals');
office_frame.setAttribute('allow', 'autoplay camera microphone display-capture');
frameholder.appendChild(office_frame);
document.getElementById('office_form').submit();
var _onMessage = function(msg) {
var data = msg.data;
if (Object.prototype.toString.apply(data) !== '[object String]' || !window.JSON) {
return;
}
var cmd = JSON.parse(data);
if (cmd) {
if ( cmd.MessageId == 'App_LoadingStatus' ) {
var fixSize = function() {
document.getElementsByTagName("iframe")[0].style.height = window.innerHeight + "px";
}
fixSize();
window.addEventListener("orientationchange", fixSize);
}
}
};
window.addEventListener('message', function (e) {
_onMessage(e);
});
</script>
</body>

View File

@ -98,14 +98,20 @@
</tr>
</tbody>
</table>
<div class="links-panel links-panel-border clearFix">
<a href="./" class="">Go to Index page</a>
</div>
</div>
</td>
<td class="section">
<div class="main-panel">
<menu class="links">
<li class="home-link" >
<a href="./">
<img src="images/home.svg" alt="Home"/>
</a>
</li>
<li class="active">
<a href="wopi">Wopi</a>
</li>
</menu>
<div id="portal-info" style="display: <%= storedFiles.length > 0 ? "none" : "table-cell" %>">
<% if (!wopiEnable)
{ %>
@ -129,7 +135,14 @@
<% if (storedFiles.length > 0)
{ %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -172,7 +185,7 @@
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a class="delete-file" data="<%= encodeURIComponent(storedFiles[i].name) %>">
<img class="icon-delete" src="images/delete.svg" alt="Delete" title="Delete" /></a>
<img class="icon-action" src="images/delete.svg" alt="Delete" title="Delete" /></a>
</td>
</tr>
<% } %>
@ -259,12 +272,10 @@
<script type="text/javascript" src="javascripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="javascripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="javascripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="javascripts/formats.js"></script>
<script type="text/javascript" src="javascripts/jscript.js"></script>
<script type="text/javascript">
var ConverExtList = "<%= convertExts %>";
var EditedExtList = "<%= editedExts %>";
var FilledExtList = "<%= fillExts %>";
var UrlConverter = "convert";
var UrlEditor = "wopi-action";
</script>

View File

@ -61,6 +61,12 @@ compose-prod: # Up containers in a production environment.
@docker-compose build
@docker-compose up --detach
.PHONY: restart
restart: # Restart containers replacing volume files.
@docker-compose rm --stop --force proxy example
@docker volume rm php_example
@docker compose up --detach --build
.PHONY: lint
lint: # Lint the source code for the style.
@./vendor/bin/phpcs src index.php

View File

@ -0,0 +1,117 @@
export class FileRow extends HTMLTableRowElement {
constructor() {
super();
}
connectedCallback() {
const encodedTitle = encodeURIComponent(this.file.title);
const encodedUser = encodeURIComponent(this.user);
const directUrl = this.directUrl ? "&directUrl=true&" : "";
this.innerHTML = `
<td class="contentCells">
<a class="stored-edit ${this.file.type}" href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}" target="_blank">
<span>${this.file.title}</span>
</a>
</td>
${this.file.editable ? `
<td class="contentCells contentCells-icon">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=edit&type=desktop" target="_blank">
<img src="assets/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?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=edit&type=mobile" target="_blank">
<img src="assets/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices" />
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=comment&type=desktop" target="_blank">
<img src="assets/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment" />
</a>
</td>
${this.file.type === "word" ? `
<td class="contentCells contentCells-icon">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=review&type=desktop" target="_blank">
<img src="assets/images/review.svg" alt="Open in editor for review" title="Open in editor for review" />
</a>
</td>
<td class="contentCells contentCells-icon ">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=blockcontent&type=desktop" target="_blank">
<img src="assets/images/block-content.svg" alt="Open in editor without content control modification" title="Open in editor without content control modification"
</a>
</td>
`: ``}
${this.file.type === "cell" ? `
<td class="contentCells contentCells-icon">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=filter&type=desktop" target="_blank">
<img src="assets/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>
`: ``}
${this.file.type !== "word" && this.file.type !== "cell" ? `<td class="contentCells contentCells-icon"></td><td class="contentCells contentCells-icon"></td>` : ``}
${this.file.fillable ? `
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=fillForms&type=desktop" target="_blank">
<img src="assets/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms" />
</a>
</td>
`: `<td class="contentCells contentCells-shift contentCells-iconfirstContentCellShift"></td>`}
` : ``}
${this.file.fillable ? `
<td class="contentCells contentCells-icon">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=fillForms&type=desktop" target="_blank">
<img src="assets/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="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=fillForms&type=desktop" target="_blank">
<img src="assets/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
` : `<td class="contentCells contentCells-shift contentCells-icon contentCellsEmpty" colspan="6"></td>`}
<td class="contentCells contentCells-icon firstContentCellViewers">
<a href="editor?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=view&type=desktop" target="_blank">
<img src="assets/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?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=view&type=mobile" target="_blank">
<img src="assets/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?fileID=${encodedTitle}&user=${encodedUser + directUrl}&action=embedded&type=embedded" target="_blank">
<img src="assets/images/embeded.svg" alt="Open in embedded mode" title="Open in embedded mode" />
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift downloadContentCellShift">
<a href="download?fileName=${encodedTitle}">
<img class="icon-download" src="assets/images/download.svg" alt="Download" title="Download"/>
</a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a class="delete-file" data="${encodedTitle}">
<img class="icon-delete" src="assets/images/delete.svg" alt="Delete" title="Delete" />
</a>
</td>
`;
this.classList.add("tableRow");
this.title = `${this.file.title} ${this.file.version}`;
}
get file() {
return JSON.parse(this.dataset.file || {});
}
get user() {
return this.dataset.user;
}
get directUrl() {
return this.dataset.directUrl;
}
}

View File

@ -0,0 +1,54 @@
export class FileTable extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const files = this.data.files;
const user = this.data.user;
const directUrl = this.data.directUrl
this.innerHTML = `
<div class="stored-list">
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
<td class="tableHeaderCell tableHeaderCellFileName">Filename</td>
<td class="tableHeaderCell tableHeaderCellEditors contentCells-shift">Editors</td>
<td class="tableHeaderCell tableHeaderCellViewers">Viewers</td>
<td class="tableHeaderCell tableHeaderCellDownload">Download</td>
<td class="tableHeaderCell tableHeaderCellRemove">Remove</td>
</tr>
</thead>
</table>
<div class="scroll-table-body">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
${files.map(file =>`
<tr
is="file-row"
data-file='${JSON.stringify(file)}'
data-user="${user}"
data-direct-url="${directUrl}"
></tr>
`).join("")}
</tbody>
</table>
</div>
</div>
`;
}
get data() {
return JSON.parse(this.getAttribute("data")) || {}
}
}

View File

@ -0,0 +1,4 @@
import { FileRow } from "./file-row.js";
import { FileTable } from "./file-table.js";
customElements.define("file-row", FileRow, { extends: "tr" });
customElements.define("file-table", FileTable);

View File

@ -504,6 +504,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -229,6 +229,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -594,6 +621,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -743,6 +793,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

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