diff --git a/.jshintignore b/.jshintignore index 919395546..c2037807f 100644 --- a/.jshintignore +++ b/.jshintignore @@ -13,3 +13,4 @@ www/common/media-tag.js www/scratch www/common/toolbar.js +www/common/hyperscript.js diff --git a/bower.json b/bower.json index 4dc8deec8..0fb80b9f9 100644 --- a/bower.json +++ b/bower.json @@ -37,6 +37,8 @@ "diff-dom": "^2.1.1", "alertifyjs": "^1.0.11", "scrypt-async": "^1.2.0", + "require-css": "^0.1.10", + "less": "^2.7.2", "bootstrap": "#v4.0.0-alpha.6" } } diff --git a/customize.dist/about.html b/customize.dist/about.html index 613cac012..5593e41b9 100644 --- a/customize.dist/about.html +++ b/customize.dist/about.html @@ -5,120 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - - + -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
- - - - - - - - - +

OOPS In order to do encryption in your browser, Javascript is really really required.

+

OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.

+ diff --git a/customize.dist/contact.html b/customize.dist/contact.html index 1bcc53dfc..5593e41b9 100644 --- a/customize.dist/contact.html +++ b/customize.dist/contact.html @@ -5,117 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - - + -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
- - - - - - - - - +

OOPS In order to do encryption in your browser, Javascript is really really required.

+

OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.

+ diff --git a/customize.dist/index.html b/customize.dist/index.html index 287592c42..5593e41b9 100644 --- a/customize.dist/index.html +++ b/customize.dist/index.html @@ -5,239 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - - + -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
- - - - - - - - - +

OOPS In order to do encryption in your browser, Javascript is really really required.

+

OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.

+ diff --git a/customize.dist/pages.js b/customize.dist/pages.js new file mode 100644 index 000000000..4f77432be --- /dev/null +++ b/customize.dist/pages.js @@ -0,0 +1,369 @@ +define([ + '/common/hyperscript.js', + '/common/cryptpad-common.js', +], function (h, Cryptpad) { + var Pages = {}; + var Msg = Cryptpad.Messages; + + var setHTML = function (e, html) { + e.innerHTML = html; + return e; + }; + + Pages['/about.html'] = function () { + return h('div#main_other', [ + h('center', [ + h('h1', Msg.about) + ]), + setHTML(h('p'), Msg.main_p2), + h('h2', Msg.main_howitworks), + setHTML(h('p', Msg.main_howitworks_p1)) + ]); + }; + + Pages['/privacy.html'] = function () { + return h('div#main_other', [ + h('center', h('h1', Msg.policy_title)), + h('h2', Msg.policy_whatweknow), + h('p', Msg.policywhatweknow_p1), + + h('h2', Msg.policy_howweuse), + h('p', Msg.policy_howweuse_p1), + h('p', Msg.policy_howweuse_p2), + + h('h2', Msg.policy_whatwetell), + h('p', Msg.policy_whatwetell_p1), + + h('h2', Msg.policy_links), + h('p', Msg.policy_links_p1), + + h('h2', Msg.policy_ads), + h('p', Msg.policy_ads_p1), + + h('h2', Msg.policy_choices), + h('p', Msg.policy_choices_open), + setHTML(h('p'), Msg.policy_choices_vpn), + + h('br') + ]); + }; + + Pages['/terms.html'] = function () { + return h('div#main_other', [ + h('center', h('h1', Msg.tos_title)), + h('p', Msg.tos_legal), + h('p', Msg.tos_availability), + h('p', Msg.tos_e2ee), + h('p', Msg.tos_logs), + h('p', Msg.tos_3rdparties), + ]); + }; + + Pages['/contact.html'] = function () { + return h('div#main_other', [ + h('center', h('h1', Msg.contact)), + setHTML(h('p'), Msg.main_about_p2) + ]); + }; + + var userForm = function () { + return h('div#userForm.form-group.hidden', [ + h('input#name.form-control', { + name: 'name', + type: 'text', + placeholder: Msg.login_username + }), + h('input#password.form-control', { + name: 'password', + type: 'password', + placeholder: Msg.login_password + }), + h('div', { + style: { display: 'none' } + }, [ + h('span.remember.form-check', [ + h('label.form-check-label', { + 'for': 'rememberme', + placeholder: Msg.login_remember, + }, [ + h('input#rememberme.form-check-input', { + type: 'checkbox', + checked: true + }) + ]) + ]) + ]), + h('button.btn.btn-secondary.login.half.first', Msg.login_login), + h('button.btn.btn-success.register.half.first', Msg.login_register), + h('p.separator', Msg.login_orNoLogin), + h('p#buttons.buttons'), + h('p.driveLink', [ + h('a.gotodrive', { + href: '/drive/' + }, Msg.login_nologin) + ]) + ]); + }; + + var indexContent = function () { + return [ + h('div.page.category.first#knowmore', [ + h('center', [ + h('h1', Msg.main_howitworks) + ]) + ]), + h('div.page', [ + h('div.info-container', [ + h('div.left.image', [ + h('img', { + src: '/customize/images/zeroknowledge_small.png', + alt: 'Zero Knowledge' + }) + ]), + h('div.right', [ + h('h2', Msg.main_zeroKnowledge), + setHTML(h('p'), Msg.main_zeroKnowledge_p) + ]) + ]) + ]), + h('div.page.even', [ + h('div.info-container', [ + h('div.left', [ + h('h2', Msg.main_writeItDown), + h('p', Msg.main_writeItDown_p) + ]), + h('div.right.image', [ + h('img', { + alt: "User account", + src: '/customize/images/realtime_small.png', + }) + ]) + ]) + ]), + h('div.page', [ + h('div.info-container', [ + h('div.left.image', [ + h('img', { + src: '/customize/images/key_small.png', + alt: 'User account' + }) + ]), + h('div.right', [ + h('h2', Msg.main_share), + h('p', Msg.main_share_p) + ]) + ]) + ]), + h('div.page.even', [ + h('div.info-container', [ + h('div.left', [ + h('h2', Msg.main_organize), + h('p', Msg.main_organize_p) + ]), + h('div.right.image', [ + h('img', { + src: '/customize/images/organize.png', + alt: 'User account' + }) + ]) + ]) + ]) + ]; + }; + + var appButton = function (alt, h2, img, p, url, btn, id) { + return h('div.app', [ + h('center', [ + h('h2', h2), + h('img', { + alt: 'Rich Text application', + src: img, + }) + ]), + setHTML(h('p'), p), + h('p.buttons', [ + h('a#' + id, { + href: url, + }, [ + h('button.btn.btn-secondary', btn), + ]) + ]) + ]); + }; + + var tryIt = function () { + return [ + h('div.class.category#tryit', [ + h('center', [ + h('h1', Msg.tryIt) + ]) + ]), + h('div.page', [ + h('div.app-container', [ + h('div.app-row', [ + appButton("Rich Text application", + Msg.main_richText, + '/customize/images/pad.png', + Msg.main_richText_p, + '/pad/', + Msg.button_newpad, + 'create-pad'), + appButton('Code application', + Msg.main_code, + '/customize/images/code.png', + Msg.main_code_p, + '/code/', + Msg.button_newcode, + 'create-code'), + appButton('Slide application', + Msg.main_slide, + '/customize/images/slide.png', + Msg.main_slide_p, + '/slide/', + Msg.button_newslide, + 'create-slide'), + appButton('Poll application', + Msg.main_poll, + '/customize/images/poll.png', + Msg.main_poll_p, + '/poll/', + Msg.button_newpoll, + 'create-poll') + ]) + ]) + ]) + ]; + }; + + Pages['/'] = Pages['/index.html'] = function () { + return [ + h('div#main', [ + h('div.mainOverlay'), + h('div#align-container', [ + h('div#main-container', [ + h('div#data.hidden', [ + setHTML(h('p.left'), Msg.main_info), + ]), + userForm(), + h('div#loggedIn.hidden', [ + h('p#loggedInHello'), + h('p', [ + h('button.btn.btn-primary.gotodrive', Msg.login_accessDrive), + ]), + h('p', [ + h('button#loggedInLogout.btn.btn-secondary', Msg.logoutButton) + ]) + ]) + ]) + ]), + ]) + ] + .concat(tryIt()) + .concat(indexContent()); + }; + + var loadingScreen = function () { + return h('div#loading', + h('div.loadingContainer', [ + h('img.cryptofist', { + src: '/customize/cryptofist_small.png' + }), + h('div.spinnerContainer', + h('span.fa.fa-spinner.fa-pulse.fa-4x.fa-fw')), + h('p', Msg.loading) + ]) + ); + }; + loadingScreen = loadingScreen; // TODO use this + + Pages['/settings/'] = Pages['/settings/index.html'] = function () { + return h('div#container'); + }; + + Pages['/user/'] = Pages['/user/index.html'] = function () { + return h('div#container'); + }; + + Pages['/register/'] = Pages['/register/index.html'] = function () { + return [h('div#main', [ + h('div.mainOverlay'), + h('div#align-container', [ + h('div#data.hidden', [ + h('h1', Msg.register_header), + h('br'), + setHTML(h('p.left.register-explanation'), Msg.register_explanation) + ]), + h('div#userForm.form-group.hidden', [ + h('input.form-control#username', { + type: 'text', + autocomplete: 'off', + autocorrect: 'off', + autocapitalize: 'off', + spellcheck: false, + placeholder: Msg.login_username, + autofocus: true, + }), + h('input.form-control#password', { + type: 'password', + placeholder: Msg.login_password, + }), + h('input.form-control#password-confirm', { + type: 'password', + placeholder: Msg.login_confirm, + }), + h('input#import-recent', { + type: 'checkbox', + checked: true + }), + h('label', { + 'for': 'import-recent', + }, Msg.register_importRecent), + h('br'), + h('input#accept-terms', { + type: 'checkbox' + }), + setHTML(h('label', { + 'for': 'accept-terms', + }), Msg.register_acceptTerms), + h('br'), + h('button#register.btn.btn-primary', Msg.login_register) + ]) + ]) + ])]; + }; + + Pages['/login/'] = Pages['/login/index.html'] = function () { + return [h('div#main', [ + h('div.mainOverlay'), + h('div#align-container', + h('div#main-container', [ + h('div#data.hidden', setHTML(h('p.left'), Msg.main_info)), + h('div#userForm.form-group.hidden', [ + h('input.form-control#name', { + name: 'name', + type: 'text', + autocomplete: 'off', + autocorrect: 'off', + autocapitalize: 'off', + spellcheck: false, + placeholder: Msg.login_username, + autofocus: true, + }), + h('input.form-control#password', { + type: 'password', + 'name': 'password', + placeholder: Msg.login_password, + }), + h('button.btn.btn-primary.login.first', Msg.login_login), + h('div.extra', [ + h('p', Msg.login_notRegistered), + h('button#register.btn.btn-success.register.first', Msg.login_register) + ]) + ]) + ]) + ) + ])]; + }; + + return Pages; +}); diff --git a/customize.dist/privacy.html b/customize.dist/privacy.html index 3d4e8f99f..5593e41b9 100644 --- a/customize.dist/privacy.html +++ b/customize.dist/privacy.html @@ -5,138 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - - + -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
- - - - - - - - - +

OOPS In order to do encryption in your browser, Javascript is really really required.

+

OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.

+ diff --git a/customize.dist/src/build.js b/customize.dist/src/build.js deleted file mode 100644 index fbcc34942..000000000 --- a/customize.dist/src/build.js +++ /dev/null @@ -1,85 +0,0 @@ -var Fs = require("fs"); - -// read a file -var read = function (path) { - return Fs.readFileSync(path, 'utf-8'); -}; - -// write a file -var write = function (path, src) { - return Fs.writeFileSync(path, src); -}; - -// basic templating -var swap = function (src, dict) { - return src.replace(/\{\{(.*?)\}\}/g, function (a, b) { - return dict[b] || b; - }); -}; - -// read the template file -var template = read('./template.html'); - -// read page fragments -var fragments = {}; -[ 'index', - 'fork', - 'topbar', - 'terms', - 'privacy', - 'about', - 'contact', - 'logo', - 'noscript', - 'footer', - 'empty', - 'script', - 'appscript' -].forEach(function (name) { - fragments[name] = read('./fragments/' + name + '.html'); -}); - -// build static pages -['index', 'privacy', 'terms', 'about', 'contact'].forEach(function (page) { - var source = swap(template, { - topbar: fragments.topbar, - fork: fragments.fork, - main: swap(fragments[page] || fragments.empty, { - topbar: fragments.topbar, - fork: fragments.fork, - logo: fragments.logo, - noscript: fragments.noscript, - footer: fragments.footer, - }), - logo: fragments.logo, - noscript: fragments.noscript, - footer: fragments.footer, - script: fragments.script - }); - write('../' + page + '.html', source); -}); - -// build static pages -[ - '../www/settings/index', - '../www/user/index' -].forEach(function (page) { - var source = swap(template, { - topbar: fragments.topbar, - fork: fragments.fork, - main: swap(fragments[page] || fragments.empty, { - topbar: fragments.topbar, - fork: fragments.fork, - logo: fragments.logo, - noscript: fragments.noscript, - footer: fragments.footer, - }), - logo: fragments.logo, - noscript: fragments.noscript, - footer: fragments.footer, - script: fragments.appscript - }); - write('../' + page + '.html', source); -}); - - diff --git a/customize.dist/src/fragments/about.html b/customize.dist/src/fragments/about.html deleted file mode 100644 index 5956b69ac..000000000 --- a/customize.dist/src/fragments/about.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
-

About

-
- -

- -

-

-
- diff --git a/customize.dist/src/fragments/appscript.html b/customize.dist/src/fragments/appscript.html deleted file mode 100644 index 3f1dd7b58..000000000 --- a/customize.dist/src/fragments/appscript.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/customize.dist/src/fragments/contact.html b/customize.dist/src/fragments/contact.html deleted file mode 100644 index 340a26e83..000000000 --- a/customize.dist/src/fragments/contact.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
-

Contact

-
- -

-
- diff --git a/customize.dist/src/fragments/empty.html b/customize.dist/src/fragments/empty.html deleted file mode 100644 index d42a450af..000000000 --- a/customize.dist/src/fragments/empty.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/customize.dist/src/fragments/footer.html b/customize.dist/src/fragments/footer.html deleted file mode 100644 index cdc0dc3a0..000000000 --- a/customize.dist/src/fragments/footer.html +++ /dev/null @@ -1,43 +0,0 @@ - diff --git a/customize.dist/src/fragments/fork.html b/customize.dist/src/fragments/fork.html deleted file mode 100644 index 668c38648..000000000 --- a/customize.dist/src/fragments/fork.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/customize.dist/src/fragments/index.html b/customize.dist/src/fragments/index.html deleted file mode 100644 index d38d04a66..000000000 --- a/customize.dist/src/fragments/index.html +++ /dev/null @@ -1,127 +0,0 @@ -{{fork}} - -
-
-
-
- - - - -
-
-
-
-
-

-
-
-
-
-
- Zero Knowledge -
-
-

-

-
-
-
-
-
-
-

-

-
-
- User account -
-
-
-
-
-
- User account -
-
-

-

-
-
-
-
-
-
-

-

-
-
- User account -
-
-
-
-
-

Try it out!

-
-
-
-
-
-
-
-

- Rich Text application -
-

-

- -

-
-
-

- Code application -
-

-

- -

-
-
-

- Slide applcation -
-

-

- -

-
-
-

- Poll application -
-

-

- -

-
-
-
-
diff --git a/customize.dist/src/fragments/logo.html b/customize.dist/src/fragments/logo.html deleted file mode 100644 index 35fca4e5e..000000000 --- a/customize.dist/src/fragments/logo.html +++ /dev/null @@ -1,3 +0,0 @@ -
- -
diff --git a/customize.dist/src/fragments/noscript.html b/customize.dist/src/fragments/noscript.html deleted file mode 100644 index f59294ea3..000000000 --- a/customize.dist/src/fragments/noscript.html +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/customize.dist/src/fragments/privacy.html b/customize.dist/src/fragments/privacy.html deleted file mode 100644 index fa1b95b35..000000000 --- a/customize.dist/src/fragments/privacy.html +++ /dev/null @@ -1,29 +0,0 @@ -
-
-

-
- -

-

- -

-

-

- -

-

- -

-

- -

-

- -

-

-

- -
-
- - diff --git a/customize.dist/src/fragments/script.html b/customize.dist/src/fragments/script.html deleted file mode 100644 index 35a65e8a1..000000000 --- a/customize.dist/src/fragments/script.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/customize.dist/src/fragments/table.html b/customize.dist/src/fragments/table.html deleted file mode 100644 index 3db6c6c76..000000000 --- a/customize.dist/src/fragments/table.html +++ /dev/null @@ -1,14 +0,0 @@ - - diff --git a/customize.dist/src/fragments/terms.html b/customize.dist/src/fragments/terms.html deleted file mode 100644 index 11ae1c512..000000000 --- a/customize.dist/src/fragments/terms.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
-

-
- -

-

-

-

-

-
- diff --git a/customize.dist/src/fragments/topbar.html b/customize.dist/src/fragments/topbar.html deleted file mode 100644 index c1ed7e24b..000000000 --- a/customize.dist/src/fragments/topbar.html +++ /dev/null @@ -1,30 +0,0 @@ -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
diff --git a/customize.dist/src/template.html b/customize.dist/src/template.html index 4615cce7f..5593e41b9 100644 --- a/customize.dist/src/template.html +++ b/customize.dist/src/template.html @@ -5,21 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - {{script}} + - {{topbar}} - - {{noscript}} - - - - {{footer}} - + diff --git a/customize.dist/template.js b/customize.dist/template.js new file mode 100644 index 000000000..0fd412a03 --- /dev/null +++ b/customize.dist/template.js @@ -0,0 +1,138 @@ +define([ + 'jquery', + '/common/hyperscript.js', + '/common/cryptpad-common.js', + '/customize/pages.js', + + 'css!/customize/main.css', + 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', + 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', +], function ($, h, Cryptpad, Pages) { +$(function () { + var Messages = Cryptpad.Messages; + var $body = $('body'); + + var rightLink = function (ref, loc, txt) { + return h('span.link.right', [ + h('a', { href: ref, 'data-localization': loc}, txt) + ]); + }; + + var $topbar = $(h('div#cryptpadTopBar', [ + h('span', [ + h('a.gotoMain', {href: '/'}, [ + h('img.cryptpad-logo', { + src: '/customize/cryptofist_mini.png', + alt: '', + }), + 'CryptPad' + ]) + ]), + h('span#user-menu.right.dropdown-bar'), + h('span#language-selector.right.dropdown-bar'), + + rightLink('/about.html', 'about', 'About'), + rightLink('/privacy.html', 'privacy', 'Privacy'), + rightLink('/terms.html', 'terms', 'ToS'), + rightLink('/contact.html', 'contact', 'Contact'), + rightLink('https://blog.cryptpad.fr/', 'blog', 'Blog'), + h('span.link.right', [ + h('button#upgrade.upgrade.btn.buttonSuccess', { + style: { display: 'none' } + }) + ]) + ] + )); + + var infoPage = function () { + return h('div#mainBlock.hidden', typeof(Pages[location.pathname]) === 'function'? + Pages[location.pathname](): [h('div#container')]); + }; + + var $main = $(infoPage()); + + var footerCol = function (title, L, literal) { + return h('div.col', [ + h('ul.list-unstyled', [ + h('li.title', { + 'data-localization': title, + }, title? Messages[title]: literal ) + ].concat(L.map(function (l) { + return h('li', [ l ]); + })) + ) + ]); + }; + + var footLink = function (ref, loc, text) { + var attrs = { + href: ref, + }; + if (!/^\//.test(ref)) { + attrs.target = '_blank'; + attrs.rel = 'noopener noreferrer'; + } + if (loc) { + attrs['data-localization'] = loc; + text = Messages[loc]; + } + return h('a', attrs, text); + }; + + var $footer = $(h('footer', [ + h('div.container', [ + h('div.row', [ + footerCol(null, [ + footLink('/about.html', 'about'), + footLink('/terms.html', 'terms'), + footLink('/privacy.html', 'privacy'), + ], 'CryptPad'), + footerCol('footer_applications', [ + footLink('/drive/', 'main_drive'), + footLink('/pad/', 'main_richText'), + footLink('/code/', 'main_code'), + footLink('/slide/', 'main_slide'), + footLink('/poll/', 'main_poll'), + footLink('/whiteboard/', null, Messages.type.whiteboard) + ]), + footerCol('footer_aboutUs', [ + footLink('https://blog.cryptpad.fr', 'blog'), + footLink('https://labs.xwiki.com', null, 'XWiki Labs'), + footLink('http://www.xwiki.com', null, 'XWiki SAS'), + footLink('https://www.open-paas.org', null, 'OpenPaaS') + ]), + footerCol('footer_contact', [ + footLink('https://riot.im/app/#/room/#cryptpad:matrix.org', null, 'Chat'), + footLink('https://twitter.com/cryptpad', null, 'Twitter'), + footLink('https://github.com/xwiki-labs/cryptpad', null, 'GitHub'), + footLink('/contact.html', null, 'Email') + ]) + ]) + ]), + h('div.version-footer', "CryptPad v1.10.0 (Kraken)") + ])); + + var pathname = location.pathname; + if (/^\/(pad|code|slide|poll|whiteboard)\//.test(pathname)) { + // TODO load apps + return; + } + + $body.append($topbar).append($main).append($footer); + + if (/^\/settings\//.test(pathname)) { + require([ '/settings/main.js', ], function () {}); + } else if (/^\/user\//.test(pathname)) { + require([ '/user/main.js'], function () {}); + } else if (/^\/register\//.test(pathname)) { + require([ '/register/main.js' ], function () {}); + } else if (/^\/login\//.test(pathname)) { + require([ '/login/main.js' ], function () {}); + } else if (/^\/($|^\/index\.html$)/.test(pathname)) { + // TODO use different top bar + require([ '/customize/main.js', ], function () {}); + } else { + require([ '/customize/main.js', ], function () {}); + } +}); +}); diff --git a/customize.dist/terms.html b/customize.dist/terms.html index 62dc97f0e..5593e41b9 100644 --- a/customize.dist/terms.html +++ b/customize.dist/terms.html @@ -5,121 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - - + -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
- - - - - - - - - +

OOPS In order to do encryption in your browser, Javascript is really really required.

+

OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.

+ diff --git a/package.json b/package.json index 864d27b52..aa6aad896 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,6 @@ "lint": "jshint --config .jshintrc --exclude-path .jshintignore .", "test": "node TestSelenium.js", "style": "lessc ./customize.dist/src/less/cryptpad.less > ./customize.dist/main.css && lessc ./customize.dist/src/less/toolbar.less > ./customize.dist/toolbar.css && lessc ./www/drive/file.less > ./www/drive/file.css && lessc ./www/settings/main.less > ./www/settings/main.css && lessc ./www/slide/slide.less > ./www/slide/slide.css && lessc ./www/whiteboard/whiteboard.less > ./www/whiteboard/whiteboard.css && lessc ./www/poll/poll.less > ./www/poll/poll.css && lessc ./www/file/file.less > ./www/file/file.css && lessc ./www/code/code.less > ./www/code/code.css", - "template": "cd customize.dist/src && node build.js" + "template": "cd customize.dist/src && for page in ../index.html ../privacy.html ../terms.html ../about.html ../contact.html ../../www/login/index.html ../../www/register/index.html ../../www/settings/index.html ../../www/user/index.html;do echo $page; cp template.html $page; done;" } } diff --git a/www/code/main.js b/www/code/main.js index b9fb3c37a..2667a9585 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -174,7 +174,7 @@ define([ var titleCfg = { getHeadingText: CodeMirror.getHeadingText }; Title = Cryptpad.createTitle(titleCfg, config.onLocal, Cryptpad); - Metadata = Cryptpad.createMetadata(UserList, Title); + Metadata = Cryptpad.createMetadata(UserList, Title, null, Cryptpad); var configTb = { displayed: ['title', 'useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad', 'limit', 'upgrade'], @@ -310,7 +310,8 @@ define([ if(userDoc !== "") { var hjson = JSON.parse(userDoc); - if (typeof (hjson) !== 'object' || Array.isArray(hjson)) { + if (typeof (hjson) !== 'object' || Array.isArray(hjson) || + (typeof(hjson.type) !== 'undefined' && hjson.type !== 'code')) { var errorText = Messages.typeError; Cryptpad.errorLoadingScreen(errorText); throw new Error(errorText); diff --git a/www/common/LessLoader.js b/www/common/LessLoader.js new file mode 100644 index 000000000..a2ba28c0c --- /dev/null +++ b/www/common/LessLoader.js @@ -0,0 +1,64 @@ +/*@flow*/ +/*:: const define = () => {}; */ +define([ + '/api/config', + '/bower_components/less/dist/less.js' +], function (Config, Less) { /*::});module.exports = (function() { + const Config = (undefined:any); + const Less = (undefined:any); + */ + + var module = { exports: {} }; + var key = Config.requireConf.urlArgs; + var localStorage = window.localStorage || {}; + + var fixURL = function (url) { + var mark = (url.indexOf('?') !== -1) ? '&' : '?'; + return url + mark + key; + }; + + var doXHR = Less.FileManager.prototype.doXHR; + Less.FileManager.prototype.doXHR = function (url, type, callback, errback) { + url = fixURL(url); + //console.log("xhr: " + url); + return doXHR(url, type, callback, errback); + }; + + var inject = function (cssText, url) { + var curStyle = document.createElement('style'); + curStyle.setAttribute('data-original-src', url); + curStyle.type = 'text/css'; + curStyle.appendChild(document.createTextNode(cssText)); + if (!document.head) { throw new Error(); } + document.head.appendChild(curStyle); + }; + + var checkCache = function () { + if (localStorage['LESS_CACHE'] === key) { return; } + Object.keys(localStorage).forEach(function (k) { + if (k.indexOf('LESS_CACHE|') !== 0) { return; } + delete localStorage[k]; + }); + localStorage['LESS_CACHE'] = key; + }; + + module.exports.load = function (url /*:string*/, cb /*:()=>void*/) { + checkCache(); + if (localStorage['LESS_CACHE|' + key + '|' + url]) { + inject(localStorage['LESS_CACHE|' + key + '|' + url], url); + cb(); + return; + } + Less.render('@import (multiple) "' + url + '";', {}, function(err, css) { + if (err) { + console.log(err); + return; + } + localStorage['LESS_CACHE|' + key + '|' + url] = css.css; + inject(css.css, url); + cb(); + }, window.less); + }; + + return module.exports; +})/*::()*/; diff --git a/www/common/RequireLess.js b/www/common/RequireLess.js new file mode 100644 index 000000000..f681e9b1c --- /dev/null +++ b/www/common/RequireLess.js @@ -0,0 +1,12 @@ +define([ + '/common/LessLoader.js' +], function (LessLoader) { + var api = {}; + api.normalize = function(name, normalize) { + return normalize(name); + }; + api.load = function(cssId, req, load /*, config */) { + LessLoader.load(cssId, load); + }; + return api; +}); diff --git a/www/common/boot2.js b/www/common/boot2.js index 40f9639e8..da1ca2bc3 100644 --- a/www/common/boot2.js +++ b/www/common/boot2.js @@ -8,8 +8,14 @@ define([], function () { "jquery": "/bower_components/jquery/dist/jquery.min", // json.sortify same "json.sortify": "/bower_components/json.sortify/dist/JSON.sortify", - "pdfjs-dist/build/pdf": "/bower_components/pdfjs-dist/build/pdf", - "pdfjs-dist/build/pdf.worker": "/bower_components/pdfjs-dist/build/pdf.worker" + //"pdfjs-dist/build/pdf": "/bower_components/pdfjs-dist/build/pdf", + //"pdfjs-dist/build/pdf.worker": "/bower_components/pdfjs-dist/build/pdf.worker" + }, + map: { + '*': { + 'css': '/bower_components/require-css/css.js', + 'less': '/common/RequireLess.js', + } } }); diff --git a/www/common/common-metadata.js b/www/common/common-metadata.js index d5487901c..99115fac6 100644 --- a/www/common/common-metadata.js +++ b/www/common/common-metadata.js @@ -1,7 +1,7 @@ define(function () { var module = {}; - module.create = function (UserList, Title, cfg) { + module.create = function (UserList, Title, cfg, Cryptpad) { var exp = {}; exp.update = function (shjson) { @@ -15,6 +15,14 @@ define(function () { metadata = json.metadata; } if (typeof metadata === "object") { + if (Cryptpad) { + if (typeof(metadata.type) === 'undefined') { + // initialize pad type by location.pathname + metadata.type = Cryptpad.getAppType(); + } + } else { + console.log("Cryptpad should exist but it does not"); + } if (metadata.users) { var userData = metadata.users; // Update the local user data diff --git a/www/common/common-util.js b/www/common/common-util.js index 0bc53f5dd..242ae6fc8 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -139,5 +139,12 @@ define([], function () { return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); }; + Util.getAppType = function () { + var parts = window.location.pathname.split('/') + .filter(function (x) { return x; }); + if (!parts[0]) { return ''; } + return parts[0]; + }; + return Util; }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 708d2e42a..492bb06d6 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -83,6 +83,7 @@ define([ common.fetch = Util.fetch; common.throttle = Util.throttle; common.createRandomInteger = Util.createRandomInteger; + common.getAppType = Util.getAppType; // import hash utilities for export var createRandomHash = common.createRandomHash = Hash.createRandomHash; @@ -906,18 +907,12 @@ define([ common.getPinnedUsage(todo); }; - var getAppSuffix = function () { - var parts = window.location.pathname.split('/') - .filter(function (x) { return x; }); - - if (!parts[0]) { return ''; } - return '_' + parts[0].toUpperCase(); - }; - var prepareFeedback = common.prepareFeedback = function (key) { if (typeof(key) !== 'string') { return $.noop; } + + var type = common.getAppType(); return function () { - feedback(key.toUpperCase() + getAppSuffix()); + feedback((key + (type? '_' + type: '')).toUpperCase()); }; }; diff --git a/www/common/hyperscript.js b/www/common/hyperscript.js new file mode 100644 index 000000000..3be018194 --- /dev/null +++ b/www/common/hyperscript.js @@ -0,0 +1,398 @@ +define([], function () { + var Hyperscript; + +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + * Available under the MIT License + * ECMAScript compliant, uniform cross-browser split method + */ + +/** + * Splits a string into an array of strings using a regex or string separator. Matches of the + * separator are not included in the result array. However, if `separator` is a regex that contains + * capturing groups, backreferences are spliced into the result each time `separator` is matched. + * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably + * cross-browser. + * @param {String} str String to split. + * @param {RegExp|String} separator Regex or string to use for separating the string. + * @param {Number} [limit] Maximum number of items to include in the result array. + * @returns {Array} Array of substrings. + * @example + * + * // Basic use + * split('a b c d', ' '); + * // -> ['a', 'b', 'c', 'd'] + * + * // With limit + * split('a b c d', ' ', 2); + * // -> ['a', 'b'] + * + * // Backreferences in result array + * split('..word1 word2..', /([a-z]+)(\d+)/i); + * // -> ['..', 'word', '1', ' ', 'word', '2', '..'] + */ +module.exports = (function split(undef) { + + var nativeSplit = String.prototype.split, + compliantExecNpcg = /()??/.exec("")[1] === undef, + // NPCG: nonparticipating capturing group + self; + + self = function(str, separator, limit) { + // If `separator` is not a regex, use `nativeSplit` + if (Object.prototype.toString.call(separator) !== "[object RegExp]") { + return nativeSplit.call(str, separator, limit); + } + var output = [], + flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6 + (separator.sticky ? "y" : ""), + // Firefox 3+ + lastLastIndex = 0, + // Make `global` and avoid `lastIndex` issues by working with a copy + separator = new RegExp(separator.source, flags + "g"), + separator2, match, lastIndex, lastLength; + str += ""; // Type-convert + if (!compliantExecNpcg) { + // Doesn't need flags gy, but they don't hurt + separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags); + } + /* Values for `limit`, per the spec: + * If undefined: 4294967295 // Math.pow(2, 32) - 1 + * If 0, Infinity, or NaN: 0 + * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; + * If negative number: 4294967296 - Math.floor(Math.abs(limit)) + * If other: Type-convert, then use the above rules + */ + limit = limit === undef ? -1 >>> 0 : // Math.pow(2, 32) - 1 + limit >>> 0; // ToUint32(limit) + while (match = separator.exec(str)) { + // `separator.lastIndex` is not reliable cross-browser + lastIndex = match.index + match[0].length; + if (lastIndex > lastLastIndex) { + output.push(str.slice(lastLastIndex, match.index)); + // Fix browsers whose `exec` methods don't consistently return `undefined` for + // nonparticipating capturing groups + if (!compliantExecNpcg && match.length > 1) { + match[0].replace(separator2, function() { + for (var i = 1; i < arguments.length - 2; i++) { + if (arguments[i] === undef) { + match[i] = undef; + } + } + }); + } + if (match.length > 1 && match.index < str.length) { + Array.prototype.push.apply(output, match.slice(1)); + } + lastLength = match[0].length; + lastLastIndex = lastIndex; + if (output.length >= limit) { + break; + } + } + if (separator.lastIndex === match.index) { + separator.lastIndex++; // Avoid an infinite loop + } + } + if (lastLastIndex === str.length) { + if (lastLength || !separator.test("")) { + output.push(""); + } + } else { + output.push(str.slice(lastLastIndex)); + } + return output.length > limit ? output.slice(0, limit) : output; + }; + + return self; +})(); + +},{}],3:[function(require,module,exports){ +// contains, add, remove, toggle +var indexof = require('indexof') + +module.exports = ClassList + +function ClassList(elem) { + var cl = elem.classList + + if (cl) { + return cl + } + + var classList = { + add: add + , remove: remove + , contains: contains + , toggle: toggle + , toString: $toString + , length: 0 + , item: item + } + + return classList + + function add(token) { + var list = getTokens() + if (indexof(list, token) > -1) { + return + } + list.push(token) + setTokens(list) + } + + function remove(token) { + var list = getTokens() + , index = indexof(list, token) + + if (index === -1) { + return + } + + list.splice(index, 1) + setTokens(list) + } + + function contains(token) { + return indexof(getTokens(), token) > -1 + } + + function toggle(token) { + if (contains(token)) { + remove(token) + return false + } else { + add(token) + return true + } + } + + function $toString() { + return elem.className + } + + function item(index) { + var tokens = getTokens() + return tokens[index] || null + } + + function getTokens() { + var className = elem.className + + return filter(className.split(" "), isTruthy) + } + + function setTokens(list) { + var length = list.length + + elem.className = list.join(" ") + classList.length = length + + for (var i = 0; i < list.length; i++) { + classList[i] = list[i] + } + + delete list[length] + } +} + +function filter (arr, fn) { + var ret = [] + for (var i = 0; i < arr.length; i++) { + if (fn(arr[i])) ret.push(arr[i]) + } + return ret +} + +function isTruthy(value) { + return !!value +} + +},{"indexof":4}],4:[function(require,module,exports){ + +var indexOf = [].indexOf; + +module.exports = function(arr, obj){ + if (indexOf) return arr.indexOf(obj); + for (var i = 0; i < arr.length; ++i) { + if (arr[i] === obj) return i; + } + return -1; +}; +},{}],5:[function(require,module,exports){ +var h = require("./index.js"); + +module.exports = h; + +/* +$(function () { + + var newDoc = h('p', + + h('ul', 'bang bang bang'.split(/\s/).map(function (word) { + return h('li', word); + })) + ); + $('body').html(newDoc.outerHTML); +}); + +*/ + +},{"./index.js":1}],6:[function(require,module,exports){ + +},{}]},{},[5]); + + return Hyperscript; +}); diff --git a/www/login/index.html b/www/login/index.html index 3e4e7a21e..5593e41b9 100644 --- a/www/login/index.html +++ b/www/login/index.html @@ -1,76 +1,16 @@ + - Cryptpad: Log in + Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - + -
- - - CryptPad - - - - - - - About - - - Privacy - - - ToS - - - Contact - -
- - - - diff --git a/www/pad/main.js b/www/pad/main.js index 099e3217f..a762221a3 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -307,7 +307,8 @@ define([ hjson[3] = { metadata: { users: UserList.userData, - defaultTitle: Title.defaultTitle + defaultTitle: Title.defaultTitle, + type: 'pad' } }; if (!initializing) { @@ -451,7 +452,7 @@ define([ var titleCfg = { getHeadingText: getHeadingText }; Title = Cryptpad.createTitle(titleCfg, realtimeOptions.onLocal, Cryptpad); - Metadata = Cryptpad.createMetadata(UserList, Title); + Metadata = Cryptpad.createMetadata(UserList, Title, null, Cryptpad); var configTb = { displayed: ['title', 'useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad', 'limit', 'upgrade'], diff --git a/www/poll/main.js b/www/poll/main.js index adfe60ec3..0948ec8b4 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -430,6 +430,7 @@ define([ }); proxy.version = 1; + proxy.type = 'poll'; }; /* @@ -475,6 +476,16 @@ var ready = function (info, userid, readOnly) { var userDoc = JSON.stringify(proxy); if (userDoc === "" || userDoc === "{}") { isNew = true; } + if (!isNew && typeof(proxy.type) !== 'undefined' && proxy.type !== 'poll') { + var errorText = Messages.typeError; + Cryptpad.errorLoadingScreen(errorText); + throw new Error(errorText); + } + + if (typeof(proxy.type) === 'undefined') { + proxy.type = 'poll'; + } + var uncommitted = APP.uncommitted = {}; prepareProxy(proxy, copyObject(Render.Example)); prepareProxy(uncommitted, copyObject(Render.Example)); diff --git a/www/register/index.html b/www/register/index.html index dd9765423..5593e41b9 100644 --- a/www/register/index.html +++ b/www/register/index.html @@ -1,83 +1,16 @@ + + Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - Cryptpad: login - - - - + + + -
- - - CryptPad - - - - - - - About - - - Privacy - - - ToS - - - Contact - -
- - - - diff --git a/www/settings/index.html b/www/settings/index.html index d628be352..5593e41b9 100644 --- a/www/settings/index.html +++ b/www/settings/index.html @@ -5,111 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - - - + -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
- - - - - - - - - +

OOPS In order to do encryption in your browser, Javascript is really really required.

+

OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.

+ diff --git a/www/settings/main.js b/www/settings/main.js index c7379db3a..992024937 100644 --- a/www/settings/main.js +++ b/www/settings/main.js @@ -5,6 +5,11 @@ define([ '/common/mergeDrive.js', '/bower_components/file-saver/FileSaver.min.js', '/customize/header.js', + + 'css!/customize/main.css', + 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', + 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', + 'css!/settings/main.css', ], function ($, Cryptpad, Crypt, Merge) { var saveAs = window.saveAs; diff --git a/www/slide/main.js b/www/slide/main.js index fcbcd109e..c0d265800 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -344,7 +344,7 @@ define([ }; Title = Cryptpad.createTitle(titleCfg, config.onLocal, Cryptpad); - Metadata = Cryptpad.createMetadata(UserList, Title, metadataCfg); + Metadata = Cryptpad.createMetadata(UserList, Title, metadataCfg, Cryptpad); var configTb = { displayed: ['title', 'useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad', 'limit', 'upgrade'], @@ -559,7 +559,8 @@ define([ var hjson = JSON.parse(userDoc); newDoc = hjson.content; - if (typeof (hjson) !== 'object' || Array.isArray(hjson)) { + if (typeof (hjson) !== 'object' || Array.isArray(hjson) || + (typeof(hjson.type) !== 'undefined' && hjson.type !== 'slide')) { var errorText = Messages.typeError; Cryptpad.errorLoadingScreen(errorText); throw new Error(errorText); diff --git a/www/user/index.html b/www/user/index.html index d628be352..5593e41b9 100644 --- a/www/user/index.html +++ b/www/user/index.html @@ -5,111 +5,12 @@ Cryptpad: Zero Knowledge, Collaborative Real Time Editing - - - - - - + -
- - - CryptPad - - - - - - - - - About - - - Privacy - - - ToS - - - Contact - - - Blog - - - - -
- - - - - - - - - +

OOPS In order to do encryption in your browser, Javascript is really really required.

+

OUPS Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est vraiment nécessaire.

+ diff --git a/www/user/main.js b/www/user/main.js index 82f16682b..9c8e98e16 100644 --- a/www/user/main.js +++ b/www/user/main.js @@ -1,6 +1,7 @@ define([ 'jquery', '/common/cryptpad-common.js', + 'css!/user/main.css', ], function ($, Cryptpad) { var APP = window.APP = { diff --git a/www/whiteboard/main.js b/www/whiteboard/main.js index 1949549af..c399d5c3f 100644 --- a/www/whiteboard/main.js +++ b/www/whiteboard/main.js @@ -293,7 +293,7 @@ window.canvas = canvas; Title = Cryptpad.createTitle({}, config.onLocal, Cryptpad); - Metadata = Cryptpad.createMetadata(UserList, Title, metadataCfg); + Metadata = Cryptpad.createMetadata(UserList, Title, metadataCfg, Cryptpad); var configTb = { displayed: ['title', 'useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad', 'limit', 'upgrade'], @@ -384,7 +384,8 @@ window.canvas = canvas; metadata: { users: UserList.userData, palette: palette, - defaultTitle: Title.defaultTitle + defaultTitle: Title.defaultTitle, + type: 'whiteboard', } }; if (!initializing) { @@ -413,6 +414,14 @@ window.canvas = canvas; var isNew = false; var userDoc = module.realtime.getUserDoc(); if (userDoc === "" || userDoc === "{}") { isNew = true; } + else { + var hjson = JSON.parse(userDoc); + if (typeof(hjson) !== 'object' || Array.isArray(hjson) || + (typeof(hjson.type) !== 'undefined' && hjson.type !== whiteboard)) { + Cryptpad.errorLoadingScreen(Messages.typeError); + throw new Error(Messages.typeError); + } + } Cryptpad.removeLoadingScreen(); setEditable(true);