Merge branch 'staging' into socketio
This commit is contained in:
commit
d9c186a3da
@ -5,7 +5,7 @@ www/common/tippy/
|
|||||||
www/common/jquery-ui/
|
www/common/jquery-ui/
|
||||||
|
|
||||||
server.js
|
server.js
|
||||||
www/common/media-tag.js
|
www/common/old-media-tag.js
|
||||||
www/scratch
|
www/scratch
|
||||||
|
|
||||||
www/common/toolbar.js
|
www/common/toolbar.js
|
||||||
|
|||||||
28
CHANGELOG.md
28
CHANGELOG.md
@ -1,3 +1,31 @@
|
|||||||
|
# Donkey release (v2.3.0)
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
For this release we wanted to deploy some new features related to our encrypted file functionality.
|
||||||
|
|
||||||
|
## Update notes
|
||||||
|
|
||||||
|
* new clientside dependencies. run `bower update`
|
||||||
|
* new serverside APIs. Restart your server
|
||||||
|
|
||||||
|
## What's new
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* When uploading files to your CryptDrive or a pad, users will now be prompted to protect the file with a password (in addition to some random data)
|
||||||
|
* this adds an additional layer of security in case a third party gains access to the file's link, but not the password.
|
||||||
|
* Users are also able to claim an encrypted file as their own, allowing them the option to delete it from the server at a later date.
|
||||||
|
* We've refactored the Media-Tag library to be much smaller and easier to use.
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
* When setting a title for a pad which was created from a template, titles were not correctly inferred from the content of a document. This has been fixed.
|
||||||
|
* We discovered that users who had installed _AdBlock Plus_ and configured it to **Block social media icons tracking** were unable to use the _share menu_ to construct alternative links to the same pad, but with different attributes. We have worked around the problem.
|
||||||
|
* Admins who had configured their CryptPad instance to use custom icons for applications in the CryptDrive may have noticed that the same icons were not used on the home page. We've fixed this such that the same icons will be used everywhere
|
||||||
|
* We have also updated the icon for the Kanban app to a more appropriate symbol
|
||||||
|
* We found that the download button in the _file_ app was downloading the user's avatar, instead of the correct encrypted file embedded in the page. We've since fixed this
|
||||||
|
|
||||||
# Coati release (v2.2.0)
|
# Coati release (v2.2.0)
|
||||||
|
|
||||||
## Goals
|
## Goals
|
||||||
|
|||||||
1
customize.dist/CryptPadlogo_op5.svg
Normal file
1
customize.dist/CryptPadlogo_op5.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 393.94 476.2"><defs><style>.cls-1{opacity:0.04;}.cls-2{fill:#999;}.cls-3{fill:#4591c4;}</style></defs><title>CryptPadlogo</title><g id="Layer_2" data-name="Layer 2"><g id="svg2"><g id="g4764" class="cls-1"><path class="cls-2" d="M139.36,288.16l32.07-64.43a13.59,13.59,0,0,0-4.23-16.62,48.65,48.65,0,0,1-21.28-48.25l-23.47-15.31a75.74,75.74,0,0,0-3.36,21.87c0,22,9.52,41.45,24.35,55.54l-27.24,54.8c-.11,0-.2,0-.31,0a23.27,23.27,0,1,0,0,46.53,23,23,0,0,0,17.31-7.86h40.27V288.16Z"/><path class="cls-2" d="M278.28,275.73c-.57,0-1.11.13-1.68.17l-27.33-55.09c14.75-14.07,24.2-33.47,24.2-55.39a77.13,77.13,0,0,0-3.06-21.72l-23.62,15.45a51.69,51.69,0,0,1,.44,6.27A50.21,50.21,0,0,1,225.65,207a13.58,13.58,0,0,0-4.22,16.62l31.77,64.58h-34V314.4h41.63a23.23,23.23,0,1,0,17.41-38.67Z"/><polygon class="cls-2" points="270.41 143.7 270.41 143.7 270.41 143.7 270.41 143.7"/><circle class="cls-3" cx="196.06" cy="167.4" r="21.21"/><path class="cls-3" d="M362.25,21.36a31.14,31.14,0,0,0-18.1,5.8L197,0,50,27.16a31.62,31.62,0,1,0-33.68,53.4v212c0,19.95,8.93,41.51,26.62,64.08,15.66,20,37.82,40.46,65.89,60.83a603,603,0,0,0,57,36.21,31.54,31.54,0,0,0,60,1.25,606,606,0,0,0,59.26-37.46c28.09-20.37,50.23-40.86,65.9-60.83,17.7-22.6,26.61-44.13,26.61-64.08V80.38a31.46,31.46,0,0,0-15.39-59ZM62.82,55.94,196.61,31.32l134.33,24.8a29.58,29.58,0,0,0,.9,5.61L253.09,113a76.78,76.78,0,0,0-113.69.36L61.55,62.82A31.8,31.8,0,0,0,62.82,55.94ZM350.49,288.21a51.41,51.41,0,0,1-.73,8.51c-3.16,12.6-10.11,25.8-20.82,39.47-13.41,17.09-32.43,34.52-56.48,51.95a532.75,532.75,0,0,1-54.19,34.09,31.5,31.5,0,0,0-43.73-.62,534,534,0,0,1-53.06-33.47c-24-17.43-42.9-34.86-56.31-51.95-12.77-16.31-20.25-31.94-22.26-46.71,0-.41,0-.86,0-1.27V82.37a31.51,31.51,0,0,0,8.69-5.25l88.88,57.75.37-.36,10.5,6.88a51,51,0,0,1,45.07-27,50.37,50.37,0,0,1,45.08,27.15l22.09-14.3L341.44,76.4A32.55,32.55,0,0,0,350.49,82Z"/></g></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
BIN
customize.dist/images/cover-faq.jpg
Normal file
BIN
customize.dist/images/cover-faq.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
BIN
customize.dist/images/cover-features.jpg
Normal file
BIN
customize.dist/images/cover-features.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
BIN
customize.dist/images/cover-privacy.jpg
Normal file
BIN
customize.dist/images/cover-privacy.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
@ -69,7 +69,7 @@ define([
|
|||||||
footerCol(null, [
|
footerCol(null, [
|
||||||
h('div.cp-bio-foot', [
|
h('div.cp-bio-foot', [
|
||||||
h('p', Msg.main_footerText),
|
h('p', Msg.main_footerText),
|
||||||
//languageSelector()
|
languageSelector()
|
||||||
])
|
])
|
||||||
], ''),
|
], ''),
|
||||||
footerCol('footer_applications', [
|
footerCol('footer_applications', [
|
||||||
@ -95,7 +95,7 @@ define([
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
h('div.cp-version-footer', "CryptPad v2.2.0 (Coati)")
|
h('div.cp-version-footer', "CryptPad v2.3.0 (Donkey)")
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,10 +181,10 @@ define([
|
|||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
h('div.row.align-items-center',[
|
h('div.row.align-items-center',[
|
||||||
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-2.cp-bio-avatar.cp-bio-avatar-right', [
|
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-lg-2.cp-bio-avatar.cp-bio-avatar-right', [
|
||||||
h('img.img-fluid', {'src': '/customize/images/AaronMacSween.jpg'})
|
h('img.img-fluid', {'src': '/customize/images/AaronMacSween.jpg'})
|
||||||
]),
|
]),
|
||||||
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-1.cp-profile-det',[
|
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-lg-1.cp-profile-det',[
|
||||||
h('h3', "Aaron MacSween"),
|
h('h3', "Aaron MacSween"),
|
||||||
h('hr'),
|
h('hr'),
|
||||||
setHTML(h('div#bioAaron'), '<p>Aaron transitioned into distributed systems development from a background in jazz and live stage performance. <br/> He appreciates the elegance of biological systems and functional programming, and focused on both as a student at the University of Toronto, where he studied cognitive and computer sciences.<br/>He moved to Paris in 2015 to work as a research engineer at XWiki SAS, after having dedicated significant time to various cryptography-related software projects.<br/>He spends his spare time experimenting with guitars, photography, science fiction, and spicy food.</p>'),
|
setHTML(h('div#bioAaron'), '<p>Aaron transitioned into distributed systems development from a background in jazz and live stage performance. <br/> He appreciates the elegance of biological systems and functional programming, and focused on both as a student at the University of Toronto, where he studied cognitive and computer sciences.<br/>He moved to Paris in 2015 to work as a research engineer at XWiki SAS, after having dedicated significant time to various cryptography-related software projects.<br/>He spends his spare time experimenting with guitars, photography, science fiction, and spicy food.</p>'),
|
||||||
@ -232,10 +232,10 @@ define([
|
|||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
h('div.row.align-items-center',[
|
h('div.row.align-items-center',[
|
||||||
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-2.cp-bio-avatar.cp-bio-avatar-right', [
|
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-lg-2.cp-bio-avatar.cp-bio-avatar-right', [
|
||||||
h('img.img-fluid', {'src': '/customize/images/Catalin.jpg'})
|
h('img.img-fluid', {'src': '/customize/images/Catalin.jpg'})
|
||||||
]),
|
]),
|
||||||
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-1.cp-profile-det',[
|
h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-lg-1.cp-profile-det',[
|
||||||
h('h3', "Catalin Scripcariu"),
|
h('h3', "Catalin Scripcariu"),
|
||||||
h('hr'),
|
h('hr'),
|
||||||
setHTML(h('div#bioCatalin'), '<p> Catalin is a Maths majour and has worked in B2B sales for 12 years. Design was always his passion and 3 years ago he started to dedicate himself to web design and front-end.<br/>At the beginning of 2017 he joined the XWiki, where he worked both on the business and the community side of XWiki, including the research team and CryptPad. </p>'),
|
setHTML(h('div#bioCatalin'), '<p> Catalin is a Maths majour and has worked in B2B sales for 12 years. Design was always his passion and 3 years ago he started to dedicate himself to web design and front-end.<br/>At the beginning of 2017 he joined the XWiki, where he worked both on the business and the community side of XWiki, including the research team and CryptPad. </p>'),
|
||||||
@ -271,113 +271,83 @@ define([
|
|||||||
Pages['/features.html'] = function () {
|
Pages['/features.html'] = function () {
|
||||||
return h('div#cp-main', [
|
return h('div#cp-main', [
|
||||||
infopageTopbar(),
|
infopageTopbar(),
|
||||||
h('div.container.cp-container', [
|
h('div.container-fluid.cp_cont_features',[
|
||||||
|
h('div.container',[
|
||||||
h('center', h('h1', Msg.features_title)),
|
h('center', h('h1', Msg.features_title)),
|
||||||
h('table#cp-features-table', [
|
|
||||||
h('thead', h('tr', [
|
|
||||||
h('th', Msg.features_feature),
|
|
||||||
h('th', Msg.features_anon),
|
|
||||||
h('th', Msg.features_registered),
|
|
||||||
h('th', Msg.features_notes)
|
|
||||||
])),
|
|
||||||
h('tbody', [
|
|
||||||
h('tr', [
|
|
||||||
h('td', Msg.features_f_pad),
|
|
||||||
h('td.yes', '✔'),// u2714, u2715
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td', Msg.features_f_pad_notes)
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
|
||||||
h('td', Msg.features_f_history),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td', Msg.features_f_history_notes)
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('div.container',[
|
||||||
h('td', Msg.features_f_export),
|
h('div.row.cp-container.cp-features-web.justify-content-sm-center',[
|
||||||
h('td.yes', '✔'),
|
h('div.col-12.col-sm-6.cp-anon-user',[
|
||||||
h('td.yes', '✔'),
|
h('div.card',[
|
||||||
h('td', Msg.features_f_export_notes)
|
h('div.card-body',[
|
||||||
|
h('h3.text-center',Msg.features_anon)
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('ul.list-group.list-group-flush', [
|
||||||
h('td', Msg.features_f_todo),
|
h('li.list-group-item.text-center', Msg.features_f_pad , [
|
||||||
h('td.yes', '✔'),
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_pad_notes}, h('i.fa.fa-question'))
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td')
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('li.list-group-item.text-center', Msg.features_f_history, [
|
||||||
h('td', Msg.features_f_viewFiles),
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_history_notes }, h('i.fa.fa-question') )
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td')
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('li.list-group-item.text-center', Msg.features_f_export, [
|
||||||
h('td', Msg.features_f_drive),
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_export_notes }, h('i.fa.fa-question'))
|
||||||
h('td.part', '~'),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td', Msg.features_f_drive_notes)
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('li.list-group-item.text-center', Msg.features_f_todo),
|
||||||
h('td', Msg.features_f_uploadFiles),
|
h('li.list-group-item.text-center', Msg.features_f_viewFiles),
|
||||||
h('td.no', '✕'),
|
h('li.list-group-item.text-center', Msg.features_f_drive),
|
||||||
h('td.yes', '✔'),
|
h('li.list-group-item.text-center', Msg.features_f_storage_anon),
|
||||||
h('td')
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
|
||||||
h('td', Msg.features_f_embedFiles),
|
|
||||||
h('td.no', '✕'),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td')
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
|
||||||
h('td', Msg.features_f_multiple),
|
|
||||||
h('td.no', '✕'),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td', Msg.features_f_multiple_notes)
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('div.col-12.col-sm-6.cp-regis-user',[
|
||||||
h('td', Msg.features_f_logoutEverywhere),
|
h('div.card',[
|
||||||
h('td.no', '✕'),
|
h('div.card-body',[
|
||||||
h('td.yes', '✔'),
|
h('h3.text-center',Msg.features_registered)
|
||||||
h('td', Msg.features_f_logoutEverywhere_notes || '')
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('ul.list-group.list-group-flush', [
|
||||||
h('td', Msg.features_f_templates),
|
h('li.list-group-item.text-center', Msg.features_f_pad, [
|
||||||
h('td.no', '✕'),
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_pad_notes}, h('i.fa.fa-question'))
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td', Msg.features_f_templates_notes)
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('li.list-group-item.text-center', Msg.features_f_history, [
|
||||||
h('td', Msg.features_f_profile),
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_history_notes }, h('i.fa.fa-question'))
|
||||||
h('td.no', '✕'),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td', Msg.features_f_profile_notes)
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('li.list-group-item.text-center', Msg.features_f_export, [
|
||||||
h('td', Msg.features_f_tags),
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_export_notes }, h('i.fa.fa-question'))
|
||||||
h('td.no', '✕'),
|
|
||||||
h('td.yes', '✔'),
|
|
||||||
h('td', Msg.features_f_tags_notes)
|
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('li.list-group-item.text-center', Msg.features_f_todo),
|
||||||
h('td', Msg.features_f_contacts),
|
h('li.list-group-item.text-center', Msg.features_f_viewFiles),
|
||||||
h('td.no', '✕'),
|
h('li.list-group-item.text-center', Msg.features_f_drive_full),
|
||||||
h('td.yes', '✔'),
|
h('li.list-group-item.text-center', Msg.features_f_uploadFiles),
|
||||||
h('td', Msg.features_f_contacts_notes)
|
h('li.list-group-item.text-center', Msg.features_f_embedFiles),
|
||||||
|
h('li.list-group-item.text-center', Msg.features_f_multiple, [
|
||||||
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_multiple_notes }, h('i.fa.fa-question'))
|
||||||
]),
|
]),
|
||||||
h('tr', [
|
h('li.list-group-item.text-center', Msg.features_f_logoutEverywhere),
|
||||||
h('td', Msg.features_f_storage),
|
h('li.list-group-item.text-center', Msg.features_f_templates, [
|
||||||
h('td.no', Msg.features_f_storage_anon),
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_templates_notes }, h('i.fa.fa-question'))
|
||||||
setHTML(h('td.yes.left'), Msg.features_f_storage_registered),
|
|
||||||
h('td')
|
|
||||||
]),
|
]),
|
||||||
])
|
h('li.list-group-item.text-center', Msg.features_f_profile, [
|
||||||
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_profile_notes }, h('i.fa.fa-question'))
|
||||||
]),
|
]),
|
||||||
|
h('li.list-group-item.text-center', Msg.features_f_tags, [
|
||||||
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_tags_notes }, h('i.fa.fa-question'))
|
||||||
|
]),
|
||||||
|
h('li.list-group-item.text-center', Msg.features_f_contacts, [
|
||||||
|
h('a.voted', {href: '#', 'data-toggle' : 'tooltip', 'data-placement': 'bottom', title : Msg.features_f_contacts_notes }, h('i.fa.fa-question'))
|
||||||
|
]),
|
||||||
|
h('li.list-group-item.text-center', setHTML(h('div'), Msg.features_f_storage_registered)),
|
||||||
|
]),
|
||||||
|
h('div.card-body',[
|
||||||
h('div#cp-features-register', [
|
h('div#cp-features-register', [
|
||||||
h('a', {
|
h('a', {
|
||||||
href: '/register/'
|
href: '/register/'
|
||||||
}, h('button.cp-features-register-button', 'Register for free'))
|
}, h('button.cp-features-register-button', Msg.features_f_register))
|
||||||
])
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
infopageFooter()
|
infopageFooter()
|
||||||
]);
|
]);
|
||||||
@ -386,25 +356,35 @@ define([
|
|||||||
Pages['/privacy.html'] = function () {
|
Pages['/privacy.html'] = function () {
|
||||||
return h('div#cp-main', [
|
return h('div#cp-main', [
|
||||||
infopageTopbar(),
|
infopageTopbar(),
|
||||||
h('div.container.cp-container', [
|
h('.container-fluid.cp-privacy-top', [
|
||||||
|
h('div.container',[
|
||||||
h('center', h('h1', Msg.policy_title)),
|
h('center', h('h1', Msg.policy_title)),
|
||||||
h('h2', Msg.policy_whatweknow),
|
]),
|
||||||
|
]),
|
||||||
|
h('div.container.cp-container.cp-privacy',[
|
||||||
|
h('h3', Msg.policy_whatweknow),
|
||||||
|
h('hr'),
|
||||||
setHTML(h('p'), Msg.policy_whatweknow_p1),
|
setHTML(h('p'), Msg.policy_whatweknow_p1),
|
||||||
|
|
||||||
h('h2', Msg.policy_howweuse),
|
h('h3', Msg.policy_howweuse),
|
||||||
|
h('hr'),
|
||||||
h('p', Msg.policy_howweuse_p1),
|
h('p', Msg.policy_howweuse_p1),
|
||||||
h('p', Msg.policy_howweuse_p2),
|
h('p', Msg.policy_howweuse_p2),
|
||||||
|
|
||||||
h('h2', Msg.policy_whatwetell),
|
h('h3', Msg.policy_whatwetell),
|
||||||
|
h('hr'),
|
||||||
h('p', Msg.policy_whatwetell_p1),
|
h('p', Msg.policy_whatwetell_p1),
|
||||||
|
|
||||||
h('h2', Msg.policy_links),
|
h('h3', Msg.policy_links),
|
||||||
|
h('hr'),
|
||||||
h('p', Msg.policy_links_p1),
|
h('p', Msg.policy_links_p1),
|
||||||
|
|
||||||
h('h2', Msg.policy_ads),
|
h('h3', Msg.policy_ads),
|
||||||
|
h('hr'),
|
||||||
h('p', Msg.policy_ads_p1),
|
h('p', Msg.policy_ads_p1),
|
||||||
|
|
||||||
h('h2', Msg.policy_choices),
|
h('h3', Msg.policy_choices),
|
||||||
|
h('hr'),
|
||||||
h('p', Msg.policy_choices_open),
|
h('p', Msg.policy_choices_open),
|
||||||
setHTML(h('p'), Msg.policy_choices_vpn),
|
setHTML(h('p'), Msg.policy_choices_vpn),
|
||||||
]),
|
]),
|
||||||
@ -425,8 +405,10 @@ define([
|
|||||||
var question = h('p.cp-faq-questions-q#' + hash);
|
var question = h('p.cp-faq-questions-q#' + hash);
|
||||||
$(question).click(function () {
|
$(question).click(function () {
|
||||||
if ($(answer).is(':visible')) {
|
if ($(answer).is(':visible')) {
|
||||||
|
$(question).toggleClass('cp-active-faq');
|
||||||
return void $(answer).slideUp();
|
return void $(answer).slideUp();
|
||||||
}
|
}
|
||||||
|
$(question).toggleClass('cp-active-faq');
|
||||||
$(answer).slideDown();
|
$(answer).slideDown();
|
||||||
});
|
});
|
||||||
questions.push(h('div.cp-faq-questions-items', [
|
questions.push(h('div.cp-faq-questions-items', [
|
||||||
@ -445,11 +427,15 @@ define([
|
|||||||
}
|
}
|
||||||
return h('div#cp-main', [
|
return h('div#cp-main', [
|
||||||
infopageTopbar(),
|
infopageTopbar(),
|
||||||
h('div.container.cp-container', [
|
h('div.container-fluid.cp-faq', [
|
||||||
|
h('div.container',[
|
||||||
h('center', h('h1', Msg.faq_title)),
|
h('center', h('h1', Msg.faq_title)),
|
||||||
h('p.cp-faq-header', h('a.nav-item.nav-link', {
|
]),
|
||||||
|
]),
|
||||||
|
h('div.container.cp-faq-ques-det',[
|
||||||
|
h('div.cp-faq-header.text-center', h('a.nav-item.nav-link', {
|
||||||
href: '/what-is-cryptpad.html'
|
href: '/what-is-cryptpad.html'
|
||||||
}, Msg.faq_whatis)),
|
}, setHTML(h('h4'),Msg.faq_whatis))),
|
||||||
h('div.cp-faq-container', categories)
|
h('div.cp-faq-container', categories)
|
||||||
]),
|
]),
|
||||||
infopageFooter()
|
infopageFooter()
|
||||||
@ -484,28 +470,28 @@ define([
|
|||||||
h('div.col-12',
|
h('div.col-12',
|
||||||
setHTML(h('h4.text-center'), Msg.main_about_p26)
|
setHTML(h('h4.text-center'), Msg.main_about_p26)
|
||||||
),
|
),
|
||||||
h('div.col-6.col-sm-3.col-md-3.col-lg-3',
|
h('div.col-12.col-sm-6.col-md-3.col-lg-3',
|
||||||
h('a.card', {href : "https://twitter.com/cryptpad"},
|
h('a.card', {href : "https://twitter.com/cryptpad"},
|
||||||
h('div.card-body',
|
h('div.card-body',
|
||||||
setHTML(h('p'), Msg.main_about_p22)
|
setHTML(h('p'), Msg.main_about_p22)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
h('div.col-6.col-sm-3.col-md-3.col-lg-3',
|
h('div.col-12.col-sm-6.col-md-3.col-lg-3',
|
||||||
h('a.card', {href : "https://github.com/xwiki-labs/cryptpad/issues/"},
|
h('a.card', {href : "https://github.com/xwiki-labs/cryptpad/issues/"},
|
||||||
h('div.card-body',
|
h('div.card-body',
|
||||||
setHTML(h('p'), Msg.main_about_p23)
|
setHTML(h('p'), Msg.main_about_p23)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
h('div.col-6.col-sm-3.col-md-3.col-lg-3',
|
h('div.col-12.col-sm-6.col-md-3.col-lg-3',
|
||||||
h('a.card', {href : "https://riot.im/app/#/room/#cryptpad:matrix.org"},
|
h('a.card', {href : "https://riot.im/app/#/room/#cryptpad:matrix.org"},
|
||||||
h('div.card-body',
|
h('div.card-body',
|
||||||
setHTML(h('p'), Msg.main_about_p24)
|
setHTML(h('p'), Msg.main_about_p24)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
h('div.col-6.col-sm-3.col-md-3.col-lg-3',
|
h('div.col-12.col-sm-6.col-md-3.col-lg-3',
|
||||||
h('a.card', {href : "mailto:research@xwiki.com"},
|
h('a.card', {href : "mailto:research@xwiki.com"},
|
||||||
h('div.card-body',
|
h('div.card-body',
|
||||||
setHTML(h('p'), Msg.main_about_p25)
|
setHTML(h('p'), Msg.main_about_p25)
|
||||||
@ -585,13 +571,13 @@ define([
|
|||||||
var showingMore = false;
|
var showingMore = false;
|
||||||
|
|
||||||
var icons = [
|
var icons = [
|
||||||
[ 'pad', '/pad/', Msg.main_richTextPad, 'fa-file-word-o' ],
|
[ 'pad', '/pad/', Msg.main_richTextPad, 'pad' ],
|
||||||
[ 'code', '/code/', Msg.main_codePad, 'fa-file-code-o' ],
|
[ 'code', '/code/', Msg.main_codePad, 'code' ],
|
||||||
[ 'slide', '/slide/', Msg.main_slidePad, 'fa-file-powerpoint-o' ],
|
[ 'slide', '/slide/', Msg.main_slidePad, 'slide' ],
|
||||||
[ 'poll', '/poll/', Msg.main_pollPad, 'fa-calendar' ],
|
[ 'poll', '/poll/', Msg.main_pollPad, 'poll' ],
|
||||||
[ 'kanban', '/kanban/', Msg.main_kanbanPad, 'fa-calendar' ],
|
[ 'kanban', '/kanban/', Msg.main_kanbanPad, 'kanban' ],
|
||||||
[ 'whiteboard', '/whiteboard/', Msg.main_whiteboardPad, 'fa-paint-brush' ],
|
[ 'whiteboard', '/whiteboard/', Msg.main_whiteboardPad, 'whiteboard' ],
|
||||||
[ 'recent', '/drive/', Msg.main_localPads, 'fa-hdd-o' ]
|
[ 'recent', '/drive/', Msg.main_localPads, 'drive' ]
|
||||||
].filter(function (x) {
|
].filter(function (x) {
|
||||||
return isAvailableType(x[1]);
|
return isAvailableType(x[1]);
|
||||||
})
|
})
|
||||||
@ -601,7 +587,7 @@ define([
|
|||||||
return h('a', [
|
return h('a', [
|
||||||
{ href: x[1] },
|
{ href: x[1] },
|
||||||
h(s, [
|
h(s, [
|
||||||
h('i.fa.' + x[3]),
|
h('i.fa.' + AppConfig.applicationsIcon[x[3]]),
|
||||||
h('div.pad-button-text', [ h('h4', x[2]) ])
|
h('div.pad-button-text', [ h('h4', x[2]) ])
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -204,7 +204,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
span.cp-password-container {
|
span.cp-password-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
justify-content: space-between;
|
||||||
|
& > * {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"], input[type="radio"] {
|
input[type="checkbox"], input[type="radio"] {
|
||||||
@ -220,10 +229,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
|
||||||
|
|
||||||
text-align: right;
|
|
||||||
|
|
||||||
button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button) {
|
button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button) {
|
||||||
|
|
||||||
background-color: @colortheme_alertify-cancel;
|
background-color: @colortheme_alertify-cancel;
|
||||||
@ -298,6 +303,9 @@
|
|||||||
button.btn {
|
button.btn {
|
||||||
margin: 6px 4px;
|
margin: 6px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -161,6 +161,9 @@
|
|||||||
background-size: contain;
|
background-size: contain;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
|
@media (max-width: 326px) {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
input {
|
input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
margin-bottom: 0 !important; // Override margin from alertify
|
|
||||||
}
|
}
|
||||||
label, .fa {
|
label, .fa {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
|
|
||||||
.sidebar-layout_main() {
|
.sidebar-layout_main() {
|
||||||
input[type="text"] {
|
input[type="text"], input[type="password"] {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
#cp-sidebarlayout-container {
|
#cp-sidebarlayout-container {
|
||||||
@ -60,7 +60,7 @@
|
|||||||
}
|
}
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
[type="text"], button {
|
[type="text"], [type="password"], button {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@ -5,23 +5,47 @@
|
|||||||
display: none;
|
display: none;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding: 10px 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
* {
|
* {
|
||||||
font: @colortheme_app-font;
|
font: @colortheme_app-font;
|
||||||
}
|
}
|
||||||
.cp-toolbar-history-next {
|
.cp-history-filler {
|
||||||
display: inline-block;
|
flex: 1;
|
||||||
vertical-align: middle;
|
|
||||||
margin: 20px;
|
|
||||||
}
|
}
|
||||||
.cp-toolbar-history-previous {
|
.cp-toolbar-history-close,
|
||||||
display: inline-block;
|
.cp-toolbar-history-revert {
|
||||||
vertical-align: middle;
|
background: white;
|
||||||
margin: 20px;
|
color: black;
|
||||||
|
//margin-top: 5px;
|
||||||
|
&:hover {
|
||||||
|
background-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-toolbar-history-loadmore {
|
||||||
|
height: 100%;
|
||||||
|
color: black;
|
||||||
|
width: 25px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cp-toolbar-history-version {
|
||||||
|
position: absolute;
|
||||||
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
.cp-toolbar-history-goto {
|
.cp-toolbar-history-goto {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
flex: 1;
|
||||||
|
flex-basis: 80%;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 600px;
|
||||||
input { width: 75px; }
|
input { width: 75px; }
|
||||||
}
|
}
|
||||||
.cp-toolbar-history-goto-input {
|
.cp-toolbar-history-goto-input {
|
||||||
@ -29,6 +53,30 @@
|
|||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
.cp-toolbar-history-bar {
|
||||||
|
width: 100%;
|
||||||
|
background: white;
|
||||||
|
height: 25px;
|
||||||
|
margin: auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.cp-toolbar-history-pos-container {
|
||||||
|
width: ~"calc(100% - 2px)";
|
||||||
|
height: 25px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
@pos-color: #55FF55;
|
||||||
|
.cp-toolbar-history-pos {
|
||||||
|
width: 2px;
|
||||||
|
height: 25px;
|
||||||
|
background: @pos-color;
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
border: 6px solid transparent;
|
||||||
|
border-top-color: @pos-color;
|
||||||
|
margin-left: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
button {
|
button {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
background-color: rgba(0,0,0,0.2);
|
background-color: rgba(0,0,0,0.2);
|
||||||
@ -36,14 +84,6 @@
|
|||||||
background-color: rgba(0,0,0,0.4);
|
background-color: rgba(0,0,0,0.4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cp-toolbar-history-close {
|
|
||||||
background: white;
|
|
||||||
color: black;
|
|
||||||
margin-top: 5px;
|
|
||||||
&:hover {
|
|
||||||
background-color: #e6e6e6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fa-spinner {
|
.fa-spinner {
|
||||||
font-size: 66px;
|
font-size: 66px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,10 @@
|
|||||||
@toolbar_top-height: 64px;
|
@toolbar_top-height: 64px;
|
||||||
@toolbar_button-font: @colortheme_app-font;
|
@toolbar_button-font: @colortheme_app-font;
|
||||||
|
|
||||||
|
// if we spell 'share' correctly, then adblock plus hides the share button
|
||||||
|
// this is a workaround
|
||||||
|
.fa-shhare-alt:before { content: "\f1e0"; }
|
||||||
|
|
||||||
.dropdown_main();
|
.dropdown_main();
|
||||||
.ckeditor_fix();
|
.ckeditor_fix();
|
||||||
.history_main();
|
.history_main();
|
||||||
|
|||||||
@ -3,20 +3,49 @@
|
|||||||
|
|
||||||
.infopages_main();
|
.infopages_main();
|
||||||
.infopages_topbar();
|
.infopages_topbar();
|
||||||
|
#cp-main {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.cp-faq {
|
||||||
|
padding-top: 3em;
|
||||||
|
padding-bottom: 3em;
|
||||||
|
background-image: url(/customize/images/cover-faq.jpg);
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
.container {
|
||||||
|
color: #fff;
|
||||||
|
font-family: "Open Sans";
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cp-faq-header {
|
.cp-faq-ques-det {
|
||||||
padding: 0;
|
.cp-faq-header {
|
||||||
font-size: 1.2em;
|
|
||||||
a {
|
a {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
h4 {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
.cp-brand-font {
|
||||||
|
font-family: "Neuropolitical";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cp-faq-container {
|
.cp-faq-container {
|
||||||
|
.cp-faq-questions-items {
|
||||||
|
background: #3a84b6;
|
||||||
|
color: #fff;
|
||||||
|
padding: 1rem 1rem 0.5rem 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
.cp-faq-questions-q {
|
.cp-faq-questions-q {
|
||||||
color: #3a84b6;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0.5rem;
|
||||||
margin-top: 5px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@ -24,14 +53,32 @@
|
|||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: '\f067';
|
||||||
|
font-family: FontAwesome;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
float: right;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-faq-questions-q.active-faq {
|
||||||
|
&:after {
|
||||||
|
content: '\f068';
|
||||||
}
|
}
|
||||||
.cp-faq-questions-q:hover {
|
|
||||||
color: #2e688f;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
}
|
||||||
.cp-faq-questions-a {
|
.cp-faq-questions-a {
|
||||||
display: none;
|
display: none;
|
||||||
padding: 0;
|
padding: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #212529;
|
||||||
}
|
}
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,53 +3,21 @@
|
|||||||
|
|
||||||
.infopages_main();
|
.infopages_main();
|
||||||
.infopages_topbar();
|
.infopages_topbar();
|
||||||
|
#cp-main {
|
||||||
@features_th-bg: #555;
|
background-color: #fff;
|
||||||
@features_th-fg: #fff;
|
}
|
||||||
@features_tr-bg-alt: #ddd;
|
.cp_cont_features {
|
||||||
@features_notes: #333;
|
padding-top: 3em;
|
||||||
@features_yes: #c4ffca;
|
padding-bottom: 3em;
|
||||||
@features_no: #ffc4bc;
|
background-image: url('/customize/images/cover-features.jpg');
|
||||||
@features_part: #faffd3;
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
table#cp-features-table {
|
background-position: center;
|
||||||
width: 100%;
|
h1 {
|
||||||
th {
|
font-weight: 700;
|
||||||
background-color: @features_th-bg;
|
color: #fff;
|
||||||
color: @features_th-fg;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid @features_th-bg;
|
|
||||||
}
|
|
||||||
tbody {
|
|
||||||
td {
|
|
||||||
height: 32px;
|
|
||||||
line-height: 32px;
|
|
||||||
padding: 5px;
|
|
||||||
border: 1px solid @features_th-bg;
|
|
||||||
}
|
|
||||||
tr:nth-child(odd) {
|
|
||||||
background-color: @features_tr-bg-alt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
td:nth-child(4) {
|
|
||||||
color: @features_notes;
|
|
||||||
font-size: 14px;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
td:first-child {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.yes, .no, .part {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.yes { background-color: @features_yes; }
|
|
||||||
.no { background-color: @features_no; }
|
|
||||||
.part { background-color: @features_part; }
|
|
||||||
.left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#cp-features-register {
|
#cp-features-register {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@ -62,6 +30,57 @@ table#cp-features-table {
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
.cp-features-web {
|
||||||
|
.card {
|
||||||
|
box-shadow: 0 5px 15px rgba(69, 145, 196, 0.3);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.list-group {
|
||||||
|
li {
|
||||||
|
&:before {
|
||||||
|
content: "\f00c";
|
||||||
|
font-family: "FontAwesome";
|
||||||
|
font-size: 14px;
|
||||||
|
color: @cryptpad_color_blue;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.voted {
|
||||||
|
opacity: 0.6;
|
||||||
|
margin-left: 15px;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-group-item {
|
||||||
|
border-color: rgba(69, 145, 196, 0.125);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-anon-user {
|
||||||
|
.card-body {
|
||||||
|
background-color: @cryptpad_color_blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-regis-user {
|
||||||
|
@media (max-width:575px) {
|
||||||
|
margin-top: 3em;
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
&:first-of-type {
|
||||||
|
background: #4591C4;
|
||||||
|
background: -webkit-linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false
|
||||||
|
background: linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,3 +3,46 @@
|
|||||||
|
|
||||||
.infopages_main();
|
.infopages_main();
|
||||||
.infopages_topbar();
|
.infopages_topbar();
|
||||||
|
#cp-main {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.cp-privacy-top {
|
||||||
|
padding-top: 3em;
|
||||||
|
padding-bottom: 3em;
|
||||||
|
background-image: url(/customize/images/cover-privacy.jpg);
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
.container {
|
||||||
|
color: #fff;
|
||||||
|
font-family: "Open Sans";
|
||||||
|
h1 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-privacy {
|
||||||
|
background-image: url(/customize/CryptPadlogo_op5.svg);
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
hr {
|
||||||
|
margin-left: 0;
|
||||||
|
width: 15rem;
|
||||||
|
border-top: 2px solid #4591C4;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
color: #1E1F1F;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: #3F4141;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -780,7 +780,7 @@
|
|||||||
|
|
||||||
out.faq_link = "FAQ";
|
out.faq_link = "FAQ";
|
||||||
out.faq_title = "Häufigste Fragen";
|
out.faq_title = "Häufigste Fragen";
|
||||||
out.faq_whatis = "Was ist CryptPad?";
|
out.faq_whatis = "Was ist <span class='cp-brand-font'>CryptPad</span>?";
|
||||||
out.faq = {};
|
out.faq = {};
|
||||||
out.faq.keywords = {
|
out.faq.keywords = {
|
||||||
title: 'Schlüsselkonzepte',
|
title: 'Schlüsselkonzepte',
|
||||||
|
|||||||
@ -39,6 +39,8 @@ define(function () {
|
|||||||
'Appuyez sur <em>Échap</em> pour voir le pad ou rechargez la page pour pouvoir le modifier à nouveau.';
|
'Appuyez sur <em>Échap</em> pour voir le pad ou rechargez la page pour pouvoir le modifier à nouveau.';
|
||||||
out.errorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur <em>Échap</em>.<br> Dés que vous aurez quitté la page, il sera impossible de le récupérer.';
|
out.errorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur <em>Échap</em>.<br> Dés que vous aurez quitté la page, il sera impossible de le récupérer.';
|
||||||
out.errorRedirectToHome = 'Appuyez sur <em>Échap</em> pour retourner vers votre CryptDrive.';
|
out.errorRedirectToHome = 'Appuyez sur <em>Échap</em> pour retourner vers votre CryptDrive.';
|
||||||
|
out.newVersionError = "Une nouvelle version de CryptPad est disponible.<br>" +
|
||||||
|
"<a href='#'>Rechargez la page</a> pour utiliser la nouvelle version, ou appuyez sur Échap pour accéder au contenu actuel en <b>mode hors-ligne</b>.";
|
||||||
|
|
||||||
out.loading = "Chargement...";
|
out.loading = "Chargement...";
|
||||||
out.error = "Erreur";
|
out.error = "Erreur";
|
||||||
@ -230,12 +232,11 @@ define(function () {
|
|||||||
|
|
||||||
out.historyText = "Historique";
|
out.historyText = "Historique";
|
||||||
out.historyButton = "Afficher l'historique du document";
|
out.historyButton = "Afficher l'historique du document";
|
||||||
out.history_next = "Voir la version suivante";
|
out.history_next = "Version plus récente";
|
||||||
out.history_prev = "Voir la version précédente";
|
out.history_prev = "Version plus ancienne";
|
||||||
out.history_goTo = "Voir la version sélectionnée";
|
out.history_loadMore = "Charger davantage d'historique";
|
||||||
out.history_close = "Retour";
|
out.history_close = "Retour";
|
||||||
out.history_closeTitle = "Fermer l'historique";
|
out.history_closeTitle = "Fermer l'historique";
|
||||||
out.history_restore = "Restaurer";
|
|
||||||
out.history_restoreTitle = "Restaurer la version du document sélectionnée";
|
out.history_restoreTitle = "Restaurer la version du document sélectionnée";
|
||||||
out.history_restorePrompt = "Êtes-vous sûr de vouloir remplacer la version actuelle du document par la version affichée ?";
|
out.history_restorePrompt = "Êtes-vous sûr de vouloir remplacer la version actuelle du document par la version affichée ?";
|
||||||
out.history_restoreDone = "Document restauré";
|
out.history_restoreDone = "Document restauré";
|
||||||
@ -616,7 +617,7 @@ define(function () {
|
|||||||
out.upload_mustLogin = "Vous devez vous connecter pour importer un fichier";
|
out.upload_mustLogin = "Vous devez vous connecter pour importer un fichier";
|
||||||
out.download_button = "Déchiffrer et télécharger";
|
out.download_button = "Déchiffrer et télécharger";
|
||||||
out.download_mt_button = "Télécharger";
|
out.download_mt_button = "Télécharger";
|
||||||
out.download_resourceNotAvailable = "Le fichier demandé n'est pas disponible...";
|
out.download_resourceNotAvailable = "Le fichier demandé n'est pas disponible... Appuyez sur Échap pour continuer.";
|
||||||
|
|
||||||
out.todo_title = "CryptTodo";
|
out.todo_title = "CryptTodo";
|
||||||
out.todo_newTodoNamePlaceholder = "Décrivez votre tâche...";
|
out.todo_newTodoNamePlaceholder = "Décrivez votre tâche...";
|
||||||
@ -673,6 +674,7 @@ define(function () {
|
|||||||
out.main_slidePad = 'Présentation Markdown';
|
out.main_slidePad = 'Présentation Markdown';
|
||||||
out.main_pollPad = 'Sondage ou Planning';
|
out.main_pollPad = 'Sondage ou Planning';
|
||||||
out.main_whiteboardPad = 'Tableau blanc';
|
out.main_whiteboardPad = 'Tableau blanc';
|
||||||
|
out.main_kanbanPad = 'Kanban';
|
||||||
out.main_localPads = 'Pads Locaux';
|
out.main_localPads = 'Pads Locaux';
|
||||||
out.main_yourCryptDrive = 'Votre CryptDrive';
|
out.main_yourCryptDrive = 'Votre CryptDrive';
|
||||||
out.main_footerText = "Avec CryptPad, vous pouvez créer des documents collaboratifs rapidement pour prendre des notes à plusieurs.";
|
out.main_footerText = "Avec CryptPad, vous pouvez créer des documents collaboratifs rapidement pour prendre des notes à plusieurs.";
|
||||||
@ -741,8 +743,8 @@ define(function () {
|
|||||||
out.features_f_history = "Historique";
|
out.features_f_history = "Historique";
|
||||||
out.features_f_history_notes = "Voir et restaurer n'importe quelle version d'un pad";
|
out.features_f_history_notes = "Voir et restaurer n'importe quelle version d'un pad";
|
||||||
out.features_f_todo = "Créer une TODO-list";
|
out.features_f_todo = "Créer une TODO-list";
|
||||||
out.features_f_drive = "CryptDrive";
|
out.features_f_drive = "Fonctionnalités CryptDrive limitées";
|
||||||
out.features_f_drive_notes = "Fonctionnalités basiques pour les utilisateurs anonymes";
|
out.features_f_drive_full = "Fonctionnalités CryptDrive limitées";
|
||||||
out.features_f_export = "Export/Import";
|
out.features_f_export = "Export/Import";
|
||||||
out.features_f_export_notes = "Pour les pads et CryptDrive";
|
out.features_f_export_notes = "Pour les pads et CryptDrive";
|
||||||
out.features_f_viewFiles = "Voir des fichiers";
|
out.features_f_viewFiles = "Voir des fichiers";
|
||||||
@ -753,7 +755,7 @@ define(function () {
|
|||||||
out.features_f_multiple_notes = "Moyen facile de voir vos pads depuis n'importe quel appareil";
|
out.features_f_multiple_notes = "Moyen facile de voir vos pads depuis n'importe quel appareil";
|
||||||
out.features_f_logoutEverywhere = "Se déconnecter partout";
|
out.features_f_logoutEverywhere = "Se déconnecter partout";
|
||||||
out.features_f_logoutEverywhere_notes = "Se déconnecter des autres appareils utilisés";
|
out.features_f_logoutEverywhere_notes = "Se déconnecter des autres appareils utilisés";
|
||||||
out.features_f_templates = "Modèles";
|
out.features_f_templates = "Utiliser les modèles";
|
||||||
out.features_f_templates_notes = "Créer des modèles et créer des pads basés sur ces modèles";
|
out.features_f_templates_notes = "Créer des modèles et créer des pads basés sur ces modèles";
|
||||||
out.features_f_profile = "Créer un profil";
|
out.features_f_profile = "Créer un profil";
|
||||||
out.features_f_profile_notes = "Page personnelle contenant un avatar et une description";
|
out.features_f_profile_notes = "Page personnelle contenant un avatar et une description";
|
||||||
@ -764,12 +766,13 @@ define(function () {
|
|||||||
out.features_f_storage = "Stockage";
|
out.features_f_storage = "Stockage";
|
||||||
out.features_f_storage_anon = "Pads supprimés après 3 mois";
|
out.features_f_storage_anon = "Pads supprimés après 3 mois";
|
||||||
out.features_f_storage_registered = "Gratuit: 50Mo<br>Premium: 5Go/20Go/50Go";
|
out.features_f_storage_registered = "Gratuit: 50Mo<br>Premium: 5Go/20Go/50Go";
|
||||||
|
out.features_f_register = "S'inscrire gratuitement";
|
||||||
|
|
||||||
// faq.html
|
// faq.html
|
||||||
|
|
||||||
out.faq_link = "FAQ";
|
out.faq_link = "FAQ";
|
||||||
out.faq_title = "Foire Aux Questions";
|
out.faq_title = "Foire Aux Questions";
|
||||||
out.faq_whatis = "Qu'est-ce que CryptPad ?";
|
out.faq_whatis = "Qu'est-ce que <span class='cp-brand-font'>CryptPad</span> ?";
|
||||||
out.faq = {};
|
out.faq = {};
|
||||||
out.faq.keywords = {
|
out.faq.keywords = {
|
||||||
title: 'Termes spéciaux',
|
title: 'Termes spéciaux',
|
||||||
@ -1113,6 +1116,16 @@ define(function () {
|
|||||||
out.password_submit = "Valider";
|
out.password_submit = "Valider";
|
||||||
out.password_show = "Afficher";
|
out.password_show = "Afficher";
|
||||||
|
|
||||||
|
// Change password in pad properties
|
||||||
|
out.properties_addPassword = "Ajouter un mot de passe";
|
||||||
|
out.properties_changePassword = "Modifier le mot de passe";
|
||||||
|
out.properties_confirmNew = "Êtes-vous sûr ? Ajouter un mot de passe changera l'URL de ce pad. Les utilisateurs ne connaissant pas le nouveau mot de passe perdront l'accès au pad.";
|
||||||
|
out.properties_confirmChange = "Êtes-vous sûr ? Les utilisateurs ne connaissant pas le nouveau mot de passe perdront l'accès au pad.";
|
||||||
|
out.properties_passwordError = "Une erreur est survenue lors de la modification du mot de passe. Veuillez réessayer.";
|
||||||
|
out.properties_passwordWarning = "Le mot de passe a été modifié avec succès mais nous n'avons pas réussi à mettre à jour votre CryptDrive avec les nouvelles informations. Vous devrez peut-être supprimer manuellement l'ancienne version de ce pad.<br>Appuyez sur OK pour recharger le pad et mettre à jour vos droits d'accès.";
|
||||||
|
out.properties_passwordSuccess = "Le mot de passe a été modifié avec succès.<br>Appuyez sur OK pour mettre à jour vos droits d'accès.";
|
||||||
|
out.properties_changePasswordButton = "Valider";
|
||||||
|
|
||||||
// New share modal
|
// New share modal
|
||||||
out.share_linkCategory = "Partage";
|
out.share_linkCategory = "Partage";
|
||||||
out.share_linkAccess = "Droits d'accès";
|
out.share_linkAccess = "Droits d'accès";
|
||||||
|
|||||||
@ -40,6 +40,8 @@ define(function () {
|
|||||||
'Hit <em>Esc</em> to continue to view this pad, or reload to try editing again.';
|
'Hit <em>Esc</em> to continue to view this pad, or reload to try editing again.';
|
||||||
out.errorCopy = ' You can still copy the content to another location by pressing <em>Esc</em>.<br>Once you leave this page, it will disappear forever!';
|
out.errorCopy = ' You can still copy the content to another location by pressing <em>Esc</em>.<br>Once you leave this page, it will disappear forever!';
|
||||||
out.errorRedirectToHome = 'Press <em>Esc</em> to be redirected to your CryptDrive.';
|
out.errorRedirectToHome = 'Press <em>Esc</em> to be redirected to your CryptDrive.';
|
||||||
|
out.newVersionError = "A new version of CryptPad is available.<br>" +
|
||||||
|
"<a href='#'>Reload</a> to use the new version, or press escape to access your content in <b>offline mode</b>.";
|
||||||
|
|
||||||
out.loading = "Loading...";
|
out.loading = "Loading...";
|
||||||
out.error = "Error";
|
out.error = "Error";
|
||||||
@ -232,12 +234,10 @@ define(function () {
|
|||||||
|
|
||||||
out.historyText = "History";
|
out.historyText = "History";
|
||||||
out.historyButton = "Display the document history";
|
out.historyButton = "Display the document history";
|
||||||
out.history_next = "Go to the next version";
|
out.history_next = "Newer version";
|
||||||
out.history_prev = "Go to the previous version";
|
out.history_prev = "Older version";
|
||||||
out.history_goTo = "Go to the selected version";
|
out.history_loadMore = "Load more history";
|
||||||
out.history_close = "Back";
|
|
||||||
out.history_closeTitle = "Close the history";
|
out.history_closeTitle = "Close the history";
|
||||||
out.history_restore = "Restore";
|
|
||||||
out.history_restoreTitle = "Restore the selected version of the document";
|
out.history_restoreTitle = "Restore the selected version of the document";
|
||||||
out.history_restorePrompt = "Are you sure you want to replace the current version of the document by the displayed one?";
|
out.history_restorePrompt = "Are you sure you want to replace the current version of the document by the displayed one?";
|
||||||
out.history_restoreDone = "Document restored";
|
out.history_restoreDone = "Document restored";
|
||||||
@ -600,6 +600,15 @@ define(function () {
|
|||||||
out.settings_templateSkip = "Skip the template selection modal";
|
out.settings_templateSkip = "Skip the template selection modal";
|
||||||
out.settings_templateSkipHint = "When you create a new empty pad, if you have stored templates for this type of pad, a modal appears to ask if you want to use a template. Here you can choose to never show this modal and so to never use a template.";
|
out.settings_templateSkipHint = "When you create a new empty pad, if you have stored templates for this type of pad, a modal appears to ask if you want to use a template. Here you can choose to never show this modal and so to never use a template.";
|
||||||
|
|
||||||
|
out.settings_changePasswordTitle = "Change your password"; // XXX
|
||||||
|
out.settings_changePasswordHint = "Change your account's password without losing its data. You have to enter your existing password once, and the new password you want twice.<br>" +
|
||||||
|
"<b>We can't reset your password if you forget it so be very careful!</b>"; // XXX
|
||||||
|
out.settings_changePasswordButton = "Change password"; // XXX
|
||||||
|
out.settings_changePasswordCurrent = "Existing password"; // XXX
|
||||||
|
out.settings_changePasswordNew = "New password"; // XXX
|
||||||
|
out.settings_changePasswordNewConfirm = "Confirm new password"; // XXX
|
||||||
|
out.settings_changePasswordConfirm = "Are you sure?"; // XXX
|
||||||
|
|
||||||
out.upload_title = "File upload";
|
out.upload_title = "File upload";
|
||||||
out.upload_modal_title = "File upload options";
|
out.upload_modal_title = "File upload options";
|
||||||
out.upload_modal_filename = "File name (extension <em>{0}</em> added automatically)";
|
out.upload_modal_filename = "File name (extension <em>{0}</em> added automatically)";
|
||||||
@ -620,7 +629,7 @@ define(function () {
|
|||||||
out.upload_mustLogin = "You must be logged in to upload files";
|
out.upload_mustLogin = "You must be logged in to upload files";
|
||||||
out.download_button = "Decrypt & Download";
|
out.download_button = "Decrypt & Download";
|
||||||
out.download_mt_button = "Download";
|
out.download_mt_button = "Download";
|
||||||
out.download_resourceNotAvailable = "The requested resource was not available...";
|
out.download_resourceNotAvailable = "The requested resource was not available... Press Esc to continue.";
|
||||||
|
|
||||||
out.todo_title = "CryptTodo";
|
out.todo_title = "CryptTodo";
|
||||||
out.todo_newTodoNamePlaceholder = "Describe your task...";
|
out.todo_newTodoNamePlaceholder = "Describe your task...";
|
||||||
@ -678,6 +687,7 @@ define(function () {
|
|||||||
out.main_slidePad = 'Markdown Presentation';
|
out.main_slidePad = 'Markdown Presentation';
|
||||||
out.main_pollPad = 'Poll or Schedule';
|
out.main_pollPad = 'Poll or Schedule';
|
||||||
out.main_whiteboardPad = 'Whiteboard';
|
out.main_whiteboardPad = 'Whiteboard';
|
||||||
|
out.main_kanbanPad = 'Kanban';
|
||||||
out.main_localPads = 'Local Pads';
|
out.main_localPads = 'Local Pads';
|
||||||
out.main_yourCryptDrive = 'Your CryptDrive';
|
out.main_yourCryptDrive = 'Your CryptDrive';
|
||||||
out.main_footerText = "With CryptPad, you can make quick collaborative documents for taking notes and writing down ideas together.";
|
out.main_footerText = "With CryptPad, you can make quick collaborative documents for taking notes and writing down ideas together.";
|
||||||
@ -746,8 +756,8 @@ define(function () {
|
|||||||
out.features_f_history = "History";
|
out.features_f_history = "History";
|
||||||
out.features_f_history_notes = "View and restore any version of your pads";
|
out.features_f_history_notes = "View and restore any version of your pads";
|
||||||
out.features_f_todo = "Create a TODO-list";
|
out.features_f_todo = "Create a TODO-list";
|
||||||
out.features_f_drive = "CryptDrive";
|
out.features_f_drive = "Limited CryptDrive functionality";
|
||||||
out.features_f_drive_notes = "Basic features for anonymous users";
|
out.features_f_drive_full = "Complete CryptDrive functionality";
|
||||||
out.features_f_export = "Export/Import";
|
out.features_f_export = "Export/Import";
|
||||||
out.features_f_export_notes = "For pads and CryptDrive";
|
out.features_f_export_notes = "For pads and CryptDrive";
|
||||||
out.features_f_viewFiles = "View files";
|
out.features_f_viewFiles = "View files";
|
||||||
@ -767,14 +777,15 @@ define(function () {
|
|||||||
out.features_f_contacts = "Contacts application";
|
out.features_f_contacts = "Contacts application";
|
||||||
out.features_f_contacts_notes = "Add contacts and chat with them in an encrypted session";
|
out.features_f_contacts_notes = "Add contacts and chat with them in an encrypted session";
|
||||||
out.features_f_storage = "Storage";
|
out.features_f_storage = "Storage";
|
||||||
out.features_f_storage_anon = "Pads deleted after 3 months";
|
out.features_f_storage_anon = "Pads are deleted after 3 months";
|
||||||
out.features_f_storage_registered = "Free: 50MB<br>Premium: 5GB/20GB/50GB";
|
out.features_f_storage_registered = "Free: 50MB<br>Premium: 5GB/20GB/50GB";
|
||||||
|
out.features_f_register = "Register for free";
|
||||||
|
|
||||||
// faq.html
|
// faq.html
|
||||||
|
|
||||||
out.faq_link = "FAQ";
|
out.faq_link = "FAQ";
|
||||||
out.faq_title = "Frequently Asked Questions";
|
out.faq_title = "Frequently Asked Questions";
|
||||||
out.faq_whatis = "What is CryptPad?";
|
out.faq_whatis = "What is <span class='cp-brand-font'>CryptPad</span>?";
|
||||||
out.faq = {};
|
out.faq = {};
|
||||||
out.faq.keywords = {
|
out.faq.keywords = {
|
||||||
title: 'Keywords',
|
title: 'Keywords',
|
||||||
@ -1151,13 +1162,23 @@ define(function () {
|
|||||||
out.creation_newPadModalDescriptionAdvanced = "You can check the box (or press <b>Space</b> to change its value) if you want to display the pad creation screen (for owned pads, expiring pads, etc.).";
|
out.creation_newPadModalDescriptionAdvanced = "You can check the box (or press <b>Space</b> to change its value) if you want to display the pad creation screen (for owned pads, expiring pads, etc.).";
|
||||||
out.creation_newPadModalAdvanced = "Display the pad creation screen";
|
out.creation_newPadModalAdvanced = "Display the pad creation screen";
|
||||||
|
|
||||||
// Password prompt on the loadind screen
|
// Password prompt on the loading screen
|
||||||
out.password_info = "The pad you're tyring to open is protected with a password. Enter the correct password to access its content.";
|
out.password_info = "The pad you're trying to open is protected with a password. Enter the correct password to access its content.";
|
||||||
out.password_error = "Pad not found!<br>This error can be caused by two factors: either the password in invalid, or the pad has been deleted from the server.";
|
out.password_error = "Pad not found!<br>This error can be caused by two factors: either the password in invalid, or the pad has been deleted from the server.";
|
||||||
out.password_placeholder = "Type the password here...";
|
out.password_placeholder = "Type the password here...";
|
||||||
out.password_submit = "Submit";
|
out.password_submit = "Submit";
|
||||||
out.password_show = "Show";
|
out.password_show = "Show";
|
||||||
|
|
||||||
|
// Change password in pad properties
|
||||||
|
out.properties_addPassword = "Add a password";
|
||||||
|
out.properties_changePassword = "Change the password";
|
||||||
|
out.properties_confirmNew = "Are you sure? Adding a password will change this pad's URL. Users without the password will lose access to this pad";
|
||||||
|
out.properties_confirmChange = "Are you sure? Users without the new password will lose access to this pad";
|
||||||
|
out.properties_passwordError = "An error occured while trying to change the password. Please try again.";
|
||||||
|
out.properties_passwordWarning = "The password was successfully changed but we were unable to update your CryptDrive with the new data. You may have to remove the old version of the pad manually.<br>Press OK to reload and update your acces rights.";
|
||||||
|
out.properties_passwordSuccess = "The password was successfully changed.<br>Press OK to reload and update your access rights.";
|
||||||
|
out.properties_changePasswordButton = "Submit";
|
||||||
|
|
||||||
// New share modal
|
// New share modal
|
||||||
out.share_linkCategory = "Share link";
|
out.share_linkCategory = "Share link";
|
||||||
out.share_linkAccess = "Access rights";
|
out.share_linkAccess = "Access rights";
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "cryptpad",
|
"name": "cryptpad",
|
||||||
"description": "realtime collaborative visual editor with zero knowlege server",
|
"description": "realtime collaborative visual editor with zero knowlege server",
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chainpad-server": "^2.0.0",
|
"chainpad-server": "^2.0.0",
|
||||||
|
|||||||
15
rpc.js
15
rpc.js
@ -896,13 +896,13 @@ var removeOwnedBlob = function (Env, blobId, unsafeKey, cb) {
|
|||||||
Fs.unlink(blobPath, w(function (e) {
|
Fs.unlink(blobPath, w(function (e) {
|
||||||
if (e) {
|
if (e) {
|
||||||
w.abort();
|
w.abort();
|
||||||
return void cb(e);
|
return void cb(e.code);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
// Delete the proof of ownership
|
// Delete the proof of ownership
|
||||||
Fs.unlink(ownPath, function (e) {
|
Fs.unlink(ownPath, function (e) {
|
||||||
cb(e);
|
cb(e && e.code);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -1204,7 +1204,7 @@ var owned_upload_complete = function (Env, safeKey, id, cb) {
|
|||||||
return void cb();
|
return void cb();
|
||||||
} else {
|
} else {
|
||||||
// it failed in an unexpected way. log it
|
// it failed in an unexpected way. log it
|
||||||
WARN(e, 'ownedUploadComplete');
|
WARN('ownedUploadComplete', e);
|
||||||
return void cb(e.code);
|
return void cb(e.code);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1221,13 +1221,13 @@ var owned_upload_complete = function (Env, safeKey, id, cb) {
|
|||||||
Mkdirp(filePath, w(function (e /*, path */) {
|
Mkdirp(filePath, w(function (e /*, path */) {
|
||||||
if (e) { // does not throw error if the directory already existed
|
if (e) { // does not throw error if the directory already existed
|
||||||
w.abort();
|
w.abort();
|
||||||
return void cb(e);
|
return void cb(e.code);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
Mkdirp(ownPath, w(function (e /*, path */) {
|
Mkdirp(ownPath, w(function (e /*, path */) {
|
||||||
if (e) { // does not throw error if the directory already existed
|
if (e) { // does not throw error if the directory already existed
|
||||||
w.abort();
|
w.abort();
|
||||||
return void cb(e);
|
return void cb(e.code);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
@ -1254,12 +1254,11 @@ var owned_upload_complete = function (Env, safeKey, id, cb) {
|
|||||||
|
|
||||||
// flow is dumb and I need to guard against this which will never happen
|
// flow is dumb and I need to guard against this which will never happen
|
||||||
/*:: if (typeof(oldPath) === 'object') { throw new Error('should never happen'); } */
|
/*:: if (typeof(oldPath) === 'object') { throw new Error('should never happen'); } */
|
||||||
Fs.rename(oldPath /* XXX */, finalPath, w(function (e) {
|
Fs.rename(oldPath, finalPath, w(function (e) {
|
||||||
if (e) {
|
if (e) {
|
||||||
// Remove the ownership file
|
// Remove the ownership file
|
||||||
// XXX not needed if we have a cleanup script?
|
|
||||||
Fs.unlink(finalOwnPath, function (e) {
|
Fs.unlink(finalOwnPath, function (e) {
|
||||||
WARN(e, 'Removing ownership file ownedUploadComplete');
|
WARN('E_UNLINK_OWN_FILE', e);
|
||||||
});
|
});
|
||||||
w.abort();
|
w.abort();
|
||||||
return void cb(e.code);
|
return void cb(e.code);
|
||||||
|
|||||||
@ -9,7 +9,8 @@ define([
|
|||||||
'/common/common-thumbnail.js',
|
'/common/common-thumbnail.js',
|
||||||
'/common/wire.js',
|
'/common/wire.js',
|
||||||
'/common/flat-dom.js',
|
'/common/flat-dom.js',
|
||||||
], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat) {
|
'/common/media-tag.js',
|
||||||
|
], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat, MediaTag) {
|
||||||
window.Hyperjson = Hyperjson;
|
window.Hyperjson = Hyperjson;
|
||||||
window.Sortify = Sortify;
|
window.Sortify = Sortify;
|
||||||
|
|
||||||
@ -295,6 +296,26 @@ define([
|
|||||||
!secret.hashData.present);
|
!secret.hashData.present);
|
||||||
}, "test support for ugly tracking query paramaters in url");
|
}, "test support for ugly tracking query paramaters in url");
|
||||||
|
|
||||||
|
assert(function (cb) {
|
||||||
|
try {
|
||||||
|
MediaTag(void 0).on('progress').on('decryption');
|
||||||
|
return void cb(true);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return void cb(false);
|
||||||
|
}
|
||||||
|
}, 'check that MediaTag does the right thing when passed no value');
|
||||||
|
|
||||||
|
assert(function (cb) {
|
||||||
|
try {
|
||||||
|
MediaTag(document.createElement('div')).on('progress').on('decryption');
|
||||||
|
return void cb(true);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return void cb(false);
|
||||||
|
}
|
||||||
|
}, 'check that MediaTag does the right thing when passed no value');
|
||||||
|
|
||||||
assert(function (cb) {
|
assert(function (cb) {
|
||||||
// TODO
|
// TODO
|
||||||
return cb(true);
|
return cb(true);
|
||||||
|
|||||||
@ -49,6 +49,7 @@ define([
|
|||||||
if (ua[0].indexOf(':') === -1 && ua[0].indexOf('/') && parent) {
|
if (ua[0].indexOf(':') === -1 && ua[0].indexOf('/') && parent) {
|
||||||
ua[0] = parent.replace(/\/[^\/]*$/, '/') + ua[0];
|
ua[0] = parent.replace(/\/[^\/]*$/, '/') + ua[0];
|
||||||
}
|
}
|
||||||
|
ua[0] = ua[0].replace(/^\/\.\.\//, '/');
|
||||||
var out = ua.join('#');
|
var out = ua.join('#');
|
||||||
//console.log(url + " --> " + out);
|
//console.log(url + " --> " + out);
|
||||||
return out;
|
return out;
|
||||||
@ -91,17 +92,32 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
var lessEngine;
|
var lessEngine;
|
||||||
|
var tempCache = { key: Math.random() };
|
||||||
var getLessEngine = function (cb) {
|
var getLessEngine = function (cb) {
|
||||||
if (lessEngine) {
|
if (lessEngine) {
|
||||||
cb(lessEngine);
|
cb(lessEngine);
|
||||||
} else {
|
} else {
|
||||||
require(['/bower_components/less/dist/less.min.js'], function (Less) {
|
require(['/bower_components/less/dist/less.min.js'], function (Less) {
|
||||||
|
if (lessEngine) { return void cb(lessEngine); }
|
||||||
lessEngine = Less;
|
lessEngine = Less;
|
||||||
var doXHR = lessEngine.FileManager.prototype.doXHR;
|
var doXHR = lessEngine.FileManager.prototype.doXHR;
|
||||||
lessEngine.FileManager.prototype.doXHR = function (url, type, callback, errback) {
|
lessEngine.FileManager.prototype.doXHR = function (url, type, callback, errback) {
|
||||||
url = fixURL(url);
|
url = fixURL(url);
|
||||||
//console.log("xhr: " + url);
|
var cached = tempCache[url];
|
||||||
return doXHR(url, type, callback, errback);
|
if (cached && cached.res) {
|
||||||
|
var res = cached.res;
|
||||||
|
return void setTimeout(function () { callback(res[0], res[1]); });
|
||||||
|
}
|
||||||
|
if (cached) { return void cached.queue.push(callback); }
|
||||||
|
cached = tempCache[url] = { queue: [ callback ], res: undefined };
|
||||||
|
return doXHR(url, type, function (text, lastModified) {
|
||||||
|
cached.res = [ text, lastModified ];
|
||||||
|
var queue = cached.queue;
|
||||||
|
cached.queue = [];
|
||||||
|
queue.forEach(function (f) {
|
||||||
|
setTimeout(function () { f(text, lastModified); });
|
||||||
|
});
|
||||||
|
}, errback);
|
||||||
};
|
};
|
||||||
cb(lessEngine);
|
cb(lessEngine);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -81,7 +81,8 @@ define(function() {
|
|||||||
whiteboard: 'fa-paint-brush',
|
whiteboard: 'fa-paint-brush',
|
||||||
todo: 'fa-tasks',
|
todo: 'fa-tasks',
|
||||||
contacts: 'fa-users',
|
contacts: 'fa-users',
|
||||||
kanban: 'fa-list-alt',
|
kanban: 'fa-columns',
|
||||||
|
drive: 'fa-hdd-o',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ability to create owned pads and expiring pads through a new pad creation screen.
|
// Ability to create owned pads and expiring pads through a new pad creation screen.
|
||||||
|
|||||||
@ -144,13 +144,15 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
dialog.frame = function (content) {
|
dialog.frame = function (content) {
|
||||||
return h('div.alertify', {
|
return $(h('div.alertify', {
|
||||||
tabindex: 1,
|
tabindex: 1,
|
||||||
}, [
|
}, [
|
||||||
h('div.dialog', [
|
h('div.dialog', [
|
||||||
h('div', content),
|
h('div', content),
|
||||||
])
|
])
|
||||||
]);
|
])).click(function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
})[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -624,6 +626,7 @@ define([
|
|||||||
h('p.cp-loading-progress-drive'),
|
h('p.cp-loading-progress-drive'),
|
||||||
h('p.cp-loading-progress-pad')
|
h('p.cp-loading-progress-pad')
|
||||||
]);
|
]);
|
||||||
|
$(progress).hide();
|
||||||
$loading.find('.cp-loading-container').append(progress);
|
$loading.find('.cp-loading-container').append(progress);
|
||||||
} else if (config.noProgress) {
|
} else if (config.noProgress) {
|
||||||
$loading.find('.cp-loading-progress').remove();
|
$loading.find('.cp-loading-progress').remove();
|
||||||
@ -645,6 +648,7 @@ define([
|
|||||||
UI.updateLoadingProgress = function (data, isDrive) {
|
UI.updateLoadingProgress = function (data, isDrive) {
|
||||||
var $loading = $('#' + LOADING);
|
var $loading = $('#' + LOADING);
|
||||||
if (!$loading.length || loading.error) { return; }
|
if (!$loading.length || loading.error) { return; }
|
||||||
|
$loading.find('.cp-loading-progress').show();
|
||||||
var $progress;
|
var $progress;
|
||||||
if (isDrive) {
|
if (isDrive) {
|
||||||
// Drive state
|
// Drive state
|
||||||
|
|||||||
@ -89,7 +89,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Used to accept friend requests within apps other than /contacts/ */
|
/* Used to accept friend requests within apps other than /contacts/ */
|
||||||
Msg.addDirectMessageHandler = function (cfg) {
|
Msg.addDirectMessageHandler = function (cfg, href) {
|
||||||
var network = cfg.network;
|
var network = cfg.network;
|
||||||
var proxy = cfg.proxy;
|
var proxy = cfg.proxy;
|
||||||
if (!network) { return void console.error('Network not ready'); }
|
if (!network) { return void console.error('Network not ready'); }
|
||||||
@ -97,13 +97,12 @@ define([
|
|||||||
var msg;
|
var msg;
|
||||||
if (sender === network.historyKeeper) { return; }
|
if (sender === network.historyKeeper) { return; }
|
||||||
try {
|
try {
|
||||||
var parsed = Hash.parsePadUrl(window.location.href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash);
|
||||||
if (!parsed.hashData) { return; }
|
if (!parsed.hashData) { return; }
|
||||||
var chan = Hash.hrefToHexChannelId(window.location.href);
|
var chan = secret.channel;
|
||||||
// Decrypt
|
// Decrypt
|
||||||
var keyStr = parsed.hashData.key;
|
var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key);
|
||||||
var cryptor = Crypto.createEditCryptor(keyStr);
|
|
||||||
var key = cryptor.cryptKey;
|
|
||||||
var decryptMsg;
|
var decryptMsg;
|
||||||
try {
|
try {
|
||||||
decryptMsg = Crypto.decrypt(message, key);
|
decryptMsg = Crypto.decrypt(message, key);
|
||||||
@ -197,15 +196,14 @@ define([
|
|||||||
var network = cfg.network;
|
var network = cfg.network;
|
||||||
var netfluxId = data.netfluxId;
|
var netfluxId = data.netfluxId;
|
||||||
var parsed = Hash.parsePadUrl(data.href);
|
var parsed = Hash.parsePadUrl(data.href);
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash);
|
||||||
if (!parsed.hashData) { return; }
|
if (!parsed.hashData) { return; }
|
||||||
// Message
|
// Message
|
||||||
var chan = Hash.hrefToHexChannelId(data.href);
|
var chan = secret.channel;
|
||||||
var myData = createData(cfg.proxy);
|
var myData = createData(cfg.proxy);
|
||||||
var msg = ["FRIEND_REQ", chan, myData];
|
var msg = ["FRIEND_REQ", chan, myData];
|
||||||
// Encryption
|
// Encryption
|
||||||
var keyStr = parsed.hashData.key;
|
var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key);
|
||||||
var cryptor = Crypto.createEditCryptor(keyStr);
|
|
||||||
var key = cryptor.cryptKey;
|
|
||||||
var msgStr = Crypto.encrypt(JSON.stringify(msg), key);
|
var msgStr = Crypto.encrypt(JSON.stringify(msg), key);
|
||||||
// Send encrypted message
|
// Send encrypted message
|
||||||
if (pendingRequests.indexOf(netfluxId) === -1) {
|
if (pendingRequests.indexOf(netfluxId) === -1) {
|
||||||
|
|||||||
@ -256,7 +256,7 @@ define([
|
|||||||
var k = getKey(parsed.type, channel);
|
var k = getKey(parsed.type, channel);
|
||||||
var whenNewThumb = function () {
|
var whenNewThumb = function () {
|
||||||
var secret = Hash.getSecrets('file', parsed.hash, password);
|
var secret = Hash.getSecrets('file', parsed.hash, password);
|
||||||
var hexFileName = channel;
|
var hexFileName = secret.channel;
|
||||||
var src = Hash.getBlobPathFromHex(hexFileName);
|
var src = Hash.getBlobPathFromHex(hexFileName);
|
||||||
var key = secret.keys && secret.keys.cryptKey;
|
var key = secret.keys && secret.keys.cryptKey;
|
||||||
FileCrypto.fetchDecryptedMetadata(src, key, function (e, metadata) {
|
FileCrypto.fetchDecryptedMetadata(src, key, function (e, metadata) {
|
||||||
|
|||||||
@ -18,8 +18,10 @@ define([
|
|||||||
var UIElements = {};
|
var UIElements = {};
|
||||||
|
|
||||||
// Configure MediaTags to use our local viewer
|
// Configure MediaTags to use our local viewer
|
||||||
if (MediaTag && MediaTag.PdfPlugin) {
|
if (MediaTag) {
|
||||||
MediaTag.PdfPlugin.viewer = '/common/pdfjs/web/viewer.html';
|
MediaTag.setDefaultConfig('pdf', {
|
||||||
|
viewer: '/common/pdfjs/web/viewer.html'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
UIElements.updateTags = function (common, href) {
|
UIElements.updateTags = function (common, href) {
|
||||||
@ -134,12 +136,6 @@ define([
|
|||||||
$d.append(UI.dialog.selectable(owners, {
|
$d.append(UI.dialog.selectable(owners, {
|
||||||
id: 'cp-app-prop-owners',
|
id: 'cp-app-prop-owners',
|
||||||
}));
|
}));
|
||||||
/* TODO
|
|
||||||
if (owned) {
|
|
||||||
var $deleteOwned = $('button').text(Messages.fc_delete_owned).click(function () {
|
|
||||||
});
|
|
||||||
$d.append($deleteOwned);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
var expire = Messages.creation_expireFalse;
|
var expire = Messages.creation_expireFalse;
|
||||||
if (data.expire && typeof (data.expire) === "number") {
|
if (data.expire && typeof (data.expire) === "number") {
|
||||||
@ -151,11 +147,12 @@ define([
|
|||||||
id: 'cp-app-prop-expire',
|
id: 'cp-app-prop-expire',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (typeof data.password !== "undefined") {
|
var hasPassword = typeof data.password !== "undefined";
|
||||||
|
if (hasPassword) {
|
||||||
$('<label>', {'for': 'cp-app-prop-password'}).text(Messages.creation_passwordValue)
|
$('<label>', {'for': 'cp-app-prop-password'}).text(Messages.creation_passwordValue)
|
||||||
.appendTo($d);
|
.appendTo($d);
|
||||||
var password = UI.passwordInput({
|
var password = UI.passwordInput({
|
||||||
id: 'cp-app-prop-expire',
|
id: 'cp-app-prop-password',
|
||||||
readonly: 'readonly'
|
readonly: 'readonly'
|
||||||
});
|
});
|
||||||
var $pwInput = $(password).find('.cp-password-input');
|
var $pwInput = $(password).find('.cp-password-input');
|
||||||
@ -165,6 +162,51 @@ define([
|
|||||||
$d.append(password);
|
$d.append(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parsed = Hash.parsePadUrl(data.href);
|
||||||
|
if (owned && parsed.hashData.type === 'pad') {
|
||||||
|
var sframeChan = common.getSframeChannel();
|
||||||
|
var changePwTitle = Messages.properties_changePassword;
|
||||||
|
var changePwConfirm = Messages.properties_confirmChange;
|
||||||
|
if (!hasPassword) {
|
||||||
|
changePwTitle = Messages.properties_addPassword;
|
||||||
|
changePwConfirm = Messages.properties_confirmNew;
|
||||||
|
}
|
||||||
|
$('<label>', {'for': 'cp-app-prop-change-password'})
|
||||||
|
.text(changePwTitle).appendTo($d);
|
||||||
|
var newPassword = UI.passwordInput({
|
||||||
|
id: 'cp-app-prop-change-password',
|
||||||
|
style: 'flex: 1;'
|
||||||
|
});
|
||||||
|
var passwordOk = h('button', Messages.properties_changePasswordButton);
|
||||||
|
var changePass = h('span.cp-password-container', [
|
||||||
|
newPassword,
|
||||||
|
passwordOk
|
||||||
|
]);
|
||||||
|
$(passwordOk).click(function () {
|
||||||
|
UI.confirm(changePwConfirm, function (yes) {
|
||||||
|
if (!yes) { return; }
|
||||||
|
sframeChan.query("Q_PAD_PASSWORD_CHANGE", {
|
||||||
|
href: data.href,
|
||||||
|
password: $(newPassword).val()
|
||||||
|
}, function (err, data) {
|
||||||
|
if (err || data.error) {
|
||||||
|
return void UI.alert(Messages.properties_passwordError);
|
||||||
|
}
|
||||||
|
UI.findOKButton().click();
|
||||||
|
if (data.warning) {
|
||||||
|
return void UI.alert(Messages.properties_passwordWarning, function () {
|
||||||
|
common.gotoURL(hasPassword ? undefined : data.href);
|
||||||
|
}, {force: true});
|
||||||
|
}
|
||||||
|
return void UI.alert(Messages.properties_passwordSuccess, function () {
|
||||||
|
common.gotoURL(hasPassword ? undefined : data.href);
|
||||||
|
}, {force: true});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$d.append(changePass);
|
||||||
|
}
|
||||||
|
|
||||||
cb(void 0, $d);
|
cb(void 0, $d);
|
||||||
};
|
};
|
||||||
var getPadProperties = function (common, data, cb) {
|
var getPadProperties = function (common, data, cb) {
|
||||||
@ -626,7 +668,6 @@ define([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sframeChan.query('Q_SAVE_AS_TEMPLATE', {
|
sframeChan.query('Q_SAVE_AS_TEMPLATE', {
|
||||||
title: title,
|
|
||||||
toSave: toSave
|
toSave: toSave
|
||||||
}, function () {
|
}, function () {
|
||||||
UI.alert(Messages.templateSaved);
|
UI.alert(Messages.templateSaved);
|
||||||
@ -1035,52 +1076,6 @@ define([
|
|||||||
|
|
||||||
// Avatars
|
// Avatars
|
||||||
|
|
||||||
// Enable mediatags
|
|
||||||
$(window.document).on('decryption', function (e) {
|
|
||||||
var decrypted = e.originalEvent;
|
|
||||||
if (decrypted.callback) {
|
|
||||||
var cb = decrypted.callback;
|
|
||||||
cb(function (mediaObject) {
|
|
||||||
var root = mediaObject.element;
|
|
||||||
if (!root) { return; }
|
|
||||||
|
|
||||||
if (mediaObject.type === 'image') {
|
|
||||||
$(root).data('blob', decrypted.blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaObject.type !== 'download') { return; }
|
|
||||||
|
|
||||||
var metadata = decrypted.metadata;
|
|
||||||
|
|
||||||
var title = '';
|
|
||||||
var size = 0;
|
|
||||||
if (metadata && metadata.name) {
|
|
||||||
title = metadata.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decrypted.blob) {
|
|
||||||
size = decrypted.blob.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sizeMb = Util.bytesToMegabytes(size);
|
|
||||||
|
|
||||||
var $btn = $(root).find('button');
|
|
||||||
$btn.addClass('btn btn-success')
|
|
||||||
.attr('type', 'download')
|
|
||||||
.html(function () {
|
|
||||||
var text = Messages.download_mt_button + '<br>';
|
|
||||||
if (title) {
|
|
||||||
text += '<b>' + Util.fixHTML(title) + '</b><br>';
|
|
||||||
}
|
|
||||||
if (size) {
|
|
||||||
text += '<em>' + Messages._getKey('formattedMB', [sizeMb]) + '</em>';
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
UIElements.displayMediatagImage = function (Common, $tag, cb) {
|
UIElements.displayMediatagImage = function (Common, $tag, cb) {
|
||||||
if (!$tag.length || !$tag.is('media-tag')) { return void cb('NOT_MEDIATAG'); }
|
if (!$tag.length || !$tag.is('media-tag')) { return void cb('NOT_MEDIATAG'); }
|
||||||
var observer = new MutationObserver(function(mutations) {
|
var observer = new MutationObserver(function(mutations) {
|
||||||
@ -1110,7 +1105,9 @@ define([
|
|||||||
childList: true,
|
childList: true,
|
||||||
characterData: false
|
characterData: false
|
||||||
});
|
});
|
||||||
MediaTag($tag[0]);
|
MediaTag($tag[0]).on('error', function (data) {
|
||||||
|
console.error(data);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ define([
|
|||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
'/common/outer/network-config.js',
|
'/common/outer/network-config.js',
|
||||||
|
'/bower_components/chainpad/chainpad.dist.js',
|
||||||
], function (Crypto, CPNetflux, Util, Hash, Realtime, NetConfig) {
|
], function (Crypto, CPNetflux, Util, Hash, Realtime, NetConfig) {
|
||||||
var finish = function (S, err, doc) {
|
var finish = function (S, err, doc) {
|
||||||
if (S.done) { return; }
|
if (S.done) { return; }
|
||||||
|
|||||||
@ -7,25 +7,27 @@ define([
|
|||||||
'/common/common-constants.js',
|
'/common/common-constants.js',
|
||||||
'/common/common-feedback.js',
|
'/common/common-feedback.js',
|
||||||
'/common/outer/local-store.js',
|
'/common/outer/local-store.js',
|
||||||
'/common/outer/store-rpc.js',
|
'/common/outer/worker-channel.js',
|
||||||
|
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
], function (Config, Messages, Util, Hash,
|
], function (Config, Messages, Util, Hash,
|
||||||
Messaging, Constants, Feedback, LocalStore, AStore,
|
Messaging, Constants, Feedback, LocalStore, Channel,
|
||||||
AppConfig, Nthen) {
|
AppConfig, Nthen) {
|
||||||
|
|
||||||
|
|
||||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||||
any particular pad type. This includes functions for committing metadata
|
any particular pad type. This includes functions for committing metadata
|
||||||
about pads to your local storage for future use and improved usability.
|
about pads to your local storage for future use and improved usability.
|
||||||
|
|
||||||
Additionally, there is some basic functionality for import/export.
|
Additionally, there is some basic functionality for import/export.
|
||||||
*/
|
*/
|
||||||
var postMessage = function (cmd, data, cb) {
|
var urlArgs = Util.find(Config, ['requireConf', 'urlArgs']) || '';
|
||||||
setTimeout(function () {
|
|
||||||
|
var postMessage = function (/*cmd, data, cb*/) {
|
||||||
|
/*setTimeout(function () {
|
||||||
AStore.query(cmd, data, cb);
|
AStore.query(cmd, data, cb);
|
||||||
});
|
});*/
|
||||||
|
console.error('NOT_READY');
|
||||||
};
|
};
|
||||||
var tryParsing = function (x) {
|
var tryParsing = function (x) {
|
||||||
try { return JSON.parse(x); }
|
try { return JSON.parse(x); }
|
||||||
@ -232,6 +234,12 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
common.writeLoginBlock = function (data, cb) {
|
||||||
|
postMessage('WRITE_LOGIN_BLOCK', data, function (obj) {
|
||||||
|
cb(obj);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// ANON RPC
|
// ANON RPC
|
||||||
|
|
||||||
// SFRAME: talk to anon_rpc from the iframe
|
// SFRAME: talk to anon_rpc from the iframe
|
||||||
@ -446,6 +454,26 @@ define([
|
|||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
Crypt.get(parsed.hash, function (err, val) {
|
Crypt.get(parsed.hash, function (err, val) {
|
||||||
if (err) { throw new Error(err); }
|
if (err) { throw new Error(err); }
|
||||||
|
try {
|
||||||
|
// Try to fix the title before importing the template
|
||||||
|
var parsed = JSON.parse(val);
|
||||||
|
var meta;
|
||||||
|
if (Array.isArray(parsed) && typeof(parsed[3]) === "object") {
|
||||||
|
meta = parsed[3].metadata; // pad
|
||||||
|
} else if (parsed.info) {
|
||||||
|
meta = parsed.info; // poll
|
||||||
|
} else {
|
||||||
|
meta = parsed.metadata;
|
||||||
|
}
|
||||||
|
if (typeof(meta) === "object") {
|
||||||
|
meta.defaultTitle = meta.title || meta.defaultTitle;
|
||||||
|
delete meta.users;
|
||||||
|
meta.title = "";
|
||||||
|
}
|
||||||
|
val = JSON.stringify(parsed);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Can't fix template title", e);
|
||||||
|
}
|
||||||
Crypt.put(parsed2.hash, val, cb, optsPut);
|
Crypt.put(parsed2.hash, val, cb, optsPut);
|
||||||
}, optsGet);
|
}, optsGet);
|
||||||
});
|
});
|
||||||
@ -469,6 +497,13 @@ define([
|
|||||||
if (typeof (data.title) !== "string") { return cb('Missing title'); }
|
if (typeof (data.title) !== "string") { return cb('Missing title'); }
|
||||||
if (data.title.trim() === "") { data.title = Hash.getDefaultName(parsed); }
|
if (data.title.trim() === "") { data.title = Hash.getDefaultName(parsed); }
|
||||||
|
|
||||||
|
if (common.initialPath) {
|
||||||
|
if (!data.path) {
|
||||||
|
data.path = common.initialPath;
|
||||||
|
delete common.initialPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
postMessage("SET_PAD_TITLE", data, function (obj) {
|
postMessage("SET_PAD_TITLE", data, function (obj) {
|
||||||
if (obj && obj.error) {
|
if (obj && obj.error) {
|
||||||
console.log("unable to set pad title");
|
console.log("unable to set pad title");
|
||||||
@ -505,11 +540,17 @@ define([
|
|||||||
// Network
|
// Network
|
||||||
common.onNetworkDisconnect = Util.mkEvent();
|
common.onNetworkDisconnect = Util.mkEvent();
|
||||||
common.onNetworkReconnect = Util.mkEvent();
|
common.onNetworkReconnect = Util.mkEvent();
|
||||||
|
common.onNewVersionReconnect = Util.mkEvent();
|
||||||
|
|
||||||
// Messaging
|
// Messaging
|
||||||
var messaging = common.messaging = {};
|
var messaging = common.messaging = {};
|
||||||
messaging.onFriendRequest = Util.mkEvent();
|
messaging.onFriendRequest = Util.mkEvent();
|
||||||
messaging.onFriendComplete = Util.mkEvent();
|
messaging.onFriendComplete = Util.mkEvent();
|
||||||
|
messaging.addHandlers = function (href) {
|
||||||
|
postMessage("ADD_DIRECT_MESSAGE_HANDLERS", {
|
||||||
|
href: href
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Messenger
|
// Messenger
|
||||||
var messenger = common.messenger = {};
|
var messenger = common.messenger = {};
|
||||||
@ -549,8 +590,11 @@ define([
|
|||||||
|
|
||||||
// Pad RPC
|
// Pad RPC
|
||||||
var pad = common.padRpc = {};
|
var pad = common.padRpc = {};
|
||||||
pad.joinPad = function (data, cb) {
|
pad.joinPad = function (data) {
|
||||||
postMessage("JOIN_PAD", data, cb);
|
postMessage("JOIN_PAD", data);
|
||||||
|
};
|
||||||
|
pad.leavePad = function (data, cb) {
|
||||||
|
postMessage("LEAVE_PAD", data, cb);
|
||||||
};
|
};
|
||||||
pad.sendPadMsg = function (data, cb) {
|
pad.sendPadMsg = function (data, cb) {
|
||||||
postMessage("SEND_PAD_MSG", data, cb);
|
postMessage("SEND_PAD_MSG", data, cb);
|
||||||
@ -560,8 +604,94 @@ define([
|
|||||||
pad.onJoinEvent = Util.mkEvent();
|
pad.onJoinEvent = Util.mkEvent();
|
||||||
pad.onLeaveEvent = Util.mkEvent();
|
pad.onLeaveEvent = Util.mkEvent();
|
||||||
pad.onDisconnectEvent = Util.mkEvent();
|
pad.onDisconnectEvent = Util.mkEvent();
|
||||||
|
pad.onConnectEvent = Util.mkEvent();
|
||||||
pad.onErrorEvent = Util.mkEvent();
|
pad.onErrorEvent = Util.mkEvent();
|
||||||
|
|
||||||
|
common.changePadPassword = function (Crypt, href, newPassword, edPublic, cb) {
|
||||||
|
if (!href) { return void cb({ error: 'EINVAL_HREF' }); }
|
||||||
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); }
|
||||||
|
|
||||||
|
var warning = false;
|
||||||
|
var newHash;
|
||||||
|
var oldChannel;
|
||||||
|
if (parsed.hashData.password) {
|
||||||
|
newHash = parsed.hash;
|
||||||
|
} else {
|
||||||
|
newHash = Hash.createRandomHash(parsed.type, newPassword);
|
||||||
|
}
|
||||||
|
var newHref = '/' + parsed.type + '/#' + newHash;
|
||||||
|
|
||||||
|
var optsGet = {};
|
||||||
|
var optsPut = {
|
||||||
|
password: newPassword
|
||||||
|
};
|
||||||
|
Nthen(function (waitFor) {
|
||||||
|
if (parsed.hashData && parsed.hashData.password) {
|
||||||
|
common.getPadAttribute('password', waitFor(function (err, password) {
|
||||||
|
optsGet.password = password;
|
||||||
|
}), href);
|
||||||
|
}
|
||||||
|
common.getPadAttribute('owners', waitFor(function (err, owners) {
|
||||||
|
if (!Array.isArray(owners) || owners.indexOf(edPublic) === -1) {
|
||||||
|
// We're not an owner, we shouldn't be able to change the password!
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: 'EPERM' });
|
||||||
|
}
|
||||||
|
optsPut.owners = owners;
|
||||||
|
}), href);
|
||||||
|
common.getPadAttribute('expire', waitFor(function (err, expire) {
|
||||||
|
optsPut.expire = (expire - (+new Date())) / 1000; // Lifetime in seconds
|
||||||
|
}), href);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
Crypt.get(parsed.hash, waitFor(function (err, val) {
|
||||||
|
if (err) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: err });
|
||||||
|
}
|
||||||
|
Crypt.put(newHash, val, waitFor(function (err) {
|
||||||
|
if (err) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: err });
|
||||||
|
}
|
||||||
|
}), optsPut);
|
||||||
|
}), optsGet);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, optsGet.password);
|
||||||
|
oldChannel = secret.channel;
|
||||||
|
pad.leavePad({
|
||||||
|
channel: oldChannel
|
||||||
|
}, waitFor());
|
||||||
|
pad.onDisconnectEvent.fire(true);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
common.removeOwnedChannel(oldChannel, waitFor(function (obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb(obj);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
common.setPadAttribute('password', newPassword, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
var secret = Hash.getSecrets(parsed.type, newHash, newPassword);
|
||||||
|
common.setPadAttribute('channel', secret.channel, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
|
||||||
|
if (parsed.hashData.password) { return; } // same hash
|
||||||
|
common.setPadAttribute('href', newHref, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
}).nThen(function () {
|
||||||
|
cb({
|
||||||
|
warning: warning,
|
||||||
|
hash: newHash,
|
||||||
|
href: newHref
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Loading events
|
// Loading events
|
||||||
common.loading = {};
|
common.loading = {};
|
||||||
common.loading.onDriveEvent = Util.mkEvent();
|
common.loading.onDriveEvent = Util.mkEvent();
|
||||||
@ -569,6 +699,9 @@ define([
|
|||||||
common.getFullHistory = function (data, cb) {
|
common.getFullHistory = function (data, cb) {
|
||||||
postMessage("GET_FULL_HISTORY", data, cb);
|
postMessage("GET_FULL_HISTORY", data, cb);
|
||||||
};
|
};
|
||||||
|
common.getHistoryRange = function (data, cb) {
|
||||||
|
postMessage("GET_HISTORY_RANGE", data, cb);
|
||||||
|
};
|
||||||
|
|
||||||
common.getShareHashes = function (secret, cb) {
|
common.getShareHashes = function (secret, cb) {
|
||||||
var hashes;
|
var hashes;
|
||||||
@ -602,9 +735,10 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
var CRYPTPAD_VERSION = 'cryptpad-version';
|
var CRYPTPAD_VERSION = 'cryptpad-version';
|
||||||
var updateLocalVersion = function () {
|
var currentVersion = localStorage[CRYPTPAD_VERSION];
|
||||||
|
var updateLocalVersion = function (newUrlArgs) {
|
||||||
// Check for CryptPad updates
|
// Check for CryptPad updates
|
||||||
var urlArgs = Config.requireConf ? Config.requireConf.urlArgs : null;
|
var urlArgs = newUrlArgs || (Config.requireConf ? Config.requireConf.urlArgs : null);
|
||||||
if (!urlArgs) { return; }
|
if (!urlArgs) { return; }
|
||||||
var arr = /ver=([0-9.]+)(-[0-9]*)?/.exec(urlArgs);
|
var arr = /ver=([0-9.]+)(-[0-9]*)?/.exec(urlArgs);
|
||||||
var ver = arr[1];
|
var ver = arr[1];
|
||||||
@ -612,14 +746,20 @@ define([
|
|||||||
var verArr = ver.split('.');
|
var verArr = ver.split('.');
|
||||||
verArr[2] = 0;
|
verArr[2] = 0;
|
||||||
if (verArr.length !== 3) { return; }
|
if (verArr.length !== 3) { return; }
|
||||||
var stored = localStorage[CRYPTPAD_VERSION] || '0.0.0';
|
var stored = currentVersion || '0.0.0';
|
||||||
var storedArr = stored.split('.');
|
var storedArr = stored.split('.');
|
||||||
storedArr[2] = 0;
|
storedArr[2] = 0;
|
||||||
var shouldUpdate = parseInt(verArr[0]) > parseInt(storedArr[0]) ||
|
var shouldUpdate = parseInt(verArr[0]) > parseInt(storedArr[0]) ||
|
||||||
(parseInt(verArr[0]) === parseInt(storedArr[0]) &&
|
(parseInt(verArr[0]) === parseInt(storedArr[0]) &&
|
||||||
parseInt(verArr[1]) > parseInt(storedArr[1]));
|
parseInt(verArr[1]) > parseInt(storedArr[1]));
|
||||||
if (!shouldUpdate) { return; }
|
if (!shouldUpdate) { return; }
|
||||||
|
currentVersion = ver;
|
||||||
localStorage[CRYPTPAD_VERSION] = ver;
|
localStorage[CRYPTPAD_VERSION] = ver;
|
||||||
|
if (newUrlArgs) {
|
||||||
|
// It's a reconnect
|
||||||
|
common.onNewVersionReconnect.fire();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var _onMetadataChanged = [];
|
var _onMetadataChanged = [];
|
||||||
@ -641,100 +781,57 @@ define([
|
|||||||
window.location.href = '/login/';
|
window.location.href = '/login/';
|
||||||
};
|
};
|
||||||
|
|
||||||
common.startAccountDeletion = function (cb) {
|
common.startAccountDeletion = function (data, cb) {
|
||||||
// Logout other tabs
|
// Logout other tabs
|
||||||
LocalStore.logout(null, true);
|
LocalStore.logout(null, true);
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
var onMessage = function (cmd, data, cb) {
|
var queries = {
|
||||||
cb = cb || function () {};
|
REQUEST_LOGIN: requestLogin,
|
||||||
switch (cmd) {
|
UPDATE_METADATA: common.changeMetadata,
|
||||||
case 'REQUEST_LOGIN': {
|
UPDATE_TOKEN: function (data) {
|
||||||
requestLogin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'UPDATE_METADATA': {
|
|
||||||
common.changeMetadata();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'UPDATE_TOKEN': {
|
|
||||||
var localToken = tryParsing(localStorage.getItem(Constants.tokenKey));
|
var localToken = tryParsing(localStorage.getItem(Constants.tokenKey));
|
||||||
if (localToken !== data.token) { requestLogin(); }
|
if (localToken !== data.token) { requestLogin(); }
|
||||||
break;
|
},
|
||||||
}
|
// Messaging
|
||||||
case 'Q_FRIEND_REQUEST': {
|
Q_FRIEND_REQUEST: common.messaging.onFriendRequest.fire,
|
||||||
common.messaging.onFriendRequest.fire(data, cb);
|
EV_FIREND_COMPLETE: common.messaging.onFriendComplete.fire,
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'EV_FRIEND_COMPLETE': {
|
|
||||||
common.messaging.onFriendComplete.fire(data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Network
|
// Network
|
||||||
case 'NETWORK_DISCONNECT': {
|
NETWORK_DISCONNECT: common.onNetworkDisconnect.fire,
|
||||||
common.onNetworkDisconnect.fire(); break;
|
NETWORK_RECONNECT: function (data) {
|
||||||
}
|
require(['/api/config?' + (+new Date())], function (NewConfig) {
|
||||||
case 'NETWORK_RECONNECT': {
|
var update = updateLocalVersion(NewConfig.requireConf && NewConfig.requireConf.urlArgs);
|
||||||
common.onNetworkReconnect.fire(data); break;
|
if (update) {
|
||||||
|
postMessage('DISCONNECT');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
common.onNetworkReconnect.fire(data);
|
||||||
|
});
|
||||||
|
},
|
||||||
// Messenger
|
// Messenger
|
||||||
case 'CONTACTS_MESSAGE': {
|
CONTACTS_MESSAGE: common.messenger.onMessageEvent.fire,
|
||||||
common.messenger.onMessageEvent.fire(data); break;
|
CONTACTS_JOIN: common.messenger.onJoinEvent.fire,
|
||||||
}
|
CONTACTS_LEAVE: common.messenger.onLeaveEvent.fire,
|
||||||
case 'CONTACTS_JOIN': {
|
CONTACTS_UPDATE: common.messenger.onUpdateEvent.fire,
|
||||||
common.messenger.onJoinEvent.fire(data); break;
|
CONTACTS_FRIEND: common.messenger.onFriendEvent.fire,
|
||||||
}
|
CONTACTS_UNFRIEND: common.messenger.onUnfriendEvent.fire,
|
||||||
case 'CONTACTS_LEAVE': {
|
|
||||||
common.messenger.onLeaveEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_UPDATE': {
|
|
||||||
common.messenger.onUpdateEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_FRIEND': {
|
|
||||||
common.messenger.onFriendEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_UNFRIEND': {
|
|
||||||
common.messenger.onUnfriendEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
// Pad
|
// Pad
|
||||||
case 'PAD_READY': {
|
PAD_READY: common.padRpc.onReadyEvent.fire,
|
||||||
common.padRpc.onReadyEvent.fire(); break;
|
PAD_MESSAGE: common.padRpc.onMessageEvent.fire,
|
||||||
}
|
PAD_JOIN: common.padRpc.onJoinEvent.fire,
|
||||||
case 'PAD_MESSAGE': {
|
PAD_LEAVE: common.padRpc.onLeaveEvent.fire,
|
||||||
common.padRpc.onMessageEvent.fire(data); break;
|
PAD_DISCONNECT: common.padRpc.onDisconnectEvent.fire,
|
||||||
}
|
PAD_CONNECT: common.padRpc.onConnectEvent.fire,
|
||||||
case 'PAD_JOIN': {
|
PAD_ERROR: common.padRpc.onErrorEvent.fire,
|
||||||
common.padRpc.onJoinEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
case 'PAD_LEAVE': {
|
|
||||||
common.padRpc.onLeaveEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
case 'PAD_DISCONNECT': {
|
|
||||||
common.padRpc.onDisconnectEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
case 'PAD_ERROR': {
|
|
||||||
common.padRpc.onErrorEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
// Drive
|
// Drive
|
||||||
case 'DRIVE_LOG': {
|
DRIVE_LOG: common.drive.onLog.fire,
|
||||||
common.drive.onLog.fire(data); break;
|
DRIVE_CHANGE: common.drive.onChange.fire,
|
||||||
}
|
DRIVE_REMOVE: common.drive.onRemove.fire,
|
||||||
case 'DRIVE_CHANGE': {
|
|
||||||
common.drive.onChange.fire(data); break;
|
|
||||||
}
|
|
||||||
case 'DRIVE_REMOVE': {
|
|
||||||
common.drive.onRemove.fire(data); break;
|
|
||||||
}
|
|
||||||
// Account deletion
|
// Account deletion
|
||||||
case 'DELETE_ACCOUNT': {
|
DELETE_ACCOUNT: common.startAccountDeletion,
|
||||||
common.startAccountDeletion(cb); break;
|
|
||||||
}
|
|
||||||
// Loading
|
// Loading
|
||||||
case 'LOADING_DRIVE': {
|
LOADING_DRIVE: common.loading.onDriveEvent.fire
|
||||||
common.loading.onDriveEvent.fire(data); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
common.ready = (function () {
|
common.ready = (function () {
|
||||||
@ -792,19 +889,136 @@ define([
|
|||||||
}
|
}
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var cfg = {
|
var cfg = {
|
||||||
query: onMessage, // TODO temporary, will be replaced by a webworker channel
|
init: true,
|
||||||
|
//query: onMessage, // TODO temporary, will be replaced by a webworker channel
|
||||||
userHash: LocalStore.getUserHash(),
|
userHash: LocalStore.getUserHash(),
|
||||||
anonHash: LocalStore.getFSHash(),
|
anonHash: LocalStore.getFSHash(),
|
||||||
localToken: tryParsing(localStorage.getItem(Constants.tokenKey)),
|
localToken: tryParsing(localStorage.getItem(Constants.tokenKey)),
|
||||||
language: common.getLanguage(),
|
language: common.getLanguage(),
|
||||||
messenger: rdyCfg.messenger,
|
messenger: rdyCfg.messenger, // Boolean
|
||||||
driveEvents: rdyCfg.driveEvents
|
driveEvents: rdyCfg.driveEvents // Boolean
|
||||||
};
|
};
|
||||||
if (sessionStorage[Constants.newPadPathKey]) {
|
if (sessionStorage[Constants.newPadPathKey]) {
|
||||||
cfg.initialPath = sessionStorage[Constants.newPadPathKey];
|
common.initialPath = sessionStorage[Constants.newPadPathKey];
|
||||||
delete sessionStorage[Constants.newPadPathKey];
|
delete sessionStorage[Constants.newPadPathKey];
|
||||||
}
|
}
|
||||||
AStore.query("CONNECT", cfg, waitFor(function (data) {
|
|
||||||
|
var channelIsReady = waitFor();
|
||||||
|
|
||||||
|
var msgEv = Util.mkEvent();
|
||||||
|
var postMsg, worker;
|
||||||
|
Nthen(function (waitFor2) {
|
||||||
|
if (typeof(SharedWorker) !== "undefined") {
|
||||||
|
worker = new SharedWorker('/common/outer/sharedworker.js?' + urlArgs);
|
||||||
|
worker.onerror = function (e) {
|
||||||
|
console.error(e);
|
||||||
|
};
|
||||||
|
worker.port.onmessage = function (ev) {
|
||||||
|
if (ev.data === "SW_READY") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msgEv.fire(ev);
|
||||||
|
};
|
||||||
|
postMsg = function (data) {
|
||||||
|
worker.port.postMessage(data);
|
||||||
|
};
|
||||||
|
postMsg('INIT');
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', function () {
|
||||||
|
postMsg('CLOSE');
|
||||||
|
});
|
||||||
|
} else if (false && 'serviceWorker' in navigator) {
|
||||||
|
var initializing = true;
|
||||||
|
var stopWaiting = waitFor2(); // Call this function when we're ready
|
||||||
|
|
||||||
|
postMsg = function (data) {
|
||||||
|
if (worker) { return void worker.postMessage(data); }
|
||||||
|
};
|
||||||
|
|
||||||
|
navigator.serviceWorker.register('/common/outer/serviceworker.js?' + urlArgs, {scope: '/'})
|
||||||
|
.then(function(reg) {
|
||||||
|
// Add handler for receiving messages from the service worker
|
||||||
|
navigator.serviceWorker.addEventListener('message', function (ev) {
|
||||||
|
if (initializing && ev.data === "SW_READY") {
|
||||||
|
initializing = false;
|
||||||
|
} else {
|
||||||
|
msgEv.fire(ev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize the worker
|
||||||
|
// If it is active (probably running in another tab), just post INIT
|
||||||
|
if (reg.active) {
|
||||||
|
worker = reg.active;
|
||||||
|
postMsg("INIT");
|
||||||
|
}
|
||||||
|
// If it was not active, wait for the "activated" state and post INIT
|
||||||
|
reg.onupdatefound = function () {
|
||||||
|
if (initializing) {
|
||||||
|
var w = reg.installing;
|
||||||
|
var onStateChange = function () {
|
||||||
|
if (w.state === "activated") {
|
||||||
|
worker = w;
|
||||||
|
postMsg("INIT");
|
||||||
|
w.removeEventListener("statechange", onStateChange);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w.addEventListener('statechange', onStateChange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// New version detected (from another tab): kill?
|
||||||
|
console.error('New version detected: ABORT?');
|
||||||
|
};
|
||||||
|
return void stopWaiting();
|
||||||
|
}).catch(function(error) {
|
||||||
|
/**/console.log('Registration failed with ' + error);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', function () {
|
||||||
|
postMsg('CLOSE');
|
||||||
|
});
|
||||||
|
} else if (Worker) {
|
||||||
|
worker = new Worker('/common/outer/webworker.js?' + urlArgs);
|
||||||
|
worker.onmessage = function (ev) {
|
||||||
|
msgEv.fire(ev);
|
||||||
|
};
|
||||||
|
postMsg = function (data) {
|
||||||
|
worker.postMessage(data);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
require(['/common/outer/noworker.js'], waitFor2(function (NoWorker) {
|
||||||
|
NoWorker.onMessage(function (data) {
|
||||||
|
msgEv.fire({data: data});
|
||||||
|
});
|
||||||
|
postMsg = function (d) { setTimeout(function () { NoWorker.query(d); }); };
|
||||||
|
NoWorker.create();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}).nThen(function () {
|
||||||
|
Channel.create(msgEv, postMsg, function (chan) {
|
||||||
|
console.log('Outer ready');
|
||||||
|
Object.keys(queries).forEach(function (q) {
|
||||||
|
chan.on(q, function (data, cb) {
|
||||||
|
try {
|
||||||
|
queries[q](data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error in outer when executing query " + q);
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
postMessage = function (cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
chan.query(cmd, data, function (err, data) {
|
||||||
|
if (err) { return void cb ({error: err}); }
|
||||||
|
cb(data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('Posting CONNECT');
|
||||||
|
postMessage('CONNECT', cfg, function (data) {
|
||||||
if (data.error) { throw new Error(data.error); }
|
if (data.error) { throw new Error(data.error); }
|
||||||
if (data.state === 'ALREADY_INIT') {
|
if (data.state === 'ALREADY_INIT') {
|
||||||
data = data.returned;
|
data = data.returned;
|
||||||
@ -828,7 +1042,12 @@ define([
|
|||||||
|
|
||||||
initFeedback(data.feedback);
|
initFeedback(data.feedback);
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}));
|
channelIsReady();
|
||||||
|
});
|
||||||
|
|
||||||
|
}, false);
|
||||||
|
});
|
||||||
|
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
// Load the new pad when the hash has changed
|
// Load the new pad when the hash has changed
|
||||||
var oldHref = document.location.href;
|
var oldHref = document.location.href;
|
||||||
@ -857,9 +1076,12 @@ define([
|
|||||||
document.location.reload();
|
document.location.reload();
|
||||||
} else if (o && !n) {
|
} else if (o && !n) {
|
||||||
LocalStore.logout();
|
LocalStore.logout();
|
||||||
postMessage("DISCONNECT");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
LocalStore.onLogout(function () {
|
||||||
|
console.log('onLogout: disconnect');
|
||||||
|
postMessage("DISCONNECT");
|
||||||
|
});
|
||||||
|
|
||||||
if (PINNING_ENABLED && LocalStore.isLoggedIn()) {
|
if (PINNING_ENABLED && LocalStore.isLoggedIn()) {
|
||||||
console.log("logged in. pads will be pinned");
|
console.log("logged in. pads will be pinned");
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -109,7 +109,7 @@ define([
|
|||||||
pinPads: function () {} // without pinPads /outer/userObject.js won't be loaded
|
pinPads: function () {} // without pinPads /outer/userObject.js won't be loaded
|
||||||
});
|
});
|
||||||
var onMigrated = function () {
|
var onMigrated = function () {
|
||||||
oldFo.fixFiles();
|
oldFo.fixFiles(true);
|
||||||
var newFo = proxyData.userObject;
|
var newFo = proxyData.userObject;
|
||||||
var oldRecentPads = parsed.drive[newFo.FILES_DATA];
|
var oldRecentPads = parsed.drive[newFo.FILES_DATA];
|
||||||
var newRecentPads = proxy.drive[newFo.FILES_DATA];
|
var newRecentPads = proxy.drive[newFo.FILES_DATA];
|
||||||
|
|||||||
@ -64,7 +64,9 @@ define(['json.sortify'], function (Sortify) {
|
|||||||
|
|
||||||
if (metadataObj.title !== rememberedTitle) {
|
if (metadataObj.title !== rememberedTitle) {
|
||||||
rememberedTitle = metadataObj.title;
|
rememberedTitle = metadataObj.title;
|
||||||
titleChangeHandlers.forEach(function (f) { f(metadataObj.title); });
|
titleChangeHandlers.forEach(function (f) {
|
||||||
|
f(metadataObj.title, metadataObj.defaultTitle);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
changeHandlers.forEach(function (f) { f(); });
|
changeHandlers.forEach(function (f) { f(); });
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,10 @@ define([], function () {
|
|||||||
|
|
||||||
var unBencode = function (str) { return str.replace(/^\d+:/, ''); };
|
var unBencode = function (str) { return str.replace(/^\d+:/, ''); };
|
||||||
|
|
||||||
|
var removeCp = function (str) {
|
||||||
|
return str.replace(/^cp\|([A-Za-z0-9+\/=]{0,20}\|)?/, '');
|
||||||
|
};
|
||||||
|
|
||||||
var start = function (conf) {
|
var start = function (conf) {
|
||||||
var channel = conf.channel;
|
var channel = conf.channel;
|
||||||
var validateKey = conf.validateKey;
|
var validateKey = conf.validateKey;
|
||||||
@ -72,7 +76,7 @@ define([], function () {
|
|||||||
// at the beginning of each message on the server.
|
// at the beginning of each message on the server.
|
||||||
// We have to make sure our regex ignores this nonce using {0,20} (our IDs
|
// We have to make sure our regex ignores this nonce using {0,20} (our IDs
|
||||||
// should only be 8 characters long)
|
// should only be 8 characters long)
|
||||||
return msg.replace(/^cp\|([A-Za-z0-9+\/=]{0,20}\|)?/, '');
|
return removeCp(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
var msgOut = function (msg) {
|
var msgOut = function (msg) {
|
||||||
@ -124,6 +128,8 @@ define([], function () {
|
|||||||
|
|
||||||
|
|
||||||
lastKnownHash = msg.slice(0,64);
|
lastKnownHash = msg.slice(0,64);
|
||||||
|
|
||||||
|
var isCp = /^cp\|/.test(msg);
|
||||||
var message = msgIn(peer, msg);
|
var message = msgIn(peer, msg);
|
||||||
|
|
||||||
verbose(message);
|
verbose(message);
|
||||||
@ -134,7 +140,7 @@ define([], function () {
|
|||||||
message = unBencode(message);//.slice(message.indexOf(':[') + 1);
|
message = unBencode(message);//.slice(message.indexOf(':[') + 1);
|
||||||
|
|
||||||
// pass the message into Chainpad
|
// pass the message into Chainpad
|
||||||
onMessage(peer, message, validateKey);
|
onMessage(peer, message, validateKey, isCp);
|
||||||
//sframeChan.query('Q_RT_MESSAGE', message, function () { });
|
//sframeChan.query('Q_RT_MESSAGE', message, function () { });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -237,7 +243,6 @@ define([], function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
network.on('disconnect', function (reason) {
|
network.on('disconnect', function (reason) {
|
||||||
console.log('disconnect');
|
|
||||||
//if (isIntentionallyLeaving) { return; }
|
//if (isIntentionallyLeaving) { return; }
|
||||||
if (reason === "network.disconnect() called") { return; }
|
if (reason === "network.disconnect() called") { return; }
|
||||||
onDisconnect();
|
onDisconnect();
|
||||||
@ -260,7 +265,8 @@ define([], function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
start: start
|
start: start,
|
||||||
|
removeCp: removeCp
|
||||||
/*function (config) {
|
/*function (config) {
|
||||||
config.sframeChan.whenReg('EV_RT_READY', function () {
|
config.sframeChan.whenReg('EV_RT_READY', function () {
|
||||||
start(config);
|
start(config);
|
||||||
|
|||||||
103
www/common/outer/noworker.js
Normal file
103
www/common/outer/noworker.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
define([
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/common/outer/worker-channel.js',
|
||||||
|
'/common/outer/store-rpc.js',
|
||||||
|
], function (Util, Channel, SRpc) {
|
||||||
|
|
||||||
|
var msgEv = Util.mkEvent();
|
||||||
|
var sendMsg = Util.mkEvent();
|
||||||
|
var create = function () {
|
||||||
|
var Rpc = SRpc();
|
||||||
|
|
||||||
|
var postMessage = function (data) {
|
||||||
|
sendMsg.fire(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
Channel.create(msgEv, postMessage, function (chan) {
|
||||||
|
var clientId = '1';
|
||||||
|
Object.keys(Rpc.queries).forEach(function (q) {
|
||||||
|
if (q === 'CONNECT') { return; }
|
||||||
|
if (q === 'JOIN_PAD') { return; }
|
||||||
|
if (q === 'SEND_PAD_MSG') { return; }
|
||||||
|
chan.on(q, function (data, cb) {
|
||||||
|
try {
|
||||||
|
Rpc.queries[q](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query ' + q);
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
chan.on('CONNECT', function (cfg, cb) {
|
||||||
|
// load Store here, with cfg, and pass a "query" (chan.query)
|
||||||
|
// cId is a clientId used in ServiceWorker or SharedWorker
|
||||||
|
cfg.query = function (cId, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
cfg.broadcast = function (excludes, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
if (excludes.indexOf(clientId) !== -1) { return; }
|
||||||
|
chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
|
||||||
|
if (data && data.state === "ALREADY_INIT") {
|
||||||
|
return void cb(data);
|
||||||
|
}
|
||||||
|
if (cfg.driveEvents) {
|
||||||
|
Rpc._subscribeToDrive(clientId);
|
||||||
|
}
|
||||||
|
if (cfg.messenger) {
|
||||||
|
Rpc._subscribeToMessenger(clientId);
|
||||||
|
}
|
||||||
|
cb(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var chanId;
|
||||||
|
chan.on('JOIN_PAD', function (data, cb) {
|
||||||
|
chanId = data.channel;
|
||||||
|
try {
|
||||||
|
Rpc.queries['JOIN_PAD'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query JOIN_PAD');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chan.on('SEND_PAD_MSG', function (msg, cb) {
|
||||||
|
var data = {
|
||||||
|
msg: msg,
|
||||||
|
channel: chanId
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query SEND_PAD_MSG');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: function (data) {
|
||||||
|
msgEv.fire({data: data});
|
||||||
|
},
|
||||||
|
onMessage: function (cb) {
|
||||||
|
sendMsg.reg(function (data) {
|
||||||
|
setTimeout(function () {
|
||||||
|
cb(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
create: create
|
||||||
|
};
|
||||||
|
});
|
||||||
175
www/common/outer/serviceworker.js
Normal file
175
www/common/outer/serviceworker.js
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/* jshint ignore:start */
|
||||||
|
importScripts('/bower_components/requirejs/require.js');
|
||||||
|
|
||||||
|
window = self;
|
||||||
|
localStorage = {
|
||||||
|
setItem: function (k, v) { localStorage[k] = v; },
|
||||||
|
getItem: function (k) { return localStorage[k]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
self.tabs = {};
|
||||||
|
|
||||||
|
var postMsg = function (client, data) {
|
||||||
|
client.postMessage(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
var debug = function (msg) { console.log(msg); };
|
||||||
|
// debug = function () {};
|
||||||
|
|
||||||
|
var init = function (client, cb) {
|
||||||
|
debug('SW INIT');
|
||||||
|
|
||||||
|
require([
|
||||||
|
'/common/requireconfig.js'
|
||||||
|
], function (RequireConfig) {
|
||||||
|
require.config(RequireConfig());
|
||||||
|
require([
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/common/outer/worker-channel.js',
|
||||||
|
'/common/outer/store-rpc.js'
|
||||||
|
], function (Util, Channel, SRpc) {
|
||||||
|
debug('SW Required ressources loaded');
|
||||||
|
var msgEv = Util.mkEvent();
|
||||||
|
|
||||||
|
if (!self.Rpc) {
|
||||||
|
self.Rpc = SRpc();
|
||||||
|
}
|
||||||
|
var Rpc = self.Rpc;
|
||||||
|
|
||||||
|
var postToClient = function (data) {
|
||||||
|
postMsg(client, data);
|
||||||
|
};
|
||||||
|
Channel.create(msgEv, postToClient, function (chan) {
|
||||||
|
debug('SW Channel created');
|
||||||
|
|
||||||
|
var clientId = client.id;
|
||||||
|
self.tabs[clientId].chan = chan;
|
||||||
|
Object.keys(Rpc.queries).forEach(function (q) {
|
||||||
|
if (q === 'CONNECT') { return; }
|
||||||
|
if (q === 'JOIN_PAD') { return; }
|
||||||
|
if (q === 'SEND_PAD_MSG') { return; }
|
||||||
|
chan.on(q, function (data, cb) {
|
||||||
|
try {
|
||||||
|
Rpc.queries[q](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query ' + q);
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
if (q === "DISCONNECT") {
|
||||||
|
console.log('Deleting existing store!');
|
||||||
|
delete self.Rpc;
|
||||||
|
delete self.store;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
chan.on('CONNECT', function (cfg, cb) {
|
||||||
|
debug('SW Connect callback');
|
||||||
|
if (self.store) {
|
||||||
|
debug('Store already exists!');
|
||||||
|
if (cfg.driveEvents) {
|
||||||
|
Rpc._subscribeToDrive(clientId);
|
||||||
|
}
|
||||||
|
if (cfg.messenger) {
|
||||||
|
Rpc._subscribeToMessenger(clientId);
|
||||||
|
}
|
||||||
|
return void cb(self.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('Loading new async store');
|
||||||
|
// One-time initialization (init async-store)
|
||||||
|
cfg.query = function (cId, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
cfg.broadcast = function (excludes, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
Object.keys(self.tabs).forEach(function (cId) {
|
||||||
|
if (excludes.indexOf(cId) !== -1) { return; }
|
||||||
|
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
|
||||||
|
if (cfg.driveEvents) {
|
||||||
|
Rpc._subscribeToDrive(clientId);
|
||||||
|
}
|
||||||
|
if (cfg.messenger) {
|
||||||
|
Rpc._subscribeToMessenger(clientId);
|
||||||
|
}
|
||||||
|
if (data && data.state === "ALREADY_INIT") {
|
||||||
|
return void cb(data.returned);
|
||||||
|
}
|
||||||
|
self.store = data;
|
||||||
|
cb(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
chan.on('JOIN_PAD', function (data, cb) {
|
||||||
|
self.tabs[clientId].channelId = data.channel;
|
||||||
|
try {
|
||||||
|
Rpc.queries['JOIN_PAD'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query JOIN_PAD');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chan.on('SEND_PAD_MSG', function (msg, cb) {
|
||||||
|
var data = {
|
||||||
|
msg: msg,
|
||||||
|
channel: self.tabs[clientId].channelId
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query SEND_PAD_MSG');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cb();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
self.tabs[client.id].msgEv = msgEv;
|
||||||
|
|
||||||
|
self.tabs[client.id].close = function () {
|
||||||
|
Rpc._removeClient(client.id);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
self.addEventListener('message', function (e) {
|
||||||
|
var cId = e.source.id;
|
||||||
|
if (e.data === "INIT") {
|
||||||
|
if (tabs[cId]) { return; }
|
||||||
|
tabs[cId] = {
|
||||||
|
client: e.source
|
||||||
|
};
|
||||||
|
init(e.source, function () {
|
||||||
|
postMsg(e.source, 'SW_READY');
|
||||||
|
});
|
||||||
|
} else if (e.data === "CLOSE") {
|
||||||
|
if (tabs[cId] && tabs[cId].close) {
|
||||||
|
console.log('leave');
|
||||||
|
tabs[cId].close();
|
||||||
|
}
|
||||||
|
} else if (self.tabs[cId] && self.tabs[cId].msgEv) {
|
||||||
|
self.tabs[cId].msgEv.fire(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.addEventListener('install', function (e) {
|
||||||
|
debug('V1 installing…');
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', function (e) {
|
||||||
|
debug('V1 now ready to handle fetches!');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
174
www/common/outer/sharedworker.js
Normal file
174
www/common/outer/sharedworker.js
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/* jshint ignore:start */
|
||||||
|
importScripts('/bower_components/requirejs/require.js');
|
||||||
|
|
||||||
|
window = self;
|
||||||
|
localStorage = {
|
||||||
|
setItem: function (k, v) { localStorage[k] = v; },
|
||||||
|
getItem: function (k) { return localStorage[k]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
self.tabs = {};
|
||||||
|
|
||||||
|
var postMsg = function (client, data) {
|
||||||
|
client.port.postMessage(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
var debug = function (msg) { console.log(msg); };
|
||||||
|
// debug = function () {};
|
||||||
|
|
||||||
|
var init = function (client, cb) {
|
||||||
|
debug('SharedW INIT');
|
||||||
|
|
||||||
|
require([
|
||||||
|
'/common/requireconfig.js'
|
||||||
|
], function (RequireConfig) {
|
||||||
|
require.config(RequireConfig());
|
||||||
|
require([
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/common/outer/worker-channel.js',
|
||||||
|
'/common/outer/store-rpc.js'
|
||||||
|
], function (Util, Channel, SRpc) {
|
||||||
|
debug('SharedW Required ressources loaded');
|
||||||
|
var msgEv = Util.mkEvent();
|
||||||
|
|
||||||
|
if (!self.Rpc) {
|
||||||
|
self.Rpc = SRpc();
|
||||||
|
}
|
||||||
|
var Rpc = self.Rpc;
|
||||||
|
|
||||||
|
var postToClient = function (data) {
|
||||||
|
postMsg(client, data);
|
||||||
|
};
|
||||||
|
Channel.create(msgEv, postToClient, function (chan) {
|
||||||
|
debug('SharedW Channel created');
|
||||||
|
|
||||||
|
var clientId = client.id;
|
||||||
|
client.chan = chan;
|
||||||
|
Object.keys(Rpc.queries).forEach(function (q) {
|
||||||
|
if (q === 'CONNECT') { return; }
|
||||||
|
if (q === 'JOIN_PAD') { return; }
|
||||||
|
if (q === 'SEND_PAD_MSG') { return; }
|
||||||
|
chan.on(q, function (data, cb) {
|
||||||
|
try {
|
||||||
|
Rpc.queries[q](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query ' + q);
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
if (q === "DISCONNECT") {
|
||||||
|
console.log('Deleting existing store!');
|
||||||
|
delete self.Rpc;
|
||||||
|
delete self.store;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
chan.on('CONNECT', function (cfg, cb) {
|
||||||
|
debug('SharedW connecting to store...');
|
||||||
|
if (self.store) {
|
||||||
|
debug('Store already exists!');
|
||||||
|
if (cfg.driveEvents) {
|
||||||
|
Rpc._subscribeToDrive(clientId);
|
||||||
|
}
|
||||||
|
if (cfg.messenger) {
|
||||||
|
Rpc._subscribeToMessenger(clientId);
|
||||||
|
}
|
||||||
|
return void cb(self.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('Loading new async store');
|
||||||
|
// One-time initialization (init async-store)
|
||||||
|
cfg.query = function (cId, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
cfg.broadcast = function (excludes, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
Object.keys(self.tabs).forEach(function (cId) {
|
||||||
|
if (excludes.indexOf(cId) !== -1) { return; }
|
||||||
|
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
|
||||||
|
if (cfg.driveEvents) {
|
||||||
|
Rpc._subscribeToDrive(clientId);
|
||||||
|
}
|
||||||
|
if (cfg.messenger) {
|
||||||
|
Rpc._subscribeToMessenger(clientId);
|
||||||
|
}
|
||||||
|
if (data && data.state === "ALREADY_INIT") {
|
||||||
|
self.store = data.returned;
|
||||||
|
return void cb(data.returned);
|
||||||
|
}
|
||||||
|
self.store = data;
|
||||||
|
cb(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
chan.on('JOIN_PAD', function (data, cb) {
|
||||||
|
client.channelId = data.channel;
|
||||||
|
try {
|
||||||
|
Rpc.queries['JOIN_PAD'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query JOIN_PAD');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chan.on('SEND_PAD_MSG', function (msg, cb) {
|
||||||
|
var data = {
|
||||||
|
msg: msg,
|
||||||
|
channel: client.channelId
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query SEND_PAD_MSG');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cb();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
client.msgEv = msgEv;
|
||||||
|
|
||||||
|
client.close = function () {
|
||||||
|
Rpc._removeClient(client.id);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onconnect = function(e) {
|
||||||
|
debug('New SharedWorker client');
|
||||||
|
var port = e.ports[0];
|
||||||
|
var cId = Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
|
||||||
|
var client = self.tabs[cId] = {
|
||||||
|
id: cId,
|
||||||
|
port: port
|
||||||
|
};
|
||||||
|
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
if (e.data === "INIT") {
|
||||||
|
if (client.init) { return; }
|
||||||
|
client.init = true;
|
||||||
|
init(client, function () {
|
||||||
|
postMsg(client, 'SW_READY');
|
||||||
|
});
|
||||||
|
} else if (e.data === "CLOSE") {
|
||||||
|
if (client && client.close) {
|
||||||
|
console.log('leave');
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
} else if (client && client.msgEv) {
|
||||||
|
client.msgEv.fire(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
@ -1,193 +1,99 @@
|
|||||||
define([
|
define([
|
||||||
'/common/outer/async-store.js'
|
'/common/outer/async-store.js'
|
||||||
], function (Store) {
|
], function (AStore) {
|
||||||
|
|
||||||
|
var create = function () {
|
||||||
|
var Store = AStore.create();
|
||||||
|
|
||||||
var Rpc = {};
|
var Rpc = {};
|
||||||
|
|
||||||
Rpc.query = function (cmd, data, cb) {
|
var queries = Rpc.queries = {
|
||||||
switch (cmd) {
|
// Ready
|
||||||
// READY
|
CONNECT: Store.init,
|
||||||
case 'CONNECT': {
|
DISCONNECT: Store.disconnect,
|
||||||
Store.init(data, cb); break;
|
CREATE_README: Store.createReadme,
|
||||||
}
|
MIGRATE_ANON_DRIVE: Store.migrateAnonDrive,
|
||||||
case 'DISCONNECT': {
|
|
||||||
Store.disconnect(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'CREATE_README': {
|
|
||||||
Store.createReadme(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'MIGRATE_ANON_DRIVE': {
|
|
||||||
Store.migrateAnonDrive(data, cb); break;
|
|
||||||
}
|
|
||||||
// RPC
|
// RPC
|
||||||
case 'INIT_RPC': {
|
INIT_RPC: Store.initRpc,
|
||||||
Store.initRpc(data, cb); break;
|
UPDATE_PIN_LIMIT: Store.updatePinLimit,
|
||||||
}
|
GET_PIN_LIMIT: Store.getPinLimit,
|
||||||
case 'UPDATE_PIN_LIMIT': {
|
CLEAR_OWNED_CHANNEL: Store.clearOwnedChannel,
|
||||||
Store.updatePinLimit(data, cb); break;
|
REMOVE_OWNED_CHANNEL: Store.removeOwnedChannel,
|
||||||
}
|
UPLOAD_CHUNK: Store.uploadChunk,
|
||||||
case 'GET_PIN_LIMIT': {
|
UPLOAD_COMPLETE: Store.uploadComplete,
|
||||||
Store.getPinLimit(data, cb); break;
|
UPLOAD_STATUS: Store.uploadStatus,
|
||||||
}
|
UPLOAD_CANCEL: Store.uploadCancel,
|
||||||
case 'CLEAR_OWNED_CHANNEL': {
|
WRITE_LOGIN_BLOCK: Store.writeLoginBlock,
|
||||||
Store.clearOwnedChannel(data, cb); break;
|
PIN_PADS: Store.pinPads,
|
||||||
}
|
UNPIN_PADS: Store.unpinPads,
|
||||||
case 'REMOVE_OWNED_CHANNEL': {
|
GET_DELETED_PADS: Store.getDeletedPads,
|
||||||
Store.removeOwnedChannel(data, cb); break;
|
GET_PINNED_USAGE: Store.getPinnedUsage,
|
||||||
}
|
|
||||||
case 'UPLOAD_CHUNK': {
|
|
||||||
Store.uploadChunk(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'UPLOAD_COMPLETE': {
|
|
||||||
Store.uploadComplete(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'UPLOAD_STATUS': {
|
|
||||||
Store.uploadStatus(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'UPLOAD_CANCEL': {
|
|
||||||
Store.uploadCancel(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'PIN_PADS': {
|
|
||||||
Store.pinPads(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'UNPIN_PADS': {
|
|
||||||
Store.unpinPads(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_DELETED_PADS': {
|
|
||||||
Store.getDeletedPads(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_PINNED_USAGE': {
|
|
||||||
Store.getPinnedUsage(data, cb); break;
|
|
||||||
}
|
|
||||||
// ANON RPC
|
// ANON RPC
|
||||||
case 'INIT_ANON_RPC': {
|
INIT_ANON_RPC: Store.initAnonRpc,
|
||||||
Store.initAnonRpc(data, cb); break;
|
ANON_RPC_MESSAGE: Store.anonRpcMsg,
|
||||||
}
|
GET_FILE_SIZE: Store.getFileSize,
|
||||||
case 'ANON_RPC_MESSAGE': {
|
GET_MULTIPLE_FILE_SIZE: Store.getMultipleFileSize,
|
||||||
Store.anonRpcMsg(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_FILE_SIZE': {
|
|
||||||
Store.getFileSize(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_MULTIPLE_FILE_SIZE': {
|
|
||||||
Store.getMultipleFileSize(data, cb); break;
|
|
||||||
}
|
|
||||||
// Store
|
// Store
|
||||||
case 'GET': {
|
GET: Store.get,
|
||||||
Store.get(data, cb); break;
|
SET: Store.set,
|
||||||
}
|
ADD_PAD: Store.addPad,
|
||||||
case 'SET': {
|
SET_PAD_TITLE: Store.setPadTitle,
|
||||||
Store.set(data, cb); break;
|
MOVE_TO_TRASH: Store.moveToTrash,
|
||||||
}
|
RESET_DRIVE: Store.resetDrive,
|
||||||
case 'ADD_PAD': {
|
GET_METADATA: Store.getMetadata,
|
||||||
Store.addPad(data, cb); break;
|
SET_DISPLAY_NAME: Store.setDisplayName,
|
||||||
}
|
SET_PAD_ATTRIBUTE: Store.setPadAttribute,
|
||||||
case 'SET_PAD_TITLE': {
|
GET_PAD_ATTRIBUTE: Store.getPadAttribute,
|
||||||
Store.setPadTitle(data, cb); break;
|
SET_ATTRIBUTE: Store.setAttribute,
|
||||||
}
|
GET_ATTRIBUTE: Store.getAttribute,
|
||||||
case 'MOVE_TO_TRASH': {
|
LIST_ALL_TAGS: Store.listAllTags,
|
||||||
Store.moveToTrash(data, cb); break;
|
GET_TEMPLATES: Store.getTemplates,
|
||||||
}
|
GET_SECURE_FILES_LIST: Store.getSecureFilesList,
|
||||||
case 'RESET_DRIVE': {
|
GET_PAD_DATA: Store.getPadData,
|
||||||
Store.resetDrive(data, cb); break;
|
GET_STRONGER_HASH: Store.getStrongerHash,
|
||||||
}
|
INCREMENT_TEMPLATE_USE: Store.incrementTemplateUse,
|
||||||
case 'GET_METADATA': {
|
|
||||||
Store.getMetadata(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'SET_DISPLAY_NAME': {
|
|
||||||
Store.setDisplayName(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'SET_PAD_ATTRIBUTE': {
|
|
||||||
Store.setPadAttribute(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_PAD_ATTRIBUTE': {
|
|
||||||
Store.getPadAttribute(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'SET_ATTRIBUTE': {
|
|
||||||
Store.setAttribute(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_ATTRIBUTE': {
|
|
||||||
Store.getAttribute(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'LIST_ALL_TAGS': {
|
|
||||||
Store.listAllTags(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_TEMPLATES': {
|
|
||||||
Store.getTemplates(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_SECURE_FILES_LIST': {
|
|
||||||
Store.getSecureFilesList(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_PAD_DATA': {
|
|
||||||
Store.getPadData(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'GET_STRONGER_HASH': {
|
|
||||||
Store.getStrongerHash(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'INCREMENT_TEMPLATE_USE': {
|
|
||||||
Store.incrementTemplateUse(data); break;
|
|
||||||
}
|
|
||||||
// Messaging
|
// Messaging
|
||||||
case 'INVITE_FROM_USERLIST': {
|
INVITE_FROM_USERLIST: Store.inviteFromUserlist,
|
||||||
Store.inviteFromUserlist(data, cb); break;
|
ADD_DIRECT_MESSAGE_HANDLERS: Store.addDirectMessageHandlers,
|
||||||
}
|
|
||||||
// Messenger
|
// Messenger
|
||||||
case 'CONTACTS_GET_FRIEND_LIST': {
|
CONTACTS_GET_FRIEND_LIST: Store.messenger.getFriendList,
|
||||||
Store.messenger.getFriendList(data, cb); break;
|
CONTACTS_GET_MY_INFO: Store.messenger.getMyInfo,
|
||||||
}
|
CONTACTS_GET_FRIEND_INFO: Store.messenger.getFriendInfo,
|
||||||
case 'CONTACTS_GET_MY_INFO': {
|
CONTACTS_REMOVE_FRIEND: Store.messenger.removeFriend,
|
||||||
Store.messenger.getMyInfo(data, cb); break;
|
CONTACTS_OPEN_FRIEND_CHANNEL: Store.messenger.openFriendChannel,
|
||||||
}
|
CONTACTS_GET_FRIEND_STATUS: Store.messenger.getFriendStatus,
|
||||||
case 'CONTACTS_GET_FRIEND_INFO': {
|
CONTACTS_GET_MORE_HISTORY: Store.messenger.getMoreHistory,
|
||||||
Store.messenger.getFriendInfo(data, cb); break;
|
CONTACTS_SEND_MESSAGE: Store.messenger.sendMessage,
|
||||||
}
|
CONTACTS_SET_CHANNEL_HEAD: Store.messenger.setChannelHead,
|
||||||
case 'CONTACTS_REMOVE_FRIEND': {
|
|
||||||
Store.messenger.removeFriend(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_OPEN_FRIEND_CHANNEL': {
|
|
||||||
Store.messenger.openFriendChannel(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_GET_FRIEND_STATUS': {
|
|
||||||
Store.messenger.getFriendStatus(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_GET_MORE_HISTORY': {
|
|
||||||
Store.messenger.getMoreHistory(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_SEND_MESSAGE': {
|
|
||||||
Store.messenger.sendMessage(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'CONTACTS_SET_CHANNEL_HEAD': {
|
|
||||||
Store.messenger.setChannelHead(data, cb); break;
|
|
||||||
}
|
|
||||||
// Pad
|
// Pad
|
||||||
case 'SEND_PAD_MSG': {
|
SEND_PAD_MSG: Store.sendPadMsg,
|
||||||
Store.sendPadMsg(data, cb); break;
|
JOIN_PAD: Store.joinPad,
|
||||||
}
|
LEAVE_PAD: Store.leavePad,
|
||||||
case 'JOIN_PAD': {
|
GET_FULL_HISTORY: Store.getFullHistory,
|
||||||
Store.joinPad(data, cb); break;
|
GET_HISTORY_RANGE: Store.getHistoryRange,
|
||||||
}
|
IS_NEW_CHANNEL: Store.isNewChannel,
|
||||||
case 'GET_FULL_HISTORY': {
|
|
||||||
Store.getFullHistory(data, cb); break;
|
|
||||||
}
|
|
||||||
// Drive
|
// Drive
|
||||||
case 'DRIVE_USEROBJECT': {
|
DRIVE_USEROBJECT: Store.userObjectCommand,
|
||||||
Store.userObjectCommand(data, cb); break;
|
// Settings,
|
||||||
}
|
DELETE_ACCOUNT: Store.deleteAccount,
|
||||||
// Settings
|
|
||||||
case 'DELETE_ACCOUNT': {
|
|
||||||
Store.deleteAccount(data, cb); break;
|
|
||||||
}
|
|
||||||
case 'IS_NEW_CHANNEL': {
|
|
||||||
Store.isNewChannel(data, cb); break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
console.error("UNHANDLED_STORE_RPC");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Rpc.query = function (cmd, data, cb) {
|
||||||
|
if (queries[cmd]) {
|
||||||
|
queries[cmd]('0', data, cb);
|
||||||
|
} else {
|
||||||
|
console.error('UNHANDLED_STORE_RPC');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal calls
|
||||||
|
Rpc._removeClient = Store._removeClient;
|
||||||
|
Rpc._subscribeToDrive = Store._subscribeToDrive;
|
||||||
|
Rpc._subscribeToMessenger = Store._subscribeToMessenger;
|
||||||
|
|
||||||
return Rpc;
|
return Rpc;
|
||||||
|
};
|
||||||
|
|
||||||
|
return create;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -11,9 +11,7 @@ define([
|
|||||||
var u8 = file.blob; // This is not a blob but a uint8array
|
var u8 = file.blob; // This is not a blob but a uint8array
|
||||||
var metadata = file.metadata;
|
var metadata = file.metadata;
|
||||||
|
|
||||||
var owned = file.isOwned;
|
var owned = file.owned;
|
||||||
// XXX
|
|
||||||
owned = true;
|
|
||||||
|
|
||||||
// if it exists, path contains the new pad location in the drive
|
// if it exists, path contains the new pad location in the drive
|
||||||
var path = file.path;
|
var path = file.path;
|
||||||
|
|||||||
@ -41,6 +41,7 @@ define([
|
|||||||
if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); }
|
if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); }
|
||||||
var data = exp.getFileData(id);
|
var data = exp.getFileData(id);
|
||||||
data[attr] = clone(value);
|
data[attr] = clone(value);
|
||||||
|
console.log(data);
|
||||||
cb(null);
|
cb(null);
|
||||||
};
|
};
|
||||||
exp.getPadAttribute = function (href, attr, cb) {
|
exp.getPadAttribute = function (href, attr, cb) {
|
||||||
@ -111,7 +112,7 @@ define([
|
|||||||
// RPC may not be responding
|
// RPC may not be responding
|
||||||
// Send a report that can be handled manually
|
// Send a report that can be handled manually
|
||||||
console.error(obj.error);
|
console.error(obj.error);
|
||||||
Feedback.send('ERROR_DELETING_OWNED_PAD=' + channelId, true);
|
Feedback.send('ERROR_DELETING_OWNED_PAD=' + channelId + '|' + obj.error, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -426,7 +427,7 @@ define([
|
|||||||
migrateToNewFormat(cb);
|
migrateToNewFormat(cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
exp.fixFiles = function () {
|
exp.fixFiles = function (silent) {
|
||||||
// Explore the tree and check that everything is correct:
|
// Explore the tree and check that everything is correct:
|
||||||
// * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects
|
// * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects
|
||||||
// * ROOT: Folders are objects, files are href
|
// * ROOT: Folders are objects, files are href
|
||||||
@ -435,6 +436,9 @@ define([
|
|||||||
// - Dates (adate, cdate) can be parsed/formatted
|
// - Dates (adate, cdate) can be parsed/formatted
|
||||||
// - All files in filesData should be either in 'root', 'trash' or 'unsorted'. If that's not the case, copy the fily to 'unsorted'
|
// - All files in filesData should be either in 'root', 'trash' or 'unsorted'. If that's not the case, copy the fily to 'unsorted'
|
||||||
// * TEMPLATE: Contains only files (href), and does not contains files that are in ROOT
|
// * TEMPLATE: Contains only files (href), and does not contains files that are in ROOT
|
||||||
|
|
||||||
|
if (silent) { debug = function () {}; }
|
||||||
|
|
||||||
debug("Cleaning file system...");
|
debug("Cleaning file system...");
|
||||||
|
|
||||||
var before = JSON.stringify(files);
|
var before = JSON.stringify(files);
|
||||||
|
|||||||
100
www/common/outer/webworker.js
Normal file
100
www/common/outer/webworker.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/* jshint ignore:start */
|
||||||
|
importScripts('/bower_components/requirejs/require.js');
|
||||||
|
|
||||||
|
window = self;
|
||||||
|
localStorage = {
|
||||||
|
setItem: function (k, v) { localStorage[k] = v; },
|
||||||
|
getItem: function (k) { return localStorage[k]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
require([
|
||||||
|
'/common/requireconfig.js'
|
||||||
|
], function (RequireConfig) {
|
||||||
|
require.config(RequireConfig());
|
||||||
|
require([
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/common/outer/worker-channel.js',
|
||||||
|
'/common/outer/store-rpc.js'
|
||||||
|
], function (Util, Channel, SRpc) {
|
||||||
|
var msgEv = Util.mkEvent();
|
||||||
|
|
||||||
|
var Rpc = SRpc();
|
||||||
|
|
||||||
|
Channel.create(msgEv, postMessage, function (chan) {
|
||||||
|
var clientId = '1';
|
||||||
|
Object.keys(Rpc.queries).forEach(function (q) {
|
||||||
|
if (q === 'CONNECT') { return; }
|
||||||
|
if (q === 'JOIN_PAD') { return; }
|
||||||
|
if (q === 'SEND_PAD_MSG') { return; }
|
||||||
|
chan.on(q, function (data, cb) {
|
||||||
|
try {
|
||||||
|
Rpc.queries[q](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query ' + q);
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
chan.on('CONNECT', function (cfg, cb) {
|
||||||
|
// load Store here, with cfg, and pass a "query" (chan.query)
|
||||||
|
// cId is a clientId used in ServiceWorker or SharedWorker
|
||||||
|
cfg.query = function (cId, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
cfg.broadcast = function (excludes, cmd, data, cb) {
|
||||||
|
cb = cb || function () {};
|
||||||
|
if (excludes.indexOf(clientId) !== -1) { return; }
|
||||||
|
chan.query(cmd, data, function (err, data2) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(data2);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
|
||||||
|
if (data && data.state === "ALREADY_INIT") {
|
||||||
|
return void cb(data);
|
||||||
|
}
|
||||||
|
if (cfg.driveEvents) {
|
||||||
|
Rpc._subscribeToDrive(clientId);
|
||||||
|
}
|
||||||
|
if (cfg.messenger) {
|
||||||
|
Rpc._subscribeToMessenger(clientId);
|
||||||
|
}
|
||||||
|
cb(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var chanId;
|
||||||
|
chan.on('JOIN_PAD', function (data, cb) {
|
||||||
|
chanId = data.channel;
|
||||||
|
try {
|
||||||
|
Rpc.queries['JOIN_PAD'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query JOIN_PAD');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chan.on('SEND_PAD_MSG', function (msg, cb) {
|
||||||
|
var data = {
|
||||||
|
msg: msg,
|
||||||
|
channel: chanId
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in webworker when executing query SEND_PAD_MSG');
|
||||||
|
console.error(e);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
onmessage = function (e) {
|
||||||
|
msgEv.fire(e);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
149
www/common/outer/worker-channel.js
Normal file
149
www/common/outer/worker-channel.js
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// This file provides the API for the channel for talking to and from the sandbox iframe.
|
||||||
|
define([
|
||||||
|
//'/common/sframe-protocol.js',
|
||||||
|
'/common/common-util.js'
|
||||||
|
], function (/*SFrameProtocol,*/ Util) {
|
||||||
|
|
||||||
|
var mkTxid = function () {
|
||||||
|
return Math.random().toString(16).replace('0.', '') + Math.random().toString(16).replace('0.', '');
|
||||||
|
};
|
||||||
|
|
||||||
|
var create = function (onMsg, postMsg, cb, isWorker) {
|
||||||
|
var chanLoaded;
|
||||||
|
var waitingData;
|
||||||
|
if (!isWorker) {
|
||||||
|
chanLoaded = false;
|
||||||
|
waitingData = [];
|
||||||
|
onMsg.reg(function (data) {
|
||||||
|
if (chanLoaded) { return; }
|
||||||
|
waitingData.push(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var evReady = Util.mkEvent(true);
|
||||||
|
|
||||||
|
var handlers = {};
|
||||||
|
var queries = {};
|
||||||
|
|
||||||
|
// list of handlers which are registered from the other side...
|
||||||
|
var insideHandlers = [];
|
||||||
|
var callWhenRegistered = {};
|
||||||
|
|
||||||
|
var chan = {};
|
||||||
|
|
||||||
|
// Send a query. channel.query('Q_SOMETHING', { args: "whatever" }, function (reply) { ... });
|
||||||
|
chan.query = function (q, content, cb) {
|
||||||
|
var txid = mkTxid();
|
||||||
|
var timeout = setTimeout(function () {
|
||||||
|
delete queries[txid];
|
||||||
|
//console.log("Timeout making query " + q);
|
||||||
|
}, 30000);
|
||||||
|
queries[txid] = function (data, msg) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
delete queries[txid];
|
||||||
|
cb(undefined, data.content, msg);
|
||||||
|
};
|
||||||
|
evReady.reg(function () {
|
||||||
|
postMsg(JSON.stringify({
|
||||||
|
txid: txid,
|
||||||
|
content: content,
|
||||||
|
q: q
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fire an event. channel.event('EV_SOMETHING', { args: "whatever" });
|
||||||
|
var event = chan.event = function (e, content) {
|
||||||
|
evReady.reg(function () {
|
||||||
|
postMsg(JSON.stringify({ content: content, q: e }));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Be notified on query or event. channel.on('EV_SOMETHING', function (args, reply) { ... });
|
||||||
|
// If the type is a query, your handler will be invoked with a reply function that takes
|
||||||
|
// one argument (the content to reply with).
|
||||||
|
chan.on = function (queryType, handler, quiet) {
|
||||||
|
(handlers[queryType] = handlers[queryType] || []).push(function (data, msg) {
|
||||||
|
handler(data.content, function (replyContent) {
|
||||||
|
postMsg(JSON.stringify({
|
||||||
|
txid: data.txid,
|
||||||
|
content: replyContent
|
||||||
|
}));
|
||||||
|
}, msg);
|
||||||
|
});
|
||||||
|
if (!quiet) {
|
||||||
|
event('EV_REGISTER_HANDLER', queryType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If a particular handler is registered, call the callback immediately, otherwise it will be called
|
||||||
|
// when that handler is first registered.
|
||||||
|
// channel.whenReg('Q_SOMETHING', function () { ...query Q_SOMETHING?... });
|
||||||
|
chan.whenReg = function (queryType, cb, always) {
|
||||||
|
var reg = always;
|
||||||
|
if (insideHandlers.indexOf(queryType) > -1) {
|
||||||
|
cb();
|
||||||
|
} else {
|
||||||
|
reg = true;
|
||||||
|
}
|
||||||
|
if (reg) {
|
||||||
|
(callWhenRegistered[queryType] = callWhenRegistered[queryType] || []).push(cb);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Same as whenReg except it will invoke every time there is another registration, not just once.
|
||||||
|
chan.onReg = function (queryType, cb) { chan.whenReg(queryType, cb, true); };
|
||||||
|
|
||||||
|
chan.on('EV_REGISTER_HANDLER', function (content) {
|
||||||
|
if (callWhenRegistered[content]) {
|
||||||
|
callWhenRegistered[content].forEach(function (f) { f(); });
|
||||||
|
delete callWhenRegistered[content];
|
||||||
|
}
|
||||||
|
insideHandlers.push(content);
|
||||||
|
});
|
||||||
|
chan.whenReg('EV_REGISTER_HANDLER', evReady.fire);
|
||||||
|
|
||||||
|
// Make sure both iframes are ready
|
||||||
|
var isReady =false;
|
||||||
|
chan.onReady = function (h) {
|
||||||
|
if (isReady) {
|
||||||
|
return void h();
|
||||||
|
}
|
||||||
|
if (typeof(h) !== "function") { return; }
|
||||||
|
chan.on('EV_RPC_READY', function () { isReady = true; h(); });
|
||||||
|
};
|
||||||
|
chan.ready = function () {
|
||||||
|
chan.whenReg('EV_RPC_READY', function () {
|
||||||
|
chan.event('EV_RPC_READY');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMsg.reg(function (msg) {
|
||||||
|
var data = JSON.parse(msg.data);
|
||||||
|
if (typeof(data.q) === 'string' && handlers[data.q]) {
|
||||||
|
handlers[data.q].forEach(function (f) {
|
||||||
|
f(data || JSON.parse(msg.data), msg);
|
||||||
|
data = undefined;
|
||||||
|
});
|
||||||
|
} else if (typeof(data.q) === 'undefined' && queries[data.txid]) {
|
||||||
|
queries[data.txid](data, msg);
|
||||||
|
} else {
|
||||||
|
console.log("DROP Unhandled message");
|
||||||
|
console.log(msg.data, isWorker);
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (isWorker) {
|
||||||
|
evReady.fire();
|
||||||
|
} else {
|
||||||
|
chanLoaded = true;
|
||||||
|
waitingData.forEach(function (d) {
|
||||||
|
onMsg.fire(d);
|
||||||
|
});
|
||||||
|
waitingData = [];
|
||||||
|
}
|
||||||
|
cb(chan);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { create: create };
|
||||||
|
});
|
||||||
@ -221,6 +221,10 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exp.writeLoginBlock = function (data, cb) {
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
|
||||||
cb(e, exp);
|
cb(e, exp);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -140,6 +140,11 @@ define([
|
|||||||
toolbar.initializing();
|
toolbar.initializing();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (text) {
|
||||||
|
// text is a boolean here. It means we won't try to reconnect
|
||||||
|
toolbar.failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
toolbar.reconnecting();
|
toolbar.reconnecting();
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -171,9 +176,12 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var contentUpdate = function (newContent) {
|
var oldContent;
|
||||||
|
var contentUpdate = function (newContent, waitFor) {
|
||||||
|
if (JSONSortify(newContent) === JSONSortify(oldContent)) { return; }
|
||||||
try {
|
try {
|
||||||
evContentUpdate.fire(newContent);
|
evContentUpdate.fire(newContent, waitFor);
|
||||||
|
setTimeout(function () { oldContent = newContent; });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e.stack);
|
console.log(e.stack);
|
||||||
UI.errorLoadingScreen(e.message);
|
UI.errorLoadingScreen(e.message);
|
||||||
@ -192,8 +200,9 @@ define([
|
|||||||
cpNfInner.metadataMgr.updateMetadata(meta);
|
cpNfInner.metadataMgr.updateMetadata(meta);
|
||||||
newContent = normalize(newContent);
|
newContent = normalize(newContent);
|
||||||
|
|
||||||
contentUpdate(newContent);
|
nThen(function (waitFor) {
|
||||||
|
contentUpdate(newContent, waitFor);
|
||||||
|
}).nThen(function () {
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
var newContent2NoMeta = normalize(contentGetter());
|
var newContent2NoMeta = normalize(contentGetter());
|
||||||
var newContent2StrNoMeta = JSONSortify(newContent2NoMeta);
|
var newContent2StrNoMeta = JSONSortify(newContent2NoMeta);
|
||||||
@ -232,6 +241,7 @@ define([
|
|||||||
if (JSONSortify(newContent) !== JSONSortify(oldContent)) {
|
if (JSONSortify(newContent) !== JSONSortify(oldContent)) {
|
||||||
common.notify();
|
common.notify();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var setHistoryMode = function (bool, update) {
|
var setHistoryMode = function (bool, update) {
|
||||||
@ -284,11 +294,13 @@ define([
|
|||||||
var newPad = false;
|
var newPad = false;
|
||||||
if (newContentStr === '') { newPad = true; }
|
if (newContentStr === '') { newPad = true; }
|
||||||
|
|
||||||
|
// contentUpdate may be async so we need an nthen here
|
||||||
|
nThen(function (waitFor) {
|
||||||
if (!newPad) {
|
if (!newPad) {
|
||||||
var newContent = JSON.parse(newContentStr);
|
var newContent = JSON.parse(newContentStr);
|
||||||
cpNfInner.metadataMgr.updateMetadata(extractMetadata(newContent));
|
cpNfInner.metadataMgr.updateMetadata(extractMetadata(newContent));
|
||||||
newContent = normalize(newContent);
|
newContent = normalize(newContent);
|
||||||
contentUpdate(newContent);
|
contentUpdate(newContent, waitFor);
|
||||||
} else {
|
} else {
|
||||||
if (!cpNfInner.metadataMgr.getPrivateData().isNewFile) {
|
if (!cpNfInner.metadataMgr.getPrivateData().isNewFile) {
|
||||||
// We're getting 'new pad' but there is an existing file
|
// We're getting 'new pad' but there is an existing file
|
||||||
@ -305,6 +317,7 @@ define([
|
|||||||
title.updateTitle(title.defaultTitle);
|
title.updateTitle(title.defaultTitle);
|
||||||
evOnDefaultContentNeeded.fire();
|
evOnDefaultContentNeeded.fire();
|
||||||
}
|
}
|
||||||
|
}).nThen(function () {
|
||||||
stateChange(STATE.READY);
|
stateChange(STATE.READY);
|
||||||
firstConnection = false;
|
firstConnection = false;
|
||||||
if (!readOnly) { onLocal(); }
|
if (!readOnly) { onLocal(); }
|
||||||
@ -336,10 +349,11 @@ define([
|
|||||||
if (newPad && (!AppConfig.displayCreationScreen || (!skipTemp && skipCreation))) {
|
if (newPad && (!AppConfig.displayCreationScreen || (!skipTemp && skipCreation))) {
|
||||||
common.openTemplatePicker();
|
common.openTemplatePicker();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
var onConnectionChange = function (info) {
|
var onConnectionChange = function (info) {
|
||||||
if (state === STATE.DELETED) { return; }
|
if (state === STATE.DELETED) { return; }
|
||||||
stateChange(info.state ? STATE.INITIALIZING : STATE.DISCONNECTED);
|
stateChange(info.state ? STATE.INITIALIZING : STATE.DISCONNECTED, info.permanent);
|
||||||
/*if (info.state) {
|
/*if (info.state) {
|
||||||
UI.findOKButton().click();
|
UI.findOKButton().click();
|
||||||
} else {
|
} else {
|
||||||
@ -380,13 +394,19 @@ define([
|
|||||||
common.createButton('import', true, options, function (c, f) {
|
common.createButton('import', true, options, function (c, f) {
|
||||||
if (async) {
|
if (async) {
|
||||||
fi(c, f, function (content) {
|
fi(c, f, function (content) {
|
||||||
contentUpdate(content);
|
nThen(function (waitFor) {
|
||||||
|
contentUpdate(content, waitFor);
|
||||||
|
}).nThen(function () {
|
||||||
onLocal();
|
onLocal();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
contentUpdate(fi(c, f));
|
nThen(function (waitFor) {
|
||||||
|
contentUpdate(fi(c, f), waitFor);
|
||||||
|
}).nThen(function () {
|
||||||
onLocal();
|
onLocal();
|
||||||
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -79,10 +79,12 @@ define([
|
|||||||
evInfiniteSpinner.fire();
|
evInfiniteSpinner.fire();
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
sframeChan.on('EV_RT_DISCONNECT', function () {
|
sframeChan.on('EV_RT_DISCONNECT', function (isPermanent) {
|
||||||
isReady = false;
|
isReady = false;
|
||||||
chainpad.abort();
|
chainpad.abort();
|
||||||
onConnectionChange({ state: false });
|
// Permanent flag is here to choose if we wnat to display
|
||||||
|
// "reconnecting" or "disconnected" in the toolbar state
|
||||||
|
onConnectionChange({ state: false, permanent: isPermanent });
|
||||||
});
|
});
|
||||||
sframeChan.on('EV_RT_ERROR', function (err) {
|
sframeChan.on('EV_RT_ERROR', function (err) {
|
||||||
isReady = false;
|
isReady = false;
|
||||||
|
|||||||
@ -112,8 +112,12 @@ define([], function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
padRpc.onDisconnectEvent.reg(function () {
|
padRpc.onDisconnectEvent.reg(function (permanent) {
|
||||||
sframeChan.event('EV_RT_DISCONNECT');
|
sframeChan.event('EV_RT_DISCONNECT', permanent);
|
||||||
|
});
|
||||||
|
|
||||||
|
padRpc.onConnectEvent.reg(function (data) {
|
||||||
|
onOpen(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
padRpc.onErrorEvent.reg(function (err) {
|
padRpc.onErrorEvent.reg(function (err) {
|
||||||
@ -128,8 +132,6 @@ define([], function () {
|
|||||||
owners: owners,
|
owners: owners,
|
||||||
password: password,
|
password: password,
|
||||||
expire: expire
|
expire: expire
|
||||||
}, function(data) {
|
|
||||||
onOpen(data);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,24 @@
|
|||||||
define([
|
define([
|
||||||
'jquery',
|
'jquery',
|
||||||
'/common/common-interface.js',
|
'/common/common-interface.js',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
//'/bower_components/chainpad-json-validator/json-ot.js',
|
//'/bower_components/chainpad-json-validator/json-ot.js',
|
||||||
|
|
||||||
'/bower_components/chainpad/chainpad.dist.js',
|
'/bower_components/chainpad/chainpad.dist.js',
|
||||||
], function ($, UI, ChainPad /* JsonOT */) {
|
], function ($, UI, nThen, ChainPad /* JsonOT */) {
|
||||||
//var ChainPad = window.ChainPad;
|
//var ChainPad = window.ChainPad;
|
||||||
var History = {};
|
var History = {};
|
||||||
|
|
||||||
|
History.create = function (common, config) {
|
||||||
|
if (!config.$toolbar) { return void console.error("config.$toolbar is undefined");}
|
||||||
|
if (History.loading) { return void console.error("History is already being loaded..."); }
|
||||||
|
History.loading = true;
|
||||||
|
var $toolbar = config.$toolbar;
|
||||||
|
|
||||||
|
if (!config.applyVal || !config.setHistory || !config.onLocal || !config.onRemote) {
|
||||||
|
throw new Error("Missing config element: applyVal, onLocal, onRemote, setHistory");
|
||||||
|
}
|
||||||
|
|
||||||
var getStates = function (rt) {
|
var getStates = function (rt) {
|
||||||
var states = [];
|
var states = [];
|
||||||
var b = rt.getAuthBlock();
|
var b = rt.getAuthBlock();
|
||||||
@ -19,8 +30,7 @@ define([
|
|||||||
return states;
|
return states;
|
||||||
};
|
};
|
||||||
|
|
||||||
var loadHistory = function (config, common, cb) {
|
var createRealtime = function (config) {
|
||||||
var createRealtime = function () {
|
|
||||||
return ChainPad.create({
|
return ChainPad.create({
|
||||||
userName: 'history',
|
userName: 'history',
|
||||||
validateContent: function (content) {
|
validateContent: function (content) {
|
||||||
@ -33,36 +43,45 @@ define([
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
initialState: '',
|
initialState: '',
|
||||||
//patchTransformer: ChainPad.NaiveJSONTransformer,
|
|
||||||
//logLevel: 0,
|
|
||||||
//transformFunction: JsonOT.validate,
|
|
||||||
logLevel: config.debug ? 2 : 0,
|
logLevel: config.debug ? 2 : 0,
|
||||||
noPrune: true
|
noPrune: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var realtime = createRealtime();
|
|
||||||
|
|
||||||
History.readOnly = common.getMetadataMgr().getPrivateData().readOnly;
|
|
||||||
|
|
||||||
/*var to = window.setTimeout(function () {
|
|
||||||
cb('[GET_FULL_HISTORY_TIMEOUT]');
|
|
||||||
}, 30000);*/
|
|
||||||
|
|
||||||
|
var loadFullHistory = function (config, common, cb) {
|
||||||
|
var realtime = createRealtime(config);
|
||||||
common.getFullHistory(realtime, function () {
|
common.getFullHistory(realtime, function () {
|
||||||
//window.clearTimeout(to);
|
|
||||||
cb(null, realtime);
|
cb(null, realtime);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
loadFullHistory = loadFullHistory;
|
||||||
|
|
||||||
History.create = function (common, config) {
|
var fillChainPad = function (realtime, messages) {
|
||||||
if (!config.$toolbar) { return void console.error("config.$toolbar is undefined");}
|
messages.forEach(function (m) {
|
||||||
if (History.loading) { return void console.error("History is already being loaded..."); }
|
realtime.message(m);
|
||||||
History.loading = true;
|
});
|
||||||
var $toolbar = config.$toolbar;
|
};
|
||||||
|
|
||||||
if (!config.applyVal || !config.setHistory || !config.onLocal || !config.onRemote) {
|
var allMessages = [];
|
||||||
throw new Error("Missing config element: applyVal, onLocal, onRemote, setHistory");
|
var lastKnownHash;
|
||||||
}
|
var isComplete = false;
|
||||||
|
var loadMoreHistory = function (config, common, cb) {
|
||||||
|
if (isComplete) { return void cb ('EFULL'); }
|
||||||
|
var realtime = createRealtime(config);
|
||||||
|
var sframeChan = common.getSframeChannel();
|
||||||
|
|
||||||
|
sframeChan.query('Q_GET_HISTORY_RANGE', {
|
||||||
|
lastKnownHash: lastKnownHash
|
||||||
|
}, function (err, data) {
|
||||||
|
if (err) { return void console.error(err); }
|
||||||
|
if (!Array.isArray(data.messages)) { return void console.error('Not an array!'); }
|
||||||
|
lastKnownHash = data.lastKnownHash;
|
||||||
|
isComplete = data.isFull;
|
||||||
|
Array.prototype.unshift.apply(allMessages, data.messages); // Destructive concat
|
||||||
|
fillChainPad(realtime, allMessages);
|
||||||
|
cb (null, realtime);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// config.setHistory(bool, bool)
|
// config.setHistory(bool, bool)
|
||||||
// - bool1: history value
|
// - bool1: history value
|
||||||
@ -84,21 +103,20 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
config.setHistory(true);
|
config.setHistory(true);
|
||||||
var onReady = function () { };
|
|
||||||
|
|
||||||
var Messages = common.Messages;
|
var Messages = common.Messages;
|
||||||
|
|
||||||
var realtime;
|
var realtime;
|
||||||
|
|
||||||
var states = [];
|
var states = [];
|
||||||
var c = states.length - 1;
|
var c = 0;//states.length - 1;
|
||||||
|
|
||||||
var $hist = $toolbar.find('.cp-toolbar-history');
|
var $hist = $toolbar.find('.cp-toolbar-history');
|
||||||
var $left = $toolbar.find('.cp-toolbar-leftside');
|
var $left = $toolbar.find('.cp-toolbar-leftside');
|
||||||
var $right = $toolbar.find('.cp-toolbar-rightside');
|
var $right = $toolbar.find('.cp-toolbar-rightside');
|
||||||
var $cke = $toolbar.find('.cke_toolbox_main');
|
var $cke = $toolbar.find('.cke_toolbox_main');
|
||||||
|
|
||||||
$hist.html('').show();
|
$hist.html('').css('display', 'flex');
|
||||||
$left.hide();
|
$left.hide();
|
||||||
$right.hide();
|
$right.hide();
|
||||||
$cke.hide();
|
$cke.hide();
|
||||||
@ -107,29 +125,73 @@ define([
|
|||||||
|
|
||||||
var onUpdate;
|
var onUpdate;
|
||||||
|
|
||||||
var update = function () {
|
var update = function (newRt) {
|
||||||
|
realtime = newRt;
|
||||||
if (!realtime) { return []; }
|
if (!realtime) { return []; }
|
||||||
states = getStates(realtime);
|
states = getStates(realtime);
|
||||||
if (typeof onUpdate === "function") { onUpdate(); }
|
if (typeof onUpdate === "function") { onUpdate(); }
|
||||||
return states;
|
return states;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var $loadMore, $version, get;
|
||||||
|
|
||||||
// Get the content of the selected version, and change the version number
|
// Get the content of the selected version, and change the version number
|
||||||
var get = function (i) {
|
var loading = false;
|
||||||
|
var loadMore = function (cb) {
|
||||||
|
if (loading) { return; }
|
||||||
|
loading = true;
|
||||||
|
$loadMore.removeClass('fa fa-ellipsis-h')
|
||||||
|
.append($('<span>', {'class': 'fa fa-refresh fa-spin fa-3x fa-fw'}));
|
||||||
|
loadMoreHistory(config, common, function (err, newRt) {
|
||||||
|
if (err === 'EFULL') {
|
||||||
|
$loadMore.off('click').hide();
|
||||||
|
get(c);
|
||||||
|
$version.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading = false;
|
||||||
|
if (err) { return void console.error(err); }
|
||||||
|
update(newRt);
|
||||||
|
$loadMore.addClass('fa fa-ellipsis-h').html('');
|
||||||
|
get(c);
|
||||||
|
if (cb) { cb(); }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
get = function (i) {
|
||||||
i = parseInt(i);
|
i = parseInt(i);
|
||||||
if (isNaN(i)) { return; }
|
if (isNaN(i)) { return; }
|
||||||
if (i < 0) { i = 0; }
|
if (i > 0) { i = 0; }
|
||||||
if (i > states.length - 1) { i = states.length - 1; }
|
if (i < -(states.length - 2)) { i = -(states.length - 2); }
|
||||||
var val = states[i].getContent().doc;
|
if (i <= -(states.length - 11)) {
|
||||||
|
loadMore();
|
||||||
|
}
|
||||||
|
var idx = states.length - 1 + i;
|
||||||
|
var val = states[idx].getContent().doc;
|
||||||
c = i;
|
c = i;
|
||||||
if (typeof onUpdate === "function") { onUpdate(); }
|
if (typeof onUpdate === "function") { onUpdate(); }
|
||||||
$hist.find('.cp-toolbar-history-next, .cp-toolbar-history-previous').css('visibility', '');
|
$hist.find('.cp-toolbar-history-next, .cp-toolbar-history-previous, ' +
|
||||||
if (c === states.length - 1) { $hist.find('.cp-toolbar-history-next').css('visibility', 'hidden'); }
|
'.cp-toolbar-history-fast-next, .cp-toolbar-history-fast-previous')
|
||||||
if (c === 0) { $hist.find('.cp-toolbar-history-previous').css('visibility', 'hidden'); }
|
.css('visibility', '');
|
||||||
|
if (c === -(states.length-1)) {
|
||||||
|
$hist.find('.cp-toolbar-history-previous').css('visibility', 'hidden');
|
||||||
|
$hist.find('.cp-toolbar-history-fast-previous').css('visibility', 'hidden');
|
||||||
|
}
|
||||||
|
if (c === 0) {
|
||||||
|
$hist.find('.cp-toolbar-history-next').css('visibility', 'hidden');
|
||||||
|
$hist.find('.cp-toolbar-history-fast-next').css('visibility', 'hidden');
|
||||||
|
}
|
||||||
|
var $pos = $hist.find('.cp-toolbar-history-pos');
|
||||||
|
var p = 100 * (1 - (-c / (states.length-1)));
|
||||||
|
$pos.css('margin-left', p+'%');
|
||||||
|
|
||||||
|
// Display the version when the full history is loaded
|
||||||
|
// Note: the first version is always empty and probably can't be displayed, so
|
||||||
|
// we can consider we have only states.length - 1 versions
|
||||||
|
$version.text(idx + ' / ' + (states.length-1));
|
||||||
|
|
||||||
if (config.debug) {
|
if (config.debug) {
|
||||||
console.log(states[i]);
|
console.log(states[idx]);
|
||||||
var ops = states[i] && states[i].getPatch() && states[i].getPatch().operations;
|
var ops = states[idx] && states[idx].getPatch() && states[idx].getPatch().operations;
|
||||||
if (Array.isArray(ops)) {
|
if (Array.isArray(ops)) {
|
||||||
ops.forEach(function (op) { console.log(op); });
|
ops.forEach(function (op) { console.log(op); });
|
||||||
}
|
}
|
||||||
@ -148,6 +210,17 @@ define([
|
|||||||
// Create the history toolbar
|
// Create the history toolbar
|
||||||
var display = function () {
|
var display = function () {
|
||||||
$hist.html('');
|
$hist.html('');
|
||||||
|
|
||||||
|
var $rev = $('<button>', {
|
||||||
|
'class':'cp-toolbar-history-revert buttonSuccess fa fa-check-circle-o',
|
||||||
|
title: Messages.history_restoreTitle
|
||||||
|
}).appendTo($hist);//.text(Messages.history_restore);
|
||||||
|
if (History.readOnly) { $rev.css('visibility', 'hidden'); }
|
||||||
|
$('<span>', {'class': 'cp-history-filler'}).appendTo($hist);
|
||||||
|
var $fastPrev = $('<button>', {
|
||||||
|
'class': 'cp-toolbar-history-fast-previous fa fa-fast-backward buttonPrimary',
|
||||||
|
title: Messages.history_prev
|
||||||
|
}).appendTo($hist);
|
||||||
var $prev =$('<button>', {
|
var $prev =$('<button>', {
|
||||||
'class': 'cp-toolbar-history-previous fa fa-step-backward buttonPrimary',
|
'class': 'cp-toolbar-history-previous fa fa-step-backward buttonPrimary',
|
||||||
title: Messages.history_prev
|
title: Messages.history_prev
|
||||||
@ -157,58 +230,73 @@ define([
|
|||||||
'class': 'cp-toolbar-history-next fa fa-step-forward buttonPrimary',
|
'class': 'cp-toolbar-history-next fa fa-step-forward buttonPrimary',
|
||||||
title: Messages.history_next
|
title: Messages.history_next
|
||||||
}).appendTo($hist);
|
}).appendTo($hist);
|
||||||
|
var $fastNext = $('<button>', {
|
||||||
$('<label>').text(Messages.history_version).appendTo($nav);
|
'class': 'cp-toolbar-history-fast-next fa fa-fast-forward buttonPrimary',
|
||||||
var $cur = $('<input>', {
|
title: Messages.history_next
|
||||||
'class' : 'cp-toolbar-history-goto-input',
|
}).appendTo($hist);
|
||||||
'type' : 'number',
|
$('<span>', {'class': 'cp-history-filler'}).appendTo($hist);
|
||||||
'min' : '1',
|
|
||||||
'max' : states.length
|
|
||||||
}).val(c + 1).appendTo($nav).mousedown(function (e) {
|
|
||||||
// stopPropagation because the event would be cancelled by the dropdown menus
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
var $label2 = $('<label>').text(' / '+ states.length).appendTo($nav);
|
|
||||||
$('<br>').appendTo($nav);
|
|
||||||
var $close = $('<button>', {
|
var $close = $('<button>', {
|
||||||
'class':'cp-toolbar-history-close',
|
'class':'cp-toolbar-history-close fa fa-window-close',
|
||||||
title: Messages.history_closeTitle
|
title: Messages.history_closeTitle
|
||||||
}).text(Messages.history_closeTitle).appendTo($nav);
|
}).appendTo($hist);
|
||||||
var $rev = $('<button>', {
|
|
||||||
'class':'cp-toolbar-history-revert buttonSuccess',
|
var $bar = $('<div>', {'class': 'cp-toolbar-history-bar'}).appendTo($nav);
|
||||||
title: Messages.history_restoreTitle
|
var $container = $('<div>', {'class':'cp-toolbar-history-pos-container'}).appendTo($bar);
|
||||||
}).text(Messages.history_restore).appendTo($nav);
|
$('<div>', {'class': 'cp-toolbar-history-pos'}).appendTo($container);
|
||||||
if (History.readOnly) { $rev.hide(); }
|
|
||||||
|
$version = $('<span>', {
|
||||||
|
'class': 'cp-toolbar-history-version'
|
||||||
|
}).prependTo($bar).hide();
|
||||||
|
$loadMore = $('<button>', {
|
||||||
|
'class':'cp-toolbar-history-loadmore fa fa-ellipsis-h',
|
||||||
|
title: Messages.history_loadMore
|
||||||
|
}).click(function () {
|
||||||
|
loadMore(function () {
|
||||||
|
get(c);
|
||||||
|
});
|
||||||
|
}).prependTo($container);
|
||||||
|
|
||||||
|
// Load a version when clicking on the bar
|
||||||
|
$container.click(function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!$(e.target).is('.cp-toolbar-history-pos-container')) { return; }
|
||||||
|
var p = e.offsetX / $container.width();
|
||||||
|
var v = -Math.round((states.length - 1) * (1 - p));
|
||||||
|
render(get(v));
|
||||||
|
});
|
||||||
|
|
||||||
onUpdate = function () {
|
onUpdate = function () {
|
||||||
$cur.attr('max', states.length);
|
// Called when a new version is loaded
|
||||||
$cur.val(c+1);
|
|
||||||
$label2.text(' / ' + states.length);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var onKeyDown, onKeyUp;
|
||||||
var close = function () {
|
var close = function () {
|
||||||
$hist.hide();
|
$hist.hide();
|
||||||
$left.show();
|
$left.show();
|
||||||
$right.show();
|
$right.show();
|
||||||
$cke.show();
|
$cke.show();
|
||||||
$(window).trigger('resize');
|
$(window).trigger('resize');
|
||||||
|
$(window).off('keydown', onKeyDown);
|
||||||
|
$(window).off('keyup', onKeyUp);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Buttons actions
|
// Version buttons
|
||||||
$prev.click(function () { render(getPrevious()); });
|
$prev.click(function () { render(getPrevious()); });
|
||||||
$next.click(function () { render(getNext()); });
|
$next.click(function () { render(getNext()); });
|
||||||
$cur.keydown(function (e) {
|
$fastPrev.click(function () { render(getPrevious(10)); });
|
||||||
|
$fastNext.click(function () { render(getNext(10)); });
|
||||||
|
onKeyDown = function (e) {
|
||||||
var p = function () { e.preventDefault(); };
|
var p = function () { e.preventDefault(); };
|
||||||
if (e.which === 13) { p(); return render( get($cur.val() - 1) ); } // Enter
|
|
||||||
if ([37, 40].indexOf(e.which) >= 0) { p(); return render(getPrevious()); } // Left
|
if ([37, 40].indexOf(e.which) >= 0) { p(); return render(getPrevious()); } // Left
|
||||||
if ([38, 39].indexOf(e.which) >= 0) { p(); return render(getNext()); } // Right
|
if ([38, 39].indexOf(e.which) >= 0) { p(); return render(getNext()); } // Right
|
||||||
if (e.which === 33) { p(); return render(getNext(10)); } // PageUp
|
if (e.which === 33) { p(); return render(getNext(10)); } // PageUp
|
||||||
if (e.which === 34) { p(); return render(getPrevious(10)); } // PageUp
|
if (e.which === 34) { p(); return render(getPrevious(10)); } // PageUp
|
||||||
if (e.which === 27) { p(); $close.click(); }
|
if (e.which === 27) { p(); $close.click(); }
|
||||||
}).keyup(function (e) { e.stopPropagation(); }).focus();
|
};
|
||||||
$cur.on('change', function () {
|
onKeyUp = function (e) { e.stopPropagation(); };
|
||||||
render( get($cur.val() - 1) );
|
$(window).on('keydown', onKeyDown).on('keyup', onKeyUp).focus();
|
||||||
});
|
|
||||||
|
// Close & restore buttons
|
||||||
$close.click(function () {
|
$close.click(function () {
|
||||||
states = [];
|
states = [];
|
||||||
close();
|
close();
|
||||||
@ -229,14 +317,13 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Load all the history messages into a new chainpad object
|
// Load all the history messages into a new chainpad object
|
||||||
loadHistory(config, common, function (err, newRt) {
|
loadMoreHistory(config, common, function (err, newRt) {
|
||||||
|
History.readOnly = common.getMetadataMgr().getPrivateData().readOnly;
|
||||||
History.loading = false;
|
History.loading = false;
|
||||||
if (err) { throw new Error(err); }
|
if (err) { throw new Error(err); }
|
||||||
realtime = newRt;
|
update(newRt);
|
||||||
update();
|
|
||||||
c = states.length - 1;
|
c = states.length - 1;
|
||||||
display();
|
display();
|
||||||
onReady();
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -143,12 +143,11 @@ define([
|
|||||||
// or get it from the pad attributes
|
// or get it from the pad attributes
|
||||||
var needPassword = parsed.hashData && parsed.hashData.password;
|
var needPassword = parsed.hashData && parsed.hashData.password;
|
||||||
if (needPassword) {
|
if (needPassword) {
|
||||||
|
// Check if we have a password, and check if it is correct (file exists).
|
||||||
|
// It we don't have a correct password, display the password prompt.
|
||||||
|
// Maybe the file has been deleted from the server or the password has been changed.
|
||||||
Cryptpad.getPadAttribute('password', waitFor(function (err, val) {
|
Cryptpad.getPadAttribute('password', waitFor(function (err, val) {
|
||||||
if (val) {
|
var askPassword = function (wrongPasswordStored) {
|
||||||
// We already know the password, use it!
|
|
||||||
password = val;
|
|
||||||
todo();
|
|
||||||
} else {
|
|
||||||
// Ask for the password and check if the pad exists
|
// Ask for the password and check if the pad exists
|
||||||
// If the pad doesn't exist, it means the password isn't correct
|
// If the pad doesn't exist, it means the password isn't correct
|
||||||
// or the pad has been deleted
|
// or the pad has been deleted
|
||||||
@ -162,7 +161,14 @@ define([
|
|||||||
cb(false);
|
cb(false);
|
||||||
} else {
|
} else {
|
||||||
todo();
|
todo();
|
||||||
|
if (wrongPasswordStored) {
|
||||||
|
// Store the correct password
|
||||||
|
Cryptpad.setPadAttribute('password', password, function () {
|
||||||
correctPassword();
|
correctPassword();
|
||||||
|
}, parsed.getUrl());
|
||||||
|
} else {
|
||||||
|
correctPassword();
|
||||||
|
}
|
||||||
cb(true);
|
cb(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -178,6 +184,19 @@ define([
|
|||||||
Cryptpad.isNewChannel(window.location.href, password, next);
|
Cryptpad.isNewChannel(window.location.href, password, next);
|
||||||
});
|
});
|
||||||
sframeChan.event("EV_PAD_PASSWORD");
|
sframeChan.event("EV_PAD_PASSWORD");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
password = val;
|
||||||
|
Cryptpad.getFileSize(window.location.href, password, function (e, size) {
|
||||||
|
if (size !== 0) {
|
||||||
|
return void todo();
|
||||||
|
}
|
||||||
|
// Wrong password or deleted file?
|
||||||
|
askPassword(true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
askPassword();
|
||||||
}
|
}
|
||||||
}), parsed.getUrl());
|
}), parsed.getUrl());
|
||||||
return;
|
return;
|
||||||
@ -267,6 +286,10 @@ define([
|
|||||||
|
|
||||||
Test.registerOuter(sframeChan);
|
Test.registerOuter(sframeChan);
|
||||||
|
|
||||||
|
Cryptpad.onNewVersionReconnect.reg(function () {
|
||||||
|
sframeChan.event("EV_NEW_VERSION");
|
||||||
|
});
|
||||||
|
|
||||||
// Put in the following function the RPC queries that should also work in filepicker
|
// Put in the following function the RPC queries that should also work in filepicker
|
||||||
var addCommonRpc = function (sframeChan) {
|
var addCommonRpc = function (sframeChan) {
|
||||||
sframeChan.on('Q_ANON_RPC_MESSAGE', function (data, cb) {
|
sframeChan.on('Q_ANON_RPC_MESSAGE', function (data, cb) {
|
||||||
@ -312,7 +335,8 @@ define([
|
|||||||
var title = currentTabTitle.replace(/\{title\}/g, currentTitle || 'CryptPad');
|
var title = currentTabTitle.replace(/\{title\}/g, currentTitle || 'CryptPad');
|
||||||
document.title = title;
|
document.title = title;
|
||||||
};
|
};
|
||||||
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newTitle, cb) {
|
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newData, cb) {
|
||||||
|
var newTitle = newData.title || newData.defaultTitle;
|
||||||
currentTitle = newTitle;
|
currentTitle = newTitle;
|
||||||
setDocumentTitle();
|
setDocumentTitle();
|
||||||
var data = {
|
var data = {
|
||||||
@ -396,6 +420,24 @@ define([
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
sframeChan.on('Q_GET_HISTORY_RANGE', function (data, cb) {
|
||||||
|
var crypto = Crypto.createEncryptor(secret.keys);
|
||||||
|
Cryptpad.getHistoryRange({
|
||||||
|
channel: secret.channel,
|
||||||
|
validateKey: secret.keys.validateKey,
|
||||||
|
lastKnownHash: data.lastKnownHash
|
||||||
|
}, function (data) {
|
||||||
|
cb({
|
||||||
|
isFull: data.isFull,
|
||||||
|
messages: data.messages.map(function (msg) {
|
||||||
|
// The 3rd parameter "true" means we're going to skip signature validation.
|
||||||
|
// We don't need it since the message is already validated serverside by hk
|
||||||
|
return crypto.decrypt(msg, true, true);
|
||||||
|
}),
|
||||||
|
lastKnownHash: data.lastKnownHash
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
sframeChan.on('Q_GET_PAD_ATTRIBUTE', function (data, cb) {
|
sframeChan.on('Q_GET_PAD_ATTRIBUTE', function (data, cb) {
|
||||||
var href;
|
var href;
|
||||||
@ -614,6 +656,15 @@ define([
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sframeChan.on('Q_PAD_PASSWORD_CHANGE', function (data, cb) {
|
||||||
|
var href = data.href || window.location.href;
|
||||||
|
Cryptpad.changePadPassword(Cryptget, href, data.password, edPublic, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
sframeChan.on('Q_WRITE_LOGIN_BLOCK', function (data, cb) {
|
||||||
|
Cryptpad.writeLoginBlock(data, cb);
|
||||||
|
});
|
||||||
|
|
||||||
if (cfg.addRpc) {
|
if (cfg.addRpc) {
|
||||||
cfg.addRpc(sframeChan, Cryptpad, Utils);
|
cfg.addRpc(sframeChan, Cryptpad, Utils);
|
||||||
}
|
}
|
||||||
@ -699,6 +750,9 @@ define([
|
|||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
crypto: Crypto.createEncryptor(secret.keys),
|
crypto: Crypto.createEncryptor(secret.keys),
|
||||||
onConnect: function () {
|
onConnect: function () {
|
||||||
|
var href = parsed.getUrl();
|
||||||
|
// Add friends requests handlers when we have the final href
|
||||||
|
Cryptpad.messaging.addHandlers(href);
|
||||||
if (window.location.hash && window.location.hash !== '#') {
|
if (window.location.hash && window.location.hash !== '#') {
|
||||||
window.location = parsed.getUrl({
|
window.location = parsed.getUrl({
|
||||||
present: parsed.hashData.present,
|
present: parsed.hashData.present,
|
||||||
|
|||||||
@ -42,6 +42,9 @@ define([
|
|||||||
exp.updateTitle = function (newTitle, cb) {
|
exp.updateTitle = function (newTitle, cb) {
|
||||||
cb = cb || $.noop;
|
cb = cb || $.noop;
|
||||||
if (newTitle === exp.title) { return void cb(); }
|
if (newTitle === exp.title) { return void cb(); }
|
||||||
|
if (newTitle === exp.defaultTitle) {
|
||||||
|
newTitle = "";
|
||||||
|
}
|
||||||
metadataMgr.updateTitle(newTitle);
|
metadataMgr.updateTitle(newTitle);
|
||||||
titleUpdated = cb;
|
titleUpdated = cb;
|
||||||
};
|
};
|
||||||
@ -51,11 +54,16 @@ define([
|
|||||||
if ($title) {
|
if ($title) {
|
||||||
$title.find('span.cp-toolbar-title-value').text(md.title || md.defaultTitle);
|
$title.find('span.cp-toolbar-title-value').text(md.title || md.defaultTitle);
|
||||||
$title.find('input').val(md.title || md.defaultTitle);
|
$title.find('input').val(md.title || md.defaultTitle);
|
||||||
|
$title.find('input').prop('placeholder', md.defaultTitle);
|
||||||
}
|
}
|
||||||
|
exp.defaultTitle = md.defaultTitle;
|
||||||
exp.title = md.title;
|
exp.title = md.title;
|
||||||
});
|
});
|
||||||
metadataMgr.onTitleChange(function (title) {
|
metadataMgr.onTitleChange(function (title, defaultTitle) {
|
||||||
sframeChan.query('Q_SET_PAD_TITLE_IN_DRIVE', title, function (err) {
|
sframeChan.query('Q_SET_PAD_TITLE_IN_DRIVE', {
|
||||||
|
title: title,
|
||||||
|
defaultTitle: defaultTitle
|
||||||
|
}, function (err) {
|
||||||
if (err === 'E_OVER_LIMIT') {
|
if (err === 'E_OVER_LIMIT') {
|
||||||
return void UI.alert(Messages.pinLimitNotPinned, null, true);
|
return void UI.alert(Messages.pinLimitNotPinned, null, true);
|
||||||
} else if (err) { return; }
|
} else if (err) { return; }
|
||||||
|
|||||||
@ -112,11 +112,9 @@ define([
|
|||||||
var origin = ctx.metadataMgr.getPrivateData().origin;
|
var origin = ctx.metadataMgr.getPrivateData().origin;
|
||||||
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
|
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
|
||||||
};
|
};
|
||||||
funcs.getMediatagFromHref = function (href) {
|
funcs.getMediatagFromHref = function () {
|
||||||
// XXX: Should only be used with the current href
|
|
||||||
var data = ctx.metadataMgr.getPrivateData();
|
var data = ctx.metadataMgr.getPrivateData();
|
||||||
var parsed = Hash.parsePadUrl(href);
|
var secret = Hash.getSecrets('file', data.availableHashes.fileHash, data.password);
|
||||||
var secret = Hash.getSecrets('file', parsed.hash, data.password);
|
|
||||||
if (secret.keys && secret.channel) {
|
if (secret.keys && secret.channel) {
|
||||||
var key = Hash.encodeBase64(secret.keys && secret.keys.cryptKey);
|
var key = Hash.encodeBase64(secret.keys && secret.keys.cryptKey);
|
||||||
var hexFileName = secret.channel;
|
var hexFileName = secret.channel;
|
||||||
@ -440,6 +438,15 @@ define([
|
|||||||
UI.updateLoadingProgress(data, true);
|
UI.updateLoadingProgress(data, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ctx.sframeChan.on('EV_NEW_VERSION', function () {
|
||||||
|
var $err = $('<div>').append(Messages.newVersionError);
|
||||||
|
$err.find('a').click(function () {
|
||||||
|
funcs.gotoURL();
|
||||||
|
});
|
||||||
|
UI.findOKButton().click();
|
||||||
|
UI.errorLoadingScreen($err, true, true);
|
||||||
|
});
|
||||||
|
|
||||||
ctx.metadataMgr.onReady(waitFor());
|
ctx.metadataMgr.onReady(waitFor());
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -74,6 +74,9 @@ define({
|
|||||||
// Get the user's pin limit, usage and plan
|
// Get the user's pin limit, usage and plan
|
||||||
'Q_PIN_GET_USAGE': true,
|
'Q_PIN_GET_USAGE': true,
|
||||||
|
|
||||||
|
// Write/update the login block when the account password is changed
|
||||||
|
'Q_WRITE_LOGIN_BLOCK': true,
|
||||||
|
|
||||||
// Check the pin limit to determine if we can store the pad in the drive or if we should.
|
// Check the pin limit to determine if we can store the pad in the drive or if we should.
|
||||||
// display a warning
|
// display a warning
|
||||||
'Q_GET_PIN_LIMIT_STATUS': true,
|
'Q_GET_PIN_LIMIT_STATUS': true,
|
||||||
@ -84,6 +87,7 @@ define({
|
|||||||
// Request the full history from the server when the users clicks on the history button.
|
// Request the full history from the server when the users clicks on the history button.
|
||||||
// Callback is called when the FULL_HISTORY_END message is received in the outside.
|
// Callback is called when the FULL_HISTORY_END message is received in the outside.
|
||||||
'Q_GET_FULL_HISTORY': true,
|
'Q_GET_FULL_HISTORY': true,
|
||||||
|
'Q_GET_HISTORY_RANGE': true,
|
||||||
// When a (full) history message is received from the server.
|
// When a (full) history message is received from the server.
|
||||||
'EV_RT_HIST_MESSAGE': true,
|
'EV_RT_HIST_MESSAGE': true,
|
||||||
|
|
||||||
@ -196,7 +200,6 @@ define({
|
|||||||
|
|
||||||
// Anonymous users can empty their drive and remove FS_hash from localStorage
|
// Anonymous users can empty their drive and remove FS_hash from localStorage
|
||||||
'EV_BURN_ANON_DRIVE': true,
|
'EV_BURN_ANON_DRIVE': true,
|
||||||
|
|
||||||
// Inner drive needs to send command and receive updates from the async store
|
// Inner drive needs to send command and receive updates from the async store
|
||||||
'Q_DRIVE_USEROBJECT': true,
|
'Q_DRIVE_USEROBJECT': true,
|
||||||
'Q_DRIVE_GETOBJECT': true,
|
'Q_DRIVE_GETOBJECT': true,
|
||||||
@ -214,6 +217,8 @@ define({
|
|||||||
// Notifications about connection and disconnection from the network
|
// Notifications about connection and disconnection from the network
|
||||||
'EV_NETWORK_DISCONNECT': true,
|
'EV_NETWORK_DISCONNECT': true,
|
||||||
'EV_NETWORK_RECONNECT': true,
|
'EV_NETWORK_RECONNECT': true,
|
||||||
|
// Reload on new version
|
||||||
|
'EV_NEW_VERSION': true,
|
||||||
|
|
||||||
// Pad creation screen: create a pad with the selected attributes (owned, expire)
|
// Pad creation screen: create a pad with the selected attributes (owned, expire)
|
||||||
'Q_CREATE_PAD': true,
|
'Q_CREATE_PAD': true,
|
||||||
@ -224,16 +229,18 @@ define({
|
|||||||
// The exact protocol is defined in common/test.js
|
// The exact protocol is defined in common/test.js
|
||||||
'EV_TESTDATA': true,
|
'EV_TESTDATA': true,
|
||||||
|
|
||||||
// Critical error outside the iframe during loading screen
|
|
||||||
'EV_LOADING_ERROR': true,
|
|
||||||
|
|
||||||
// Ask for the pad password when a pad is protected
|
// Ask for the pad password when a pad is protected
|
||||||
'EV_PAD_PASSWORD': true,
|
'EV_PAD_PASSWORD': true,
|
||||||
'Q_PAD_PASSWORD_VALUE': true,
|
'Q_PAD_PASSWORD_VALUE': true,
|
||||||
|
// Change pad password
|
||||||
|
'Q_PAD_PASSWORD_CHANGE': true,
|
||||||
|
|
||||||
// Loading events to display in the loading screen
|
// Loading events to display in the loading screen
|
||||||
'EV_LOADING_INFO': true,
|
'EV_LOADING_INFO': true,
|
||||||
|
// Critical error outside the iframe during loading screen
|
||||||
|
'EV_LOADING_ERROR': true,
|
||||||
|
|
||||||
// Get all existing tags
|
// Get all existing tags
|
||||||
'Q_GET_ALL_TAGS': true,
|
'Q_GET_ALL_TAGS': true,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -420,7 +420,7 @@ define([
|
|||||||
var hashes = metadataMgr.getPrivateData().availableHashes;
|
var hashes = metadataMgr.getPrivateData().availableHashes;
|
||||||
|
|
||||||
var $shareBlock = $('<button>', {
|
var $shareBlock = $('<button>', {
|
||||||
'class': 'fa fa-share-alt cp-toolbar-share-button',
|
'class': 'fa fa-shhare-alt cp-toolbar-share-button',
|
||||||
title: Messages.shareButton
|
title: Messages.shareButton
|
||||||
});
|
});
|
||||||
var modal = UIElements.createShareModal({
|
var modal = UIElements.createShareModal({
|
||||||
@ -449,7 +449,7 @@ define([
|
|||||||
var hashes = metadataMgr.getPrivateData().availableHashes;
|
var hashes = metadataMgr.getPrivateData().availableHashes;
|
||||||
|
|
||||||
var $shareBlock = $('<button>', {
|
var $shareBlock = $('<button>', {
|
||||||
'class': 'fa fa-share-alt cp-toolbar-share-button',
|
'class': 'fa fa-shhare-alt cp-toolbar-share-button',
|
||||||
title: Messages.shareButton
|
title: Messages.shareButton
|
||||||
});
|
});
|
||||||
var modal = UIElements.createFileShareModal({
|
var modal = UIElements.createFileShareModal({
|
||||||
|
|||||||
@ -65,6 +65,7 @@ define([
|
|||||||
xhr.setRequestHeader('Range', 'bytes=0-1');
|
xhr.setRequestHeader('Range', 'bytes=0-1');
|
||||||
xhr.responseType = 'arraybuffer';
|
xhr.responseType = 'arraybuffer';
|
||||||
|
|
||||||
|
xhr.onerror= function () { return CB('XHR_ERROR'); };
|
||||||
xhr.onload = function () {
|
xhr.onload = function () {
|
||||||
if (/^4/.test('' + this.status)) { return CB('XHR_ERROR'); }
|
if (/^4/.test('' + this.status)) { return CB('XHR_ERROR'); }
|
||||||
var res = new Uint8Array(xhr.response);
|
var res = new Uint8Array(xhr.response);
|
||||||
|
|||||||
@ -37,6 +37,9 @@ define([
|
|||||||
var Nacl = window.nacl;
|
var Nacl = window.nacl;
|
||||||
|
|
||||||
var APP = window.APP = {};
|
var APP = window.APP = {};
|
||||||
|
MediaTag.setDefaultConfig('download', {
|
||||||
|
text: Messages.download_mt_button
|
||||||
|
});
|
||||||
|
|
||||||
var andThen = function (common) {
|
var andThen = function (common) {
|
||||||
var $appContainer = $('#cp-app-file-content');
|
var $appContainer = $('#cp-app-file-content');
|
||||||
@ -92,7 +95,9 @@ define([
|
|||||||
FileCrypto.fetchDecryptedMetadata(src, key, function (e, metadata) {
|
FileCrypto.fetchDecryptedMetadata(src, key, function (e, metadata) {
|
||||||
if (e) {
|
if (e) {
|
||||||
if (e === 'XHR_ERROR') {
|
if (e === 'XHR_ERROR') {
|
||||||
return void UI.errorLoadingScreen(Messages.download_resourceNotAvailable);
|
return void UI.errorLoadingScreen(Messages.download_resourceNotAvailable, false, function () {
|
||||||
|
common.gotoURL('/file/');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return void console.error(e);
|
return void console.error(e);
|
||||||
}
|
}
|
||||||
@ -130,32 +135,17 @@ define([
|
|||||||
$mt.attr('data-crypto-key', 'cryptpad:'+cryptKey);
|
$mt.attr('data-crypto-key', 'cryptpad:'+cryptKey);
|
||||||
|
|
||||||
var rightsideDisplayed = false;
|
var rightsideDisplayed = false;
|
||||||
$(window.document).on('decryption', function (e) {
|
|
||||||
/* FIXME
|
|
||||||
we're listening for decryption events and assuming that only
|
|
||||||
the main media-tag exists. In practice there is also your avatar
|
|
||||||
and there could be other things in the future, so we should
|
|
||||||
figure out a generic way target media-tag decryption events.
|
|
||||||
*/
|
|
||||||
var decrypted = e.originalEvent;
|
|
||||||
if (decrypted.callback) {
|
|
||||||
decrypted.callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
MediaTag($mt[0]).on('complete', function (decrypted) {
|
||||||
$dlview.show();
|
$dlview.show();
|
||||||
$dlform.hide();
|
$dlform.hide();
|
||||||
var $dlButton = $dlview.find('media-tag button');
|
var $dlButton = $dlview.find('media-tag button');
|
||||||
if (ev) { $dlButton.click(); }
|
if (ev) { $dlButton.click(); }
|
||||||
$dlButton.addClass('btn btn-success');
|
|
||||||
var text = Messages.download_mt_button + '<br>';
|
|
||||||
text += '<b>' + Util.fixHTML(title) + '</b><br>';
|
|
||||||
text += '<em>' + Messages._getKey('formattedMB', [sizeMb]) + '</em>';
|
|
||||||
$dlButton.html(text);
|
|
||||||
|
|
||||||
if (!rightsideDisplayed) {
|
if (!rightsideDisplayed) {
|
||||||
toolbar.$rightside
|
toolbar.$rightside
|
||||||
.append(common.createButton('export', true, {}, function () {
|
.append(common.createButton('export', true, {}, function () {
|
||||||
saveAs(decrypted.blob, decrypted.metadata.name);
|
saveAs(decrypted.content, decrypted.metadata.name);
|
||||||
}));
|
}));
|
||||||
rightsideDisplayed = true;
|
rightsideDisplayed = true;
|
||||||
}
|
}
|
||||||
@ -178,42 +168,12 @@ define([
|
|||||||
} else {
|
} else {
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
})
|
}).on('progress', function (data) {
|
||||||
.on('decryptionError', function (e) {
|
var p = data.progress +'%';
|
||||||
var error = e.originalEvent;
|
|
||||||
//UI.alert(error.message);
|
|
||||||
cb(error.message);
|
|
||||||
})
|
|
||||||
.on('decryptionProgress', function (e) {
|
|
||||||
var progress = e.originalEvent;
|
|
||||||
var p = progress.percent +'%';
|
|
||||||
$progress.width(p);
|
$progress.width(p);
|
||||||
|
}).on('error', function (err) {
|
||||||
|
console.error(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Allowed mime types that have to be set for a rendering after a decryption.
|
|
||||||
*
|
|
||||||
* @type {Array}
|
|
||||||
*/
|
|
||||||
var allowedMediaTypes = [
|
|
||||||
'image/png',
|
|
||||||
'image/jpeg',
|
|
||||||
'image/jpg',
|
|
||||||
'image/gif',
|
|
||||||
'audio/mp3',
|
|
||||||
'audio/ogg',
|
|
||||||
'audio/wav',
|
|
||||||
'audio/webm',
|
|
||||||
'video/mp4',
|
|
||||||
'video/ogg',
|
|
||||||
'video/webm',
|
|
||||||
'application/pdf',
|
|
||||||
'application/dash+xml',
|
|
||||||
'download'
|
|
||||||
];
|
|
||||||
MediaTag.CryptoFilter.setAllowedMediaTypes(allowedMediaTypes);
|
|
||||||
|
|
||||||
MediaTag($mt[0]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var todoBigFile = function (sizeMb) {
|
var todoBigFile = function (sizeMb) {
|
||||||
|
|||||||
@ -4,11 +4,15 @@
|
|||||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
@import (once) '../../customize/src/less2/include/fileupload.less';
|
||||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
@import (once) '../../customize/src/less2/include/alertify.less';
|
||||||
@import (once) '../../customize/src/less2/include/tippy.less';
|
@import (once) '../../customize/src/less2/include/tippy.less';
|
||||||
|
@import (once) '../../customize/src/less2/include/checkmark.less';
|
||||||
|
@import (once) '../../customize/src/less2/include/password-input.less';
|
||||||
|
|
||||||
.iconColors_main();
|
.iconColors_main();
|
||||||
.fileupload_main();
|
.fileupload_main();
|
||||||
.alertify_main();
|
.alertify_main();
|
||||||
.tippy_main();
|
.tippy_main();
|
||||||
|
.checkmark_main(20px);
|
||||||
|
.password_main();
|
||||||
|
|
||||||
#cp-filepicker-dialog {
|
#cp-filepicker-dialog {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
else { this[name] = definition(); }
|
else { this[name] = definition(); }
|
||||||
}('MediaTag', function() {
|
}('MediaTag', function() {
|
||||||
var cache;
|
var cache;
|
||||||
var PARANOIA = true;
|
|
||||||
var cypherChunkLength = 131088;
|
var cypherChunkLength = 131088;
|
||||||
|
|
||||||
// Save a blob on the file system
|
// Save a blob on the file system
|
||||||
@ -23,6 +22,14 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var fixHTML = function (str) {
|
||||||
|
if (!str) { return ''; }
|
||||||
|
return str.replace(/[<>&"']/g, function (x) {
|
||||||
|
return ({ "<": "<", ">": ">", "&": "&", '"': """, "'": "'" })[x];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Default config, can be overriden per media-tag call
|
// Default config, can be overriden per media-tag call
|
||||||
var config = {
|
var config = {
|
||||||
allowed: [
|
allowed: [
|
||||||
@ -49,6 +56,7 @@
|
|||||||
image: function (metadata, url, content, cfg, cb) {
|
image: function (metadata, url, content, cfg, cb) {
|
||||||
var img = document.createElement('img');
|
var img = document.createElement('img');
|
||||||
img.setAttribute('src', url);
|
img.setAttribute('src', url);
|
||||||
|
img.blob = content;
|
||||||
cb(void 0, img);
|
cb(void 0, img);
|
||||||
},
|
},
|
||||||
video: function (metadata, url, content, cfg, cb) {
|
video: function (metadata, url, content, cfg, cb) {
|
||||||
@ -75,7 +83,8 @@
|
|||||||
},
|
},
|
||||||
download: function (metadata, url, content, cfg, cb) {
|
download: function (metadata, url, content, cfg, cb) {
|
||||||
var btn = document.createElement('button');
|
var btn = document.createElement('button');
|
||||||
btn.innerHTML = cfg.download.text;
|
btn.innerHTML = cfg.download.text + '<br>' +
|
||||||
|
metadata.name ? '<b>' + fixHTML(metadata.name) + '</b>' : '';
|
||||||
btn.addEventListener('click', function () {
|
btn.addEventListener('click', function () {
|
||||||
saveFile(content, url, metadata.name);
|
saveFile(content, url, metadata.name);
|
||||||
});
|
});
|
||||||
@ -106,38 +115,24 @@
|
|||||||
var Decrypt = {
|
var Decrypt = {
|
||||||
// Create a nonce
|
// Create a nonce
|
||||||
createNonce: function () {
|
createNonce: function () {
|
||||||
if (!Array.prototype.fill) {
|
var n = new Uint8Array(24);
|
||||||
// IE support
|
for (var i = 0; i < 24; i++) { n[i] = 0; }
|
||||||
var arr = [];
|
return n;
|
||||||
for (var i = 0; i < 24; i++) { arr[i] = 0; }
|
|
||||||
return new Uint8Array(arr);
|
|
||||||
}
|
|
||||||
return new Uint8Array(new Array(24).fill(0));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Increment a nonce
|
// Increment a nonce
|
||||||
// FIXME: remove throw?
|
|
||||||
increment: function (N) {
|
increment: function (N) {
|
||||||
var l = N.length;
|
var l = N.length;
|
||||||
while (l-- > 1) {
|
while (l-- > 1) {
|
||||||
if (PARANOIA) {
|
|
||||||
if (typeof(N[l]) !== 'number') {
|
|
||||||
throw new Error('E_UNSAFE_TYPE');
|
|
||||||
}
|
|
||||||
if (N[l] > 255) {
|
|
||||||
throw new Error('E_OUT_OF_BOUNDS');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* .jshint probably suspects this is unsafe because we lack types
|
/* .jshint probably suspects this is unsafe because we lack types
|
||||||
but as long as this is only used on nonces, it should be safe */
|
but as long as this is only used on nonces, it should be safe */
|
||||||
if (N[l] !== 255) { return void N[l]++; } // jshint ignore:line
|
if (N[l] !== 255) { return void N[l]++; } // jshint ignore:line
|
||||||
N[l] = 0;
|
|
||||||
|
|
||||||
// you don't need to worry about this running out.
|
// you don't need to worry about this running out.
|
||||||
// you'd need a REAAAALLY big file
|
// you'd need a REAAAALLY big file
|
||||||
if (l === 0) {
|
if (l === 0) { throw new Error('E_NONCE_TOO_LARGE'); }
|
||||||
throw new Error('E_NONCE_TOO_LARGE');
|
|
||||||
}
|
N[l] = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -153,13 +148,6 @@
|
|||||||
return Array.prototype.slice.call(u8);
|
return Array.prototype.slice.call(u8);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Gets the random key string.
|
|
||||||
getRandomKeyStr: function () {
|
|
||||||
var Nacl = window.nacl;
|
|
||||||
var rdm = Nacl.randomBytes(18);
|
|
||||||
return Nacl.util.encodeBase64(rdm);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Gets the key from the key string.
|
// Gets the key from the key string.
|
||||||
getKeyFromStr: function (str) {
|
getKeyFromStr: function (str) {
|
||||||
return window.nacl.util.decodeBase64(str);
|
return window.nacl.util.decodeBase64(str);
|
||||||
@ -287,7 +275,7 @@
|
|||||||
|
|
||||||
// Get blob URL
|
// Get blob URL
|
||||||
var url = decrypted.url;
|
var url = decrypted.url;
|
||||||
if (!url) {
|
if (!url && window.URL) {
|
||||||
url = decrypted.url = window.URL.createObjectURL(new Blob([blob], {
|
url = decrypted.url = window.URL.createObjectURL(new Blob([blob], {
|
||||||
type: metadata.type
|
type: metadata.type
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -601,8 +601,8 @@ define([
|
|||||||
var $clone = $(inner).clone();
|
var $clone = $(inner).clone();
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(inner).find('media-tag').each(function (i, el) {
|
$(inner).find('media-tag').each(function (i, el) {
|
||||||
if (!$(el).data('blob')) { return; }
|
if (!$(el).data('blob') || !el.blob) { return; }
|
||||||
Util.blobToImage($(el).data('blob'), waitFor(function (imgSrc) {
|
Util.blobToImage(el.blob || $(el).data('blob'), waitFor(function (imgSrc) {
|
||||||
$clone.find('media-tag[src="' + $(el).attr('src') + '"] img')
|
$clone.find('media-tag[src="' + $(el).attr('src') + '"] img')
|
||||||
.attr('src', imgSrc);
|
.attr('src', imgSrc);
|
||||||
$clone.find('media-tag').parent()
|
$clone.find('media-tag').parent()
|
||||||
|
|||||||
@ -43,16 +43,6 @@ define([
|
|||||||
_onRefresh: []
|
_onRefresh: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Decryption event for avatar mediatag (TODO not needed anymore?)
|
|
||||||
$(window.document).on('decryption', function (e) {
|
|
||||||
var decrypted = e.originalEvent;
|
|
||||||
if (decrypted.callback) { decrypted.callback(); }
|
|
||||||
})
|
|
||||||
.on('decryptionError', function (e) {
|
|
||||||
var error = e.originalEvent;
|
|
||||||
UI.alert(error.message);
|
|
||||||
});
|
|
||||||
|
|
||||||
$(window).click(function () {
|
$(window).click(function () {
|
||||||
$('.cp-dropdown-content').hide();
|
$('.cp-dropdown-content').hide();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -55,6 +55,15 @@
|
|||||||
width: @sidebar_button-width;
|
width: @sidebar_button-width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.cp-settings-change-password {
|
||||||
|
[type="password"], [type="text"] {
|
||||||
|
width: @sidebar_button-width;
|
||||||
|
flex: unset;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.cp-settings-drive-backup {
|
.cp-settings-drive-backup {
|
||||||
button {
|
button {
|
||||||
span.fa {
|
span.fa {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ define([
|
|||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
'/common/hyperscript.js',
|
'/common/hyperscript.js',
|
||||||
|
'/customize/credential.js',
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ define([
|
|||||||
Hash,
|
Hash,
|
||||||
Messages,
|
Messages,
|
||||||
h,
|
h,
|
||||||
|
Cred,
|
||||||
AppConfig,
|
AppConfig,
|
||||||
ApiConfig
|
ApiConfig
|
||||||
)
|
)
|
||||||
@ -48,6 +50,7 @@ define([
|
|||||||
'cp-settings-resettips',
|
'cp-settings-resettips',
|
||||||
'cp-settings-thumbnails',
|
'cp-settings-thumbnails',
|
||||||
'cp-settings-userfeedback',
|
'cp-settings-userfeedback',
|
||||||
|
'cp-settings-change-password',
|
||||||
'cp-settings-delete'
|
'cp-settings-delete'
|
||||||
],
|
],
|
||||||
'creation': [
|
'creation': [
|
||||||
@ -312,6 +315,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
create['delete'] = function () {
|
create['delete'] = function () {
|
||||||
|
if (!common.isLoggedIn()) { return; }
|
||||||
var $div = $('<div>', { 'class': 'cp-settings-delete cp-sidebarlayout-element'});
|
var $div = $('<div>', { 'class': 'cp-settings-delete cp-sidebarlayout-element'});
|
||||||
|
|
||||||
$('<span>', {'class': 'label'}).text(Messages.settings_deleteTitle).appendTo($div);
|
$('<span>', {'class': 'label'}).text(Messages.settings_deleteTitle).appendTo($div);
|
||||||
@ -368,6 +372,95 @@ define([
|
|||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
create['change-password'] = function () {
|
||||||
|
if (!common.isLoggedIn()) { return; }
|
||||||
|
|
||||||
|
var $div = $('<div>', { 'class': 'cp-settings-change-password cp-sidebarlayout-element'});
|
||||||
|
|
||||||
|
$('<span>', {'class': 'label'}).text(Messages.settings_changePasswordTitle).appendTo($div);
|
||||||
|
|
||||||
|
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||||
|
.append(Messages.settings_changePasswordHint).appendTo($div);
|
||||||
|
|
||||||
|
// var publicKey = privateData.edPublic;
|
||||||
|
|
||||||
|
var form = h('div', [
|
||||||
|
UI.passwordInput({
|
||||||
|
id: 'cp-settings-change-password-current',
|
||||||
|
placeholder: Messages.settings_changePasswordCurrent
|
||||||
|
}, true),
|
||||||
|
h('br'),
|
||||||
|
UI.passwordInput({
|
||||||
|
id: 'cp-settings-change-password-new',
|
||||||
|
placeholder: Messages.settings_changePasswordNew
|
||||||
|
}, true),
|
||||||
|
UI.passwordInput({
|
||||||
|
id: 'cp-settings-change-password-new2',
|
||||||
|
placeholder: Messages.settings_changePasswordNewConfirm
|
||||||
|
}, true),
|
||||||
|
h('button.btn.btn-primary', Messages.settings_changePasswordButton)
|
||||||
|
]);
|
||||||
|
|
||||||
|
$(form).appendTo($div);
|
||||||
|
|
||||||
|
var updateBlock = function (data, cb) {
|
||||||
|
sframeChan.query('Q_WRITE_LOGIN_BLOCK', data, function (err, obj) {
|
||||||
|
if (err || obj.error) { return void cb ({error: err || obj.error}); }
|
||||||
|
cb (obj);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
updateBlock = updateBlock; // jshint..
|
||||||
|
|
||||||
|
var todo = function () {
|
||||||
|
var oldPassword = $(form).find('#cp-settings-change-password-current').val();
|
||||||
|
var newPassword = $(form).find('#cp-settings-change-password-new').val();
|
||||||
|
var newPasswordConfirm = $(form).find('#cp-settings-change-password-new2').val();
|
||||||
|
|
||||||
|
/* basic validation */
|
||||||
|
if (!Cred.isLongEnoughPassword(newPassword)) {
|
||||||
|
var warning = Messages._getKey('register_passwordTooShort', [
|
||||||
|
Cred.MINIMUM_PASSWORD_LENGTH
|
||||||
|
]);
|
||||||
|
return void UI.alert(warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPassword !== newPasswordConfirm) {
|
||||||
|
UI.alert(Messages.register_passwordsDontMatch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UI.confirm(Messages.settings_changePasswordConfirm,
|
||||||
|
function (yes) {
|
||||||
|
if (!yes) { return; }
|
||||||
|
// TODO
|
||||||
|
console.log(oldPassword, newPassword, newPasswordConfirm);
|
||||||
|
}, {
|
||||||
|
ok: Messages.register_writtenPassword,
|
||||||
|
cancel: Messages.register_cancel,
|
||||||
|
cancelClass: 'safe',
|
||||||
|
okClass: 'danger',
|
||||||
|
reverseOrder: true,
|
||||||
|
done: function ($dialog) {
|
||||||
|
$dialog.find('> div').addClass('half');
|
||||||
|
},
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
$(form).find('button').click(function () {
|
||||||
|
todo();
|
||||||
|
});
|
||||||
|
$(form).find('input').keydown(function (e) {
|
||||||
|
// Save on Enter
|
||||||
|
if (e.which === 13) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
todo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $div;
|
||||||
|
};
|
||||||
|
|
||||||
// Pad Creation settings
|
// Pad Creation settings
|
||||||
|
|
||||||
var setHTML = function (e, html) {
|
var setHTML = function (e, html) {
|
||||||
|
|||||||
@ -1,81 +1,59 @@
|
|||||||
define([
|
define([
|
||||||
'jquery',
|
'jquery',
|
||||||
'/bower_components/chainpad-crypto/crypto.js',
|
|
||||||
'/common/toolbar3.js',
|
|
||||||
'json.sortify',
|
'json.sortify',
|
||||||
'/common/common-util.js',
|
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/common/sframe-common.js',
|
'/common/sframe-common.js',
|
||||||
|
'/common/sframe-app-framework.js',
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/common/common-hash.js',
|
||||||
'/common/common-interface.js',
|
'/common/common-interface.js',
|
||||||
'/api/config',
|
'/common/common-thumbnail.js',
|
||||||
'/common/common-realtime.js',
|
|
||||||
'/customize/pages.js',
|
'/customize/pages.js',
|
||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
'/customize/application_config.js',
|
|
||||||
'/common/common-thumbnail.js',
|
|
||||||
'/whiteboard/colors.js',
|
'/whiteboard/colors.js',
|
||||||
|
'/customize/application_config.js',
|
||||||
'/bower_components/chainpad/chainpad.dist.js',
|
'/bower_components/chainpad/chainpad.dist.js',
|
||||||
|
|
||||||
'/bower_components/secure-fabric.js/dist/fabric.min.js',
|
'/bower_components/secure-fabric.js/dist/fabric.min.js',
|
||||||
'/bower_components/file-saver/FileSaver.min.js',
|
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
|
||||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
|
||||||
'less!/customize/src/less2/main.less',
|
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
Crypto,
|
Sortify,
|
||||||
Toolbar,
|
|
||||||
JSONSortify,
|
|
||||||
Util,
|
|
||||||
nThen,
|
nThen,
|
||||||
SFCommon,
|
SFCommon,
|
||||||
|
Framework,
|
||||||
|
Util,
|
||||||
|
Hash,
|
||||||
UI,
|
UI,
|
||||||
ApiConfig,
|
Thumb,
|
||||||
CommonRealtime,
|
|
||||||
Pages,
|
Pages,
|
||||||
Messages,
|
Messages,
|
||||||
AppConfig,
|
|
||||||
Thumb,
|
|
||||||
Colors,
|
Colors,
|
||||||
|
AppConfig,
|
||||||
ChainPad)
|
ChainPad)
|
||||||
{
|
{
|
||||||
var saveAs = window.saveAs;
|
|
||||||
|
|
||||||
var APP = window.APP = {
|
var APP = window.APP = {
|
||||||
$: $
|
$: $
|
||||||
};
|
};
|
||||||
var Fabric = APP.Fabric = window.fabric;
|
var Fabric = APP.Fabric = window.fabric;
|
||||||
|
|
||||||
var stringify = function (obj) {
|
var verbose = function (x) { console.log(x); };
|
||||||
return JSONSortify(obj);
|
verbose = function () {}; // comment out to enable verbose logging
|
||||||
};
|
|
||||||
|
|
||||||
var toolbar;
|
var mkControls = function (framework, canvas) {
|
||||||
|
|
||||||
var andThen = function (common) {
|
|
||||||
var config = {};
|
|
||||||
/* Initialize Fabric */
|
|
||||||
var canvas = APP.canvas = new Fabric.Canvas('cp-app-whiteboard-canvas', {
|
|
||||||
containerClass: 'cp-app-whiteboard-canvas-container'
|
|
||||||
});
|
|
||||||
var $canvas = $('canvas');
|
|
||||||
var $controls = $('#cp-app-whiteboard-controls');
|
|
||||||
var $canvasContainer = $('canvas').parents('.cp-app-whiteboard-canvas-container');
|
|
||||||
var $pickers = $('#cp-app-whiteboard-pickers');
|
var $pickers = $('#cp-app-whiteboard-pickers');
|
||||||
var $colors = $('#cp-app-whiteboard-colors');
|
var $colors = $('#cp-app-whiteboard-colors');
|
||||||
var $cursors = $('#cp-app-whiteboard-cursors');
|
var $cursors = $('#cp-app-whiteboard-cursors');
|
||||||
var $deleteButton = $('#cp-app-whiteboard-delete');
|
var $controls = $('#cp-app-whiteboard-controls');
|
||||||
var $toggle = $('#cp-app-whiteboard-toggledraw');
|
|
||||||
var $width = $('#cp-app-whiteboard-width');
|
var $width = $('#cp-app-whiteboard-width');
|
||||||
var $widthLabel = $('label[for="cp-app-whiteboard-width"]');
|
var $widthLabel = $('label[for="cp-app-whiteboard-width"]');
|
||||||
var $opacity = $('#cp-app-whiteboard-opacity');
|
var $opacity = $('#cp-app-whiteboard-opacity');
|
||||||
var $opacityLabel = $('label[for="cp-app-whiteboard-opacity"]');
|
var $opacityLabel = $('label[for="cp-app-whiteboard-opacity"]');
|
||||||
|
var $toggle = $('#cp-app-whiteboard-toggledraw');
|
||||||
|
var $deleteButton = $('#cp-app-whiteboard-delete');
|
||||||
|
|
||||||
|
var metadataMgr = framework._.cpNfInner.metadataMgr;
|
||||||
|
|
||||||
// Brush
|
|
||||||
|
|
||||||
var readOnly = false;
|
|
||||||
var brush = {
|
var brush = {
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
opacity: 1
|
opacity: 1
|
||||||
@ -136,6 +114,36 @@ define([
|
|||||||
updateBrushOpacity();
|
updateBrushOpacity();
|
||||||
$opacity.on('change', updateBrushOpacity);
|
$opacity.on('change', updateBrushOpacity);
|
||||||
|
|
||||||
|
APP.draw = true;
|
||||||
|
var toggleDrawMode = function () {
|
||||||
|
canvas.deactivateAll().renderAll();
|
||||||
|
APP.draw = !APP.draw;
|
||||||
|
canvas.isDrawingMode = APP.draw;
|
||||||
|
$toggle.text(APP.draw ? Messages.canvas_disable : Messages.canvas_enable);
|
||||||
|
if (APP.draw) { $deleteButton.hide(); }
|
||||||
|
else { $deleteButton.show(); }
|
||||||
|
};
|
||||||
|
$toggle.click(toggleDrawMode);
|
||||||
|
|
||||||
|
var deleteSelection = function () {
|
||||||
|
if (canvas.getActiveObject()) {
|
||||||
|
canvas.getActiveObject().remove();
|
||||||
|
}
|
||||||
|
if (canvas.getActiveGroup()) {
|
||||||
|
canvas.getActiveGroup()._objects.forEach(function (el) {
|
||||||
|
el.remove();
|
||||||
|
});
|
||||||
|
canvas.discardActiveGroup();
|
||||||
|
}
|
||||||
|
canvas.renderAll();
|
||||||
|
framework.localChange();
|
||||||
|
};
|
||||||
|
$deleteButton.click(deleteSelection);
|
||||||
|
$(window).on('keyup', function (e) {
|
||||||
|
if (e.which === 46) { deleteSelection (); }
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
var pickColor = function (current, cb) {
|
var pickColor = function (current, cb) {
|
||||||
var $picker = $('<input>', {
|
var $picker = $('<input>', {
|
||||||
type: 'color',
|
type: 'color',
|
||||||
@ -169,96 +177,8 @@ define([
|
|||||||
setColor(color);
|
setColor(color);
|
||||||
});
|
});
|
||||||
|
|
||||||
APP.draw = true;
|
|
||||||
var toggleDrawMode = function () {
|
|
||||||
canvas.deactivateAll().renderAll();
|
|
||||||
APP.draw = !APP.draw;
|
|
||||||
canvas.isDrawingMode = APP.draw;
|
|
||||||
$toggle.text(APP.draw ? Messages.canvas_disable : Messages.canvas_enable);
|
|
||||||
if (APP.draw) { $deleteButton.hide(); }
|
|
||||||
else { $deleteButton.show(); }
|
|
||||||
};
|
|
||||||
$toggle.click(toggleDrawMode);
|
|
||||||
|
|
||||||
var deleteSelection = function () {
|
|
||||||
if (canvas.getActiveObject()) {
|
|
||||||
canvas.getActiveObject().remove();
|
|
||||||
}
|
|
||||||
if (canvas.getActiveGroup()) {
|
|
||||||
canvas.getActiveGroup()._objects.forEach(function (el) {
|
|
||||||
el.remove();
|
|
||||||
});
|
|
||||||
canvas.discardActiveGroup();
|
|
||||||
}
|
|
||||||
canvas.renderAll();
|
|
||||||
config.onLocal();
|
|
||||||
};
|
|
||||||
$deleteButton.click(deleteSelection);
|
|
||||||
$(window).on('keyup', function (e) {
|
|
||||||
if (e.which === 46) { deleteSelection (); }
|
|
||||||
});
|
|
||||||
|
|
||||||
var setEditable = function (bool) {
|
|
||||||
APP.editable = bool;
|
|
||||||
if (readOnly && bool) { return; }
|
|
||||||
if (bool) { $controls.css('display', 'flex'); }
|
|
||||||
else { $controls.hide(); }
|
|
||||||
|
|
||||||
canvas.isDrawingMode = bool ? APP.draw : false;
|
|
||||||
if (!bool) {
|
|
||||||
canvas.deactivateAll();
|
|
||||||
canvas.renderAll();
|
|
||||||
}
|
|
||||||
canvas.forEachObject(function (object) {
|
|
||||||
object.selectable = bool;
|
|
||||||
});
|
|
||||||
$canvasContainer.find('canvas').css('border-color', bool? 'black': 'red');
|
|
||||||
};
|
|
||||||
|
|
||||||
var saveImage = APP.saveImage = function () {
|
|
||||||
var defaultName = "pretty-picture.png";
|
|
||||||
UI.prompt(Messages.exportPrompt, defaultName, function (filename) {
|
|
||||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
|
||||||
$canvas[0].toBlob(function (blob) {
|
|
||||||
saveAs(blob, filename);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
APP.FM = common.createFileManager({});
|
|
||||||
APP.upload = function (title) {
|
|
||||||
var canvas = $canvas[0];
|
|
||||||
APP.canvas.deactivateAll().renderAll();
|
|
||||||
canvas.toBlob(function (blob) {
|
|
||||||
blob.name = title;
|
|
||||||
APP.FM.handleFile(blob);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var initializing = true;
|
|
||||||
var $bar = $('#cp-toolbar');
|
|
||||||
var Title;
|
|
||||||
var cpNfInner;
|
|
||||||
var metadataMgr;
|
|
||||||
|
|
||||||
config = {
|
|
||||||
readOnly: readOnly,
|
|
||||||
patchTransformer: ChainPad.NaiveJSONTransformer,
|
|
||||||
// cryptpad debug logging (default is 1)
|
|
||||||
// logLevel: 0,
|
|
||||||
validateContent: function (content) {
|
|
||||||
try {
|
|
||||||
JSON.parse(content);
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Failed to parse, rejecting patch");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var addColorToPalette = function (color, i) {
|
var addColorToPalette = function (color, i) {
|
||||||
if (readOnly) { return; }
|
if (framework.isReadOnly()) { return; }
|
||||||
var $color = $('<span>', {
|
var $color = $('<span>', {
|
||||||
'class': 'cp-app-whiteboard-palette-color',
|
'class': 'cp-app-whiteboard-palette-color',
|
||||||
})
|
})
|
||||||
@ -271,7 +191,7 @@ define([
|
|||||||
})
|
})
|
||||||
.on('dblclick', function (e) {
|
.on('dblclick', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!APP.editable) { return; }
|
if (framework.isLocked()) { return; }
|
||||||
pickColor(Colors.rgb2hex($color.css('background-color')), function (c) {
|
pickColor(Colors.rgb2hex($color.css('background-color')), function (c) {
|
||||||
$color.css({
|
$color.css({
|
||||||
'background-color': c,
|
'background-color': c,
|
||||||
@ -287,7 +207,7 @@ define([
|
|||||||
|
|
||||||
var first = true;
|
var first = true;
|
||||||
var updatePalette = function (newPalette) {
|
var updatePalette = function (newPalette) {
|
||||||
if (first || stringify(palette) !== stringify(newPalette)) {
|
if (first || Sortify(palette) !== Sortify(newPalette)) {
|
||||||
palette = newPalette;
|
palette = newPalette;
|
||||||
$colors.html('<div class="hidden"> </div>');
|
$colors.html('<div class="hidden"> </div>');
|
||||||
palette.forEach(addColorToPalette);
|
palette.forEach(addColorToPalette);
|
||||||
@ -299,7 +219,7 @@ define([
|
|||||||
var metadata = JSON.parse(JSON.stringify(metadataMgr.getMetadata()));
|
var metadata = JSON.parse(JSON.stringify(metadataMgr.getMetadata()));
|
||||||
metadata.palette = newPalette;
|
metadata.palette = newPalette;
|
||||||
metadataMgr.updateMetadata(metadata);
|
metadataMgr.updateMetadata(metadata);
|
||||||
config.onLocal();
|
framework.localChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
var makeColorButton = function ($container) {
|
var makeColorButton = function ($container) {
|
||||||
@ -312,7 +232,7 @@ define([
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var $color = APP.$color = common.createButton(null, true, {
|
var $color = APP.$color = framework._.sfCommon.createButton(null, true, {
|
||||||
icon: 'fa-square',
|
icon: 'fa-square',
|
||||||
title: Messages.canvas_chooseColor,
|
title: Messages.canvas_chooseColor,
|
||||||
name: 'color',
|
name: 'color',
|
||||||
@ -331,33 +251,73 @@ define([
|
|||||||
return $color;
|
return $color;
|
||||||
};
|
};
|
||||||
|
|
||||||
var stringifyInner = function (textValue) {
|
updateLocalPalette(palette);
|
||||||
var obj = {
|
|
||||||
content: textValue,
|
|
||||||
metadata: metadataMgr.getMetadataLazy()
|
|
||||||
};
|
|
||||||
// stringify the json and send it into chainpad
|
|
||||||
return stringify(obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
var onLocal = config.onLocal = function () {
|
metadataMgr.onChange(function () {
|
||||||
if (initializing) { return; }
|
var md = metadataMgr.getMetadata();
|
||||||
if (readOnly) { return; }
|
if (md.palette) {
|
||||||
|
updateLocalPalette(md.palette);
|
||||||
var content = stringifyInner(canvas.toDatalessJSON());
|
|
||||||
|
|
||||||
try {
|
|
||||||
APP.realtime.contentUpdate(content);
|
|
||||||
} catch (e) {
|
|
||||||
APP.unrecoverable = true;
|
|
||||||
setEditable(false);
|
|
||||||
APP.toolbar.errorState(true, e.message);
|
|
||||||
var msg = Messages.chainpadError;
|
|
||||||
UI.errorLoadingScreen(msg, true, true);
|
|
||||||
console.error(e);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
palette: palette,
|
||||||
|
makeColorButton: makeColorButton,
|
||||||
|
updateLocalPalette: updateLocalPalette,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var mkHelpMenu = function (framework) {
|
||||||
|
var $appContainer = $('#cp-app-whiteboard-container');
|
||||||
|
var helpMenu = framework._.sfCommon.createHelpMenu(['whiteboard']);
|
||||||
|
$appContainer.prepend(helpMenu.menu);
|
||||||
|
framework._.toolbar.$drawer.append(helpMenu.button);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start of the main loop
|
||||||
|
var andThen2 = function (framework) {
|
||||||
|
var canvas = APP.canvas = new Fabric.Canvas('cp-app-whiteboard-canvas', {
|
||||||
|
containerClass: 'cp-app-whiteboard-canvas-container'
|
||||||
|
});
|
||||||
|
var $canvas = $('canvas');
|
||||||
|
var $canvasContainer = $('canvas').parents('.cp-app-whiteboard-canvas-container');
|
||||||
|
var $controls = $('#cp-app-whiteboard-controls');
|
||||||
|
var metadataMgr = framework._.cpNfInner.metadataMgr;
|
||||||
|
|
||||||
|
var setEditable = function (bool) {
|
||||||
|
if (bool) { $controls.css('display', 'flex'); }
|
||||||
|
else { $controls.hide(); }
|
||||||
|
|
||||||
|
canvas.isDrawingMode = bool ? APP.draw : false;
|
||||||
|
if (!bool) {
|
||||||
|
canvas.deactivateAll();
|
||||||
|
canvas.renderAll();
|
||||||
|
}
|
||||||
|
canvas.forEachObject(function (object) {
|
||||||
|
object.selectable = bool;
|
||||||
|
});
|
||||||
|
$canvasContainer.find('canvas').css('border-color', bool? 'black': 'red');
|
||||||
|
};
|
||||||
|
|
||||||
|
mkHelpMenu(framework);
|
||||||
|
|
||||||
|
var controls = mkControls(framework, canvas);
|
||||||
|
|
||||||
|
// ---------------------------------------------
|
||||||
|
// Whiteboard custom buttons
|
||||||
|
// ---------------------------------------------
|
||||||
|
|
||||||
|
var $rightside = framework._.toolbar.$rightside;
|
||||||
|
|
||||||
|
APP.FM = framework._.sfCommon.createFileManager({});
|
||||||
|
APP.upload = function (title) {
|
||||||
|
var canvas = $canvas[0];
|
||||||
|
APP.canvas.deactivateAll().renderAll();
|
||||||
|
canvas.toBlob(function (blob) {
|
||||||
|
blob.name = title;
|
||||||
|
APP.FM.handleFile(blob);
|
||||||
|
});
|
||||||
|
};
|
||||||
var addImageToCanvas = function (img) {
|
var addImageToCanvas = function (img) {
|
||||||
var w = img.width;
|
var w = img.width;
|
||||||
var h = img.height;
|
var h = img.height;
|
||||||
@ -370,107 +330,18 @@ define([
|
|||||||
}
|
}
|
||||||
var cImg = new Fabric.Image(img, { left:0, top:0, angle:0, });
|
var cImg = new Fabric.Image(img, { left:0, top:0, angle:0, });
|
||||||
APP.canvas.add(cImg);
|
APP.canvas.add(cImg);
|
||||||
onLocal();
|
framework.localChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
var initThumbnails = function () {
|
// Export to drive as PNG
|
||||||
var oldThumbnailState;
|
framework._.sfCommon.createButton('savetodrive', true, {}).click(function () {
|
||||||
var privateDat = metadataMgr.getPrivateData();
|
var defaultName = framework._.title.getTitle();
|
||||||
if (!privateDat.thumbnails) { return; }
|
UI.prompt(Messages.exportPrompt, defaultName + '.png', function (name) {
|
||||||
var hash = privateDat.availableHashes.editHash ||
|
|
||||||
privateDat.availableHashes.viewHash;
|
|
||||||
var href = privateDat.pathname + '#' + hash;
|
|
||||||
var mkThumbnail = function () {
|
|
||||||
if (!hash) { return; }
|
|
||||||
if (initializing) { return; }
|
|
||||||
if (!APP.realtime) { return; }
|
|
||||||
var content = APP.realtime.getUserDoc();
|
|
||||||
if (content === oldThumbnailState) { return; }
|
|
||||||
var D = Thumb.getResizedDimensions($canvas[0], 'pad');
|
|
||||||
Thumb.fromCanvas($canvas[0], D, function (err, b64) {
|
|
||||||
oldThumbnailState = content;
|
|
||||||
Thumb.setPadThumbnail(common, href, privateDat.channel, b64);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
window.setInterval(mkThumbnail, Thumb.UPDATE_INTERVAL);
|
|
||||||
window.setTimeout(mkThumbnail, Thumb.UPDATE_FIRST);
|
|
||||||
};
|
|
||||||
|
|
||||||
config.onInit = function (info) {
|
|
||||||
updateLocalPalette(palette);
|
|
||||||
readOnly = metadataMgr.getPrivateData().readOnly;
|
|
||||||
|
|
||||||
Title = common.createTitle({});
|
|
||||||
|
|
||||||
var configTb = {
|
|
||||||
displayed: [
|
|
||||||
'userlist',
|
|
||||||
'title',
|
|
||||||
'useradmin',
|
|
||||||
'spinner',
|
|
||||||
'newpad',
|
|
||||||
'share',
|
|
||||||
'limit',
|
|
||||||
'unpinnedWarning'
|
|
||||||
],
|
|
||||||
title: Title.getTitleConfig(),
|
|
||||||
metadataMgr: metadataMgr,
|
|
||||||
readOnly: readOnly,
|
|
||||||
realtime: info.realtime,
|
|
||||||
sfCommon: common,
|
|
||||||
$container: $bar,
|
|
||||||
$contentContainer: $('#cp-app-whiteboard-canvas-area')
|
|
||||||
};
|
|
||||||
toolbar = APP.toolbar = Toolbar.create(configTb);
|
|
||||||
Title.setToolbar(toolbar);
|
|
||||||
|
|
||||||
var $rightside = toolbar.$rightside;
|
|
||||||
var $drawer = toolbar.$drawer;
|
|
||||||
|
|
||||||
/* save as template */
|
|
||||||
if (!metadataMgr.getPrivateData().isTemplate) {
|
|
||||||
var templateObj = {
|
|
||||||
rt: info.realtime,
|
|
||||||
getTitle: function () { return metadataMgr.getMetadata().title; }
|
|
||||||
};
|
|
||||||
var $templateButton = common.createButton('template', true, templateObj);
|
|
||||||
$rightside.append($templateButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add an export button */
|
|
||||||
var $export = common.createButton('export', true, {}, saveImage);
|
|
||||||
$drawer.append($export);
|
|
||||||
|
|
||||||
if (common.isLoggedIn()) {
|
|
||||||
common.createButton('savetodrive', true, {}, function () {})
|
|
||||||
.click(function () {
|
|
||||||
UI.prompt(Messages.exportPrompt, document.title + '.png',
|
|
||||||
function (name) {
|
|
||||||
if (name === null || !name.trim()) { return; }
|
if (name === null || !name.trim()) { return; }
|
||||||
APP.upload(name);
|
APP.upload(name);
|
||||||
});
|
});
|
||||||
}).appendTo($rightside);
|
}).appendTo($rightside);
|
||||||
|
|
||||||
common.createButton('hashtag', true).appendTo($rightside);
|
|
||||||
}
|
|
||||||
|
|
||||||
var $forget = common.createButton('forget', true, {}, function (err) {
|
|
||||||
if (err) { return; }
|
|
||||||
setEditable(false);
|
|
||||||
});
|
|
||||||
$rightside.append($forget);
|
|
||||||
|
|
||||||
var $properties = common.createButton('properties', true);
|
|
||||||
toolbar.$drawer.append($properties);
|
|
||||||
|
|
||||||
var $appContainer = $('#cp-app-whiteboard-container');
|
|
||||||
var helpMenu = common.createHelpMenu(['whiteboard']);
|
|
||||||
$appContainer.prepend(helpMenu.menu);
|
|
||||||
toolbar.$drawer.append(helpMenu.button);
|
|
||||||
|
|
||||||
if (!readOnly) {
|
|
||||||
makeColorButton($rightside);
|
|
||||||
|
|
||||||
// Embed image
|
// Embed image
|
||||||
var onUpload = function (e) {
|
var onUpload = function (e) {
|
||||||
var file = e.target.files[0];
|
var file = e.target.files[0];
|
||||||
@ -484,7 +355,7 @@ define([
|
|||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
};
|
};
|
||||||
common.createButton('', true, {
|
framework._.sfCommon.createButton('', true, {
|
||||||
title: Messages.canvas_imageEmbed,
|
title: Messages.canvas_imageEmbed,
|
||||||
icon: 'fa-file-image-o',
|
icon: 'fa-file-image-o',
|
||||||
name: 'embedImage'
|
name: 'embedImage'
|
||||||
@ -492,12 +363,12 @@ define([
|
|||||||
$('<input>', {type:'file'}).on('change', onUpload).click();
|
$('<input>', {type:'file'}).on('change', onUpload).click();
|
||||||
}).appendTo($rightside);
|
}).appendTo($rightside);
|
||||||
|
|
||||||
if (common.isLoggedIn()) {
|
if (framework._.sfCommon.isLoggedIn()) {
|
||||||
var fileDialogCfg = {
|
var fileDialogCfg = {
|
||||||
onSelect: function (data) {
|
onSelect: function (data) {
|
||||||
if (data.type === 'file') {
|
if (data.type === 'file') {
|
||||||
var mt = '<media-tag src="' + data.src + '" data-crypto-key="cryptpad:' + data.key + '"></media-tag>';
|
var mt = '<media-tag src="' + data.src + '" data-crypto-key="cryptpad:' + data.key + '"></media-tag>';
|
||||||
common.displayMediatagImage($(mt), function (err, $image) {
|
framework._.sfCommon.displayMediatagImage($(mt), function (err, $image) {
|
||||||
Util.blobURLToImage($image.attr('src'), function (imgSrc) {
|
Util.blobURLToImage($image.attr('src'), function (imgSrc) {
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.onload = function () { addImageToCanvas(img); };
|
img.onload = function () { addImageToCanvas(img); };
|
||||||
@ -508,8 +379,8 @@ define([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
common.initFilePicker(fileDialogCfg);
|
framework._.sfCommon.initFilePicker(fileDialogCfg);
|
||||||
APP.$mediaTagButton = common.createButton('mediatag', true).click(function () {
|
framework._.sfCommon.createButton('mediatag', true).click(function () {
|
||||||
var pickerCfg = {
|
var pickerCfg = {
|
||||||
types: ['file'],
|
types: ['file'],
|
||||||
where: ['root'],
|
where: ['root'],
|
||||||
@ -517,166 +388,101 @@ define([
|
|||||||
fileType: ['image/']
|
fileType: ['image/']
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
common.openFilePicker(pickerCfg);
|
framework._.sfCommon.openFilePicker(pickerCfg);
|
||||||
}).appendTo($rightside);
|
}).appendTo($rightside);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$colors.hide();
|
|
||||||
$controls.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
metadataMgr.onChange(function () {
|
if (framework.isReadOnly()) {
|
||||||
var md = metadataMgr.getMetadata();
|
|
||||||
if (md.palette) {
|
|
||||||
updateLocalPalette(md.palette);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
config.onReady = function (info) {
|
|
||||||
if (APP.realtime !== info.realtime) {
|
|
||||||
APP.realtime = info.realtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userDoc = APP.realtime.getUserDoc();
|
|
||||||
var isNew = false;
|
|
||||||
var newDoc = '';
|
|
||||||
if (userDoc === "" || userDoc === "{}") { isNew = true; }
|
|
||||||
|
|
||||||
if (userDoc !== "") {
|
|
||||||
var hjson = JSON.parse(userDoc);
|
|
||||||
|
|
||||||
if (hjson && hjson.metadata) {
|
|
||||||
metadataMgr.updateMetadata(hjson.metadata);
|
|
||||||
}
|
|
||||||
if (typeof (hjson) !== 'object' || Array.isArray(hjson) ||
|
|
||||||
(hjson.metadata && typeof(hjson.metadata.type) !== 'undefined' &&
|
|
||||||
hjson.metadata.type !== 'whiteboard')) {
|
|
||||||
var errorText = Messages.typeError;
|
|
||||||
UI.errorLoadingScreen(errorText);
|
|
||||||
throw new Error(errorText);
|
|
||||||
}
|
|
||||||
newDoc = hjson.content;
|
|
||||||
} else {
|
|
||||||
Title.updateTitle(Title.defaultTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
nThen(function (waitFor) {
|
|
||||||
if (newDoc) {
|
|
||||||
canvas.loadFromJSON(newDoc, waitFor(function () {
|
|
||||||
console.log('loaded');
|
|
||||||
canvas.renderAll();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}).nThen(function () {
|
|
||||||
setEditable(!readOnly);
|
|
||||||
initializing = false;
|
|
||||||
config.onLocal();
|
|
||||||
UI.removeLoadingScreen();
|
|
||||||
|
|
||||||
initThumbnails();
|
|
||||||
|
|
||||||
|
|
||||||
if (readOnly) { return; }
|
|
||||||
|
|
||||||
var privateDat = metadataMgr.getPrivateData();
|
|
||||||
var skipTemp = Util.find(privateDat,
|
|
||||||
['settings', 'general', 'creation', 'noTemplate']);
|
|
||||||
var skipCreation = Util.find(privateDat, ['settings', 'general', 'creation', 'skip']);
|
|
||||||
if (isNew && (!AppConfig.displayCreationScreen || (!skipTemp && skipCreation))) {
|
|
||||||
common.openTemplatePicker();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
config.onRemote = function () {
|
|
||||||
if (initializing) { return; }
|
|
||||||
var userDoc = APP.realtime.getUserDoc();
|
|
||||||
|
|
||||||
var json = JSON.parse(userDoc);
|
|
||||||
var remoteDoc = json.content;
|
|
||||||
|
|
||||||
canvas.loadFromJSON(remoteDoc, function () {
|
|
||||||
canvas.renderAll();
|
|
||||||
if (json.metadata) {
|
|
||||||
metadataMgr.updateMetadata(json.metadata);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var content = canvas.toDatalessJSON();
|
|
||||||
if (content !== remoteDoc) { common.notify(); }
|
|
||||||
if (readOnly) { setEditable(false); }
|
|
||||||
};
|
|
||||||
|
|
||||||
config.onAbort = function () {
|
|
||||||
if (APP.unrecoverable) { return; }
|
|
||||||
// inform of network disconnect
|
|
||||||
setEditable(false);
|
setEditable(false);
|
||||||
toolbar.failed();
|
|
||||||
UI.alert(Messages.common_connectionLost, undefined, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
config.onConnectionChange = function (info) {
|
|
||||||
if (APP.unrecoverable) { return; }
|
|
||||||
setEditable(info.state);
|
|
||||||
if (info.state) {
|
|
||||||
initializing = true;
|
|
||||||
//UI.findOKButton().click();
|
|
||||||
} else {
|
} else {
|
||||||
//UI.alert(Messages.common_connectionLost, undefined, true);
|
controls.makeColorButton($rightside);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
config.onError = function (err) {
|
|
||||||
common.onServerError(err, toolbar, function () {
|
|
||||||
APP.unrecoverable = true;
|
|
||||||
setEditable(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
cpNfInner = common.startRealtime(config);
|
|
||||||
metadataMgr = cpNfInner.metadataMgr;
|
|
||||||
|
|
||||||
cpNfInner.onInfiniteSpinner(function () {
|
|
||||||
if (APP.unrecoverable) { return; }
|
|
||||||
setEditable(false);
|
|
||||||
UI.confirm(Messages.realtime_unrecoverableError, function (yes) {
|
|
||||||
if (!yes) { return; }
|
|
||||||
common.gotoURL();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.on('mouse:up', onLocal);
|
|
||||||
|
|
||||||
$('#cp-app-whiteboard-clear').on('click', function () {
|
$('#cp-app-whiteboard-clear').on('click', function () {
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
onLocal();
|
framework.localChange();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#save').on('click', function () {
|
// ---------------------------------------------
|
||||||
saveImage();
|
// End custom
|
||||||
|
// ---------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
framework.onEditableChange(function () {
|
||||||
|
var locked = framework.isLocked() || framework.isReadOnly();
|
||||||
|
setEditable(!locked);
|
||||||
});
|
});
|
||||||
|
|
||||||
common.onLogout(function () { setEditable(false); });
|
framework.setFileExporter('png', function (cb) {
|
||||||
|
$canvas[0].toBlob(function (blob) {
|
||||||
|
cb(blob);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
framework.setNormalizer(function (c) {
|
||||||
|
return {
|
||||||
|
content: c.content
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
framework.onContentUpdate(function (newContent, waitFor) {
|
||||||
|
var content = newContent.content;
|
||||||
|
canvas.loadFromJSON(content, waitFor(function () {
|
||||||
|
canvas.renderAll();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
framework.setContentGetter(function () {
|
||||||
|
var content = canvas.toDatalessJSON();
|
||||||
|
return {
|
||||||
|
content: content
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
framework.onReady(function () {
|
||||||
|
var oldThumbnailState;
|
||||||
|
var privateDat = metadataMgr.getPrivateData();
|
||||||
|
if (!privateDat.thumbnails) { return; }
|
||||||
|
var hash = privateDat.availableHashes.editHash ||
|
||||||
|
privateDat.availableHashes.viewHash;
|
||||||
|
var href = privateDat.pathname + '#' + hash;
|
||||||
|
var mkThumbnail = function () {
|
||||||
|
if (!hash) { return; }
|
||||||
|
if (framework.getState() !== 'READY') { return; }
|
||||||
|
if (!framework._.cpNfInner.chainpad) { return; }
|
||||||
|
var content = framework._.cpNfInner.chainpad.getUserDoc();
|
||||||
|
if (content === oldThumbnailState) { return; }
|
||||||
|
var D = Thumb.getResizedDimensions($canvas[0], 'pad');
|
||||||
|
Thumb.fromCanvas($canvas[0], D, function (err, b64) {
|
||||||
|
oldThumbnailState = content;
|
||||||
|
Thumb.setPadThumbnail(framework._.sfCommon, href, privateDat.channel, b64);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
window.setInterval(mkThumbnail, Thumb.UPDATE_INTERVAL);
|
||||||
|
window.setTimeout(mkThumbnail, Thumb.UPDATE_FIRST);
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.on('mouse:up', framework.localChange);
|
||||||
|
framework.start();
|
||||||
};
|
};
|
||||||
|
|
||||||
var main = function () {
|
var main = function () {
|
||||||
var common;
|
// var framework;
|
||||||
|
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor(function () {
|
$(waitFor(function () {
|
||||||
UI.addLoadingScreen();
|
|
||||||
var $div = $('<div>').append(Pages['/whiteboard/']());
|
var $div = $('<div>').append(Pages['/whiteboard/']());
|
||||||
$('body').append($div.html());
|
$('body').append($div.html());
|
||||||
}));
|
}));
|
||||||
SFCommon.create(waitFor(function (c) { APP.common = common = c; }));
|
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
common.getSframeChannel().onReady(waitFor());
|
|
||||||
}).nThen(function (waitFor) {
|
// Framework initialization
|
||||||
common.handleNewFile(waitFor);
|
Framework.create({
|
||||||
}).nThen(function (/*waitFor*/) {
|
patchTransformer: ChainPad.NaiveJSONTransformer,
|
||||||
andThen(common);
|
toolbarContainer: '#cp-toolbar',
|
||||||
|
contentContainer: '#cp-app-whiteboard-canvas-area',
|
||||||
|
}, waitFor(function (framework) {
|
||||||
|
andThen2(framework);
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
main();
|
main();
|
||||||
|
|||||||
@ -51,6 +51,8 @@ define([
|
|||||||
if (!window.Worker) {
|
if (!window.Worker) {
|
||||||
return void $container.text("WebWorkers not supported by your browser");
|
return void $container.text("WebWorkers not supported by your browser");
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
// Shared worker
|
||||||
console.log('ready');
|
console.log('ready');
|
||||||
var myWorker = new SharedWorker('/worker/worker.js');
|
var myWorker = new SharedWorker('/worker/worker.js');
|
||||||
console.log(myWorker);
|
console.log(myWorker);
|
||||||
@ -65,7 +67,73 @@ define([
|
|||||||
}
|
}
|
||||||
$container.append('<br>');
|
$container.append('<br>');
|
||||||
$container.append(e.data);
|
$container.append(e.data);
|
||||||
|
};*/
|
||||||
|
|
||||||
|
// Service worker
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
console.log('here');
|
||||||
|
var initializing = true;
|
||||||
|
var worker;
|
||||||
|
var postMessage = function (data) {
|
||||||
|
console.log(data, navigator.serviceWorker);
|
||||||
|
if (worker) {
|
||||||
|
return void worker.postMessage(data);
|
||||||
|
}
|
||||||
|
console.log('NOT READY');
|
||||||
|
/*if (navigator.serviceWorker && navigator.serviceWorker.controller) {
|
||||||
|
navigator.serviceWorker.controller.postMessage(data);
|
||||||
|
}*/
|
||||||
};
|
};
|
||||||
|
navigator.serviceWorker.register('/worker/sw.js', {scope: '/'})
|
||||||
|
.then(function(reg) {
|
||||||
|
console.log(reg);
|
||||||
|
console.log('Registration succeeded. Scope is ' + reg.scope);
|
||||||
|
$container.append('<br>');
|
||||||
|
$container.append('Registered! (scope: ' + reg.scope +')');
|
||||||
|
reg.onupdatefound = function () {
|
||||||
|
if (initializing) {
|
||||||
|
var w = reg.installing;
|
||||||
|
var onStateChange = function () {
|
||||||
|
if (w.state === "activated") {
|
||||||
|
console.log(w);
|
||||||
|
worker = w;
|
||||||
|
postMessage("INIT");
|
||||||
|
w.removeEventListener("statechange", onStateChange);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w.addEventListener('statechange', onStateChange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('new SW version found!');
|
||||||
|
// KILL EVERYTHING
|
||||||
|
UI.confirm("New version detected, you have to reload", function (yes) {
|
||||||
|
if (yes) { common.gotoURL(); }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// Here we add the event listener for receiving messages
|
||||||
|
navigator.serviceWorker.addEventListener('message', function (e) {
|
||||||
|
var data = e.data;
|
||||||
|
if (data && data.state === "READY") {
|
||||||
|
initializing = false;
|
||||||
|
$container.append('<hr>sw.js ready');
|
||||||
|
postMessage(["Hello worker"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$container.append('<br>');
|
||||||
|
$container.append(e.data);
|
||||||
|
});
|
||||||
|
if (reg.active) {
|
||||||
|
worker = reg.active;
|
||||||
|
postMessage("INIT");
|
||||||
|
}
|
||||||
|
}).catch(function(error) {
|
||||||
|
console.log('Registration failed with ' + error);
|
||||||
|
$container.append('Registration error: ' + error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('NO SERVICE WORKER');
|
||||||
|
}
|
||||||
|
|
||||||
$container.append('<hr>inner.js ready');
|
$container.append('<hr>inner.js ready');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
69
www/worker/sw.js
Normal file
69
www/worker/sw.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* jshint ignore:start */
|
||||||
|
var id;
|
||||||
|
//= Math.floor(Math.random()*100000);
|
||||||
|
|
||||||
|
var postMsg = function (client, data) {
|
||||||
|
client.postMessage(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
var broadcast = function (data, excludes) {
|
||||||
|
// Loop over all available clients
|
||||||
|
clients.matchAll().then(function (clients) {
|
||||||
|
clients.forEach(function (client) {
|
||||||
|
if (excludes.indexOf(client.id) === -1) {
|
||||||
|
postMsg(client, data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
var sendTo = function (data, clientId){
|
||||||
|
clients.matchAll().then(function (clients) {
|
||||||
|
clients.some(function (client) {
|
||||||
|
if (client.id === clientId) {
|
||||||
|
postMsg(client, data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
var getClients = function () {
|
||||||
|
clients.matchAll().then(function (clients) {
|
||||||
|
var cl = clients.map(function (c) {
|
||||||
|
console.log(JSON.stringify(c));
|
||||||
|
return c.id;
|
||||||
|
});
|
||||||
|
console.log(cl);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.addEventListener('message', function (e) {
|
||||||
|
console.log(clients);
|
||||||
|
console.log('worker received');
|
||||||
|
console.log(e.data);
|
||||||
|
console.log(e.source);
|
||||||
|
var cId = e.source.id;
|
||||||
|
if (e.data === "INIT") {
|
||||||
|
if (!id) {
|
||||||
|
id = Math.floor(Math.random()*100000);
|
||||||
|
}
|
||||||
|
broadcast(cId + ' has joined!', [cId]);
|
||||||
|
postMsg(e.source, {state: 'READY'});
|
||||||
|
postMsg(e.source, "Welcome to SW " + id + "!");
|
||||||
|
postMsg(e.source, "You are identified as " + cId);
|
||||||
|
} else {
|
||||||
|
console.log(e.data);
|
||||||
|
postMsg(e.source, 'Yo (Re: '+e.data+')');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.addEventListener('install', function (e) {
|
||||||
|
console.log(e);
|
||||||
|
console.log('V1 installing…');
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', function (e) {
|
||||||
|
console.log(e);
|
||||||
|
console.log('V1 now ready to handle fetches!');
|
||||||
|
});
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user