diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 138cc5590..689843f50 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -532,7 +532,7 @@ MessengerUI, Messages) { Common.getSframeChannel().event('EV_SHARE_OPEN', { hidden: true }); - $shareBlock.click(function () { + $shareBlock.click(function () { var title = (config.title && config.title.getTitle && config.title.getTitle()) || (config.title && config.title.defaultName) || ""; diff --git a/www/pad/app-pad.less b/www/pad/app-pad.less index f31b87ad5..48ee72854 100644 --- a/www/pad/app-pad.less +++ b/www/pad/app-pad.less @@ -24,14 +24,68 @@ body.cp-app-pad { overflow: hidden; } + #cp-app-pad-toc, #cp-app-pad-comments, #cp-app-pad-resize { + .cp-pad-show, .cp-pad-hide { + position: absolute; + cursor: pointer; + height: 28px; + line-height: 28px; + .fa { margin: 0 !important; } + } + &.hidden { + width: auto !important; + .cp-pad-show { + position: relative; + } + & > :not(.cp-pad-show) { + display: none; + } + } + &:not(.hidden) { + .cp-pad-show { display: none; } + } + } + #cp-app-pad-toc { + .cp-pad-show { + line-height: 25px; + } + } + #cp-app-pad-comments { + &.hidden { + .cp-pad-show.notif { + color: red; + } + } + .cp-pad-show { + line-height: 0px; + } + } + #cp-app-pad-resize { + order: 2; + height: 28px; + width: 36px; + margin-left: -40px; + margin-top: 10px; + margin-right: 0; + &.hidden { + margin-left: -70px; + margin-right: 40px; + } + } #cp-app-pad-toc { @toc-level-indent: 15px; overflow-y: auto; margin-top: 10px; margin-left: 10px; + margin-right: 10px; width: 200px; color: @cp_pad-fg; + //color: @cryptpad_text_col; + position: relative; + .cp-pad-show, .cp-pad-hide { + right: 0; + } h2 { font-size: 1.5rem; } @@ -135,7 +189,16 @@ body.cp-app-pad { #cp-app-pad-comments { order: 3; width: 330px; - margin: 0px 20px; + //background-color: white; + margin: 10px; + position: relative; + .cp-pad-show, .cp-pad-hide { + left: 0; + } + h2 { + font-size: 1.5rem; + text-align: right; + } .comments_main(); } &.cke_body_width { @@ -175,6 +238,20 @@ body.cp-app-pad { min-width: 60%; } + .cp-pad-settings-dialog { + .cp-pad-settings-radio-container { + display: flex; + align-items: center; + .cp-radio, &>button { + margin-right: 20px; + } + margin-bottom: 20px; + } + .cp-app-prop-content { + margin-bottom: 0; + } + } + @media print { #cke_1_top { display:none !important; diff --git a/www/pad/comments.js b/www/pad/comments.js index 60466649c..6af3743d0 100644 --- a/www/pad/comments.js +++ b/www/pad/comments.js @@ -298,6 +298,31 @@ define([ // Remove everything Env.$container.html(''); + var hideBtn = h('button.cp-pad-hide.btn.btn-default.fa.fa-chevron-right'); + var showBtn = h('button.cp-pad-show.btn.btn-default', { + title: Messages.poll_comment_list + }, [ + h('i.fa.fa-comment') + ]); + + + var store = window.cryptpadStore; + var key = 'hide-pad-comments'; + $(hideBtn).click(function () { + Env.$container.addClass('hidden'); + Env.localHide = true; + if (store) { store.put(key, '1'); } + }); + var $showBtn = $(showBtn).click(function () { + Env.$container.removeClass('hidden'); + Env.localHide = false; + if (store) { store.put(key, '0'); } + }); + Env.$container.append([ + showBtn, + hideBtn, + h('h2', Messages.poll_comment_list) + ]); // "show" tells us if we need to display the "comments" column or not var show = false; @@ -595,11 +620,32 @@ define([ }); } - if (show) { - Env.$container.show(); + + // Hidden or visible? check pad settings first, then browser otherwise hide + var md = Util.clone(Env.metadataMgr.getMetadata()); + var hide = false; + if (typeof(md.defaultComments) === "undefined") { + if (typeof(store.store[key]) === 'undefined') { + hide = !show; // Hide if there are no comments + } else { + hide = store.store[key] === '1'; + } } else { - Env.$container.hide(); + hide = md.defaultComments === 0; + } + // If we've clicked on the show/hide buttons, always use our latest local value + if (typeof(Env.localHide) === "boolean") { hide = Env.localHide; } + + Env.$container.removeClass('hidden'); + if (hide) { Env.$container.addClass('hidden'); } + + $showBtn.removeClass('notif'); + if (show) { + $showBtn.addClass('notif'); } + + + Env.$container.show(); }; var onChange = function(Env) { @@ -762,6 +808,8 @@ define([ // Remove active class on other comments Env.$container.find('.cp-comment-active').removeClass('cp-comment-active'); Env.$container.find('.cp-comment-form').remove(); + Env.$container.removeClass('hidden'); + Env.localHide = false; var form = getCommentForm(Env, false, function(val) { $(form).remove(); Env.$inner.focus(); @@ -798,7 +846,9 @@ define([ Env.oldComments = undefined; }); - Env.$container.prepend(form).show(); + + Env.$container.show(); + Env.$container.find('> h2').after(form); }; @@ -827,6 +877,8 @@ define([ var ready = function(Env) { Env.ready = 0; + onChange(Env); + // If you're the only edit user online, clear "deleted" comments if (!Env.common.isLoggedIn()) { return; } var users = Env.metadataMgr.getMetadata().users || {}; diff --git a/www/pad/inner.js b/www/pad/inner.js index 977e4e7a8..af3ef88fb 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -203,6 +203,156 @@ define([ check(); }; + var mkSettingsMenu = function(framework) { + + // XXX + Messages.pad_settings_title = "Document Settings"; + Messages.pad_settings_info = "Default settings for this document. These will be applied when new users visit this document."; + Messages.pad_settings_width_small = "Page mode"; + Messages.pad_settings_width_large = "Full width"; + Messages.pad_settings_outline = "Choose whether the Table of Contents should be visible or hidden by default."; + Messages.pad_settings_comments = "Choose whether the Comments should be visible or hidden by default."; + Messages.pad_settings_hide = "Hide"; + Messages.pad_settings_show = "Show"; + var getSettings = function () { + var $d = $(h('div.cp-pad-settings-dialog')); + var common = framework._.sfCommon; + var metadataMgr = common.getMetadataMgr(); + var md = Util.clone(metadataMgr.getMetadata()); + + var set = function (key, val, spinner) { + var md = Util.clone(metadataMgr.getMetadata()); + if (typeof(val) === "undefined") { delete md[key]; } + else { md[key] = val; } + metadataMgr.updateMetadata(md); + framework.localChange(); + framework._.cpNfInner.whenRealtimeSyncs(spinner.done); + }; + + // Pad width + var opt1 = UI.createRadio('cp-pad-settings-width', 'cp-pad-settings-width-small', + Messages.pad_settings_width_small, md.defaultWidth === 0, { + input: { value: 0 }, + label: { class: 'noTitle' } + }); + var opt2 = UI.createRadio('cp-pad-settings-width', 'cp-pad-settings-width-large', + Messages.pad_settings_width_large, md.defaultWidth === 1, { + input: { value: 1 }, + label: { class: 'noTitle' } + }); + var delWidth = h('button.btn.btn-default.fa.fa-times'); + var width = h('div.cp-pad-settings-radio-container', [ + opt1, + opt2, + delWidth + ]); + var $width = $(width); + var spinner = UI.makeSpinner($width); + + $(delWidth).click(function () { + spinner.spin(); + $width.find('input[type="radio"]').prop('checked', false); + set('defaultWidth', undefined, spinner); + }); + $width.find('input[type="radio"]').on('change', function() { + spinner.spin(); + var val = $('input:radio[name="cp-pad-settings-width"]:checked').val(); + val = Number(val) || 0; + set('defaultWidth', val, spinner); + }); + + // Outline + var opt3 = UI.createRadio('cp-pad-settings-outline', 'cp-pad-settings-outline-false', + Messages.pad_settings_hide, md.defaultOutline === 0, { + input: { value: 0 }, + label: { class: 'noTitle' } + }); + var opt4 = UI.createRadio('cp-pad-settings-outline', 'cp-pad-settings-outline-true', + Messages.pad_settings_show, md.defaultOutline === 1, { + input: { value: 1 }, + label: { class: 'noTitle' } + }); + var delOutline = h('button.btn.btn-default.fa.fa-times'); + var outline = h('div.cp-pad-settings-radio-container', [ + opt3, + opt4, + delOutline + ]); + var $outline = $(outline); + var spinner2 = UI.makeSpinner($outline); + + $(delOutline).click(function () { + spinner2.spin(); + $outline.find('input[type="radio"]').prop('checked', false); + set('defaultOutline', undefined, spinner2); + }); + $outline.find('input[type="radio"]').on('change', function() { + spinner2.spin(); + var val = $('input:radio[name="cp-pad-settings-outline"]:checked').val(); + val = Number(val) || 0; + set('defaultOutline', val, spinner2); + }); + + // Comments + var opt5 = UI.createRadio('cp-pad-settings-comments', 'cp-pad-settings-comments-false', + Messages.pad_settings_hide, md.defaultComments === 0, { + input: { value: 0 }, + label: { class: 'noTitle' } + }); + var opt6 = UI.createRadio('cp-pad-settings-comments', 'cp-pad-settings-comments-true', + Messages.pad_settings_show, md.defaultComments === 1, { + input: { value: 1 }, + label: { class: 'noTitle' } + }); + var delComments = h('button.btn.btn-default.fa.fa-times'); + var comments = h('div.cp-pad-settings-radio-container', [ + opt5, + opt6, + delComments + ]); + var $comments = $(comments); + var spinner3 = UI.makeSpinner($comments); + + $(delComments).click(function () { + spinner3.spin(); + $comments.find('input[type="radio"]').prop('checked', false); + set('defaultComments', undefined, spinner3); + }); + $comments.find('input[type="radio"]').on('change', function() { + spinner3.spin(); + var val = $('input:radio[name="cp-pad-settings-comments"]:checked').val(); + val = Number(val) || 0; + set('defaultComments', val, spinner3); + }); + + $d.append([ + h('h5', Messages.pad_settings_title), + h('p.cp-app-prop-content', h('p', Messages.pad_settings_info)), + h('label', Messages.settings_padWidth), + h('p.cp-app-prop-content', Messages.settings_padWidthHint), + $width[0], + h('label', Messages.markdown_toc), + h('p.cp-app-prop-content', Messages.pad_settings_outline), + $outline[0], + h('label', Messages.poll_comment_list), + h('p.cp-app-prop-content', Messages.pad_settings_comments), + $comments[0], + ]); + + return $d[0]; + }; + + var $settingsButton = framework._.sfCommon.createButton('', true, { + drawer: true, + text: Messages.pad_settings_title, + name: 'pad_settings', + icon: 'fa-cog', + }, function () { + UI.alert(getSettings()); + }); + framework._.toolbar.$drawer.append($settingsButton); + }; + var mkHelpMenu = function(framework) { var $toolbarContainer = $('.cke_toolbox_main'); var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'pad']); @@ -424,41 +574,6 @@ define([ }); }; - var addTOCHideBtn = function(framework, $toc) { - // Expand / collapse the toolbar - var onClick = function(visible) { - framework._.sfCommon.setAttribute(['pad', 'showTOC'], visible); - }; - framework._.sfCommon.getAttribute(['pad', 'showTOC'], function(err, data) { - var state = false; - if (($(window).height() >= 800 || $(window).width() >= 800) && - (typeof(data) === "undefined" || data)) { - state = true; - $toc.show(); - } else { - $toc.hide(); - } - var $tocButton = framework._.sfCommon.createButton('', true, { - drawer: false, - text: Messages.pad_tocHide, - name: 'pad_toc', - icon: 'fa-list-ul', - }, function () { - $tocButton.removeClass('cp-toolbar-button-active'); - $toc.toggle(); - state = $toc.is(':visible'); - if (state) { - $tocButton.addClass('cp-toolbar-button-active'); - } - onClick(state); - }); - framework._.toolbar.$bottomL.append($tocButton); - if (state) { - $tocButton.addClass('cp-toolbar-button-active'); - } - }); - }; - var displayMediaTags = function(framework, dom, mediaTagMap) { setTimeout(function() { // Just in case var tags = dom.querySelectorAll('media-tag:empty'); @@ -585,8 +700,9 @@ define([ $container: $('#cp-app-pad-comments') }); + var $resize = $('#cp-app-pad-resize'); var $toc = $('#cp-app-pad-toc'); - addTOCHideBtn(framework, $toc); + $toc.show(); // My cursor var cursor = module.cursor = Cursor(inner); @@ -606,6 +722,7 @@ define([ if (!privateData.isEmbed) { mkHelpMenu(framework); } + mkSettingsMenu(framework); framework._.sfCommon.getAttribute(['pad', 'width'], function(err, data) { var active = data || typeof(data) === "undefined"; @@ -666,7 +783,61 @@ define([ Util.stripTags($(el).text()); }; + var updatePageMode = function () { + var md = Util.clone(metadataMgr.getMetadata()); + var store = window.cryptpadStore; + var key = 'pad-small-width'; + + var hideBtn = h('button.btn.btn-default.cp-pad-hide.fa.fa-compress'); + var showBtn = h('button.btn.btn-default.cp-pad-show.fa.fa-expand'); + + var localHide; + $(hideBtn).click(function () { // Expand + $contentContainer.addClass('cke_body_width'); + $resize.addClass('hidden'); + localHide = true; + if (store) { store.put(key, '1'); } + }); + $(showBtn).click(function () { + $contentContainer.removeClass('cke_body_width'); + $resize.removeClass('hidden'); + localHide = false; + if (store) { store.put(key, '0'); } + }); + + var content = [ + hideBtn, + showBtn, + ]; + $resize.html('').append(content); + + // Hidden or visible? check pad settings first, then browser otherwise hide + var hide = false; + if (typeof(md.defaultWidth) === "undefined") { + if (typeof(store.store[key]) === 'undefined') { + hide = true; + } else { + hide = store.store[key] === '1'; + } + } else { + hide = md.defaultWidth === 0; + } + + // If we've clicking on the show/hide buttons, always use our last value + if (typeof(localHide) === "boolean") { hide = localHide; } + + $contentContainer.removeClass('cke_body_width'); + $resize.removeClass('hidden'); + if (hide) { + $resize.addClass('hidden'); + $contentContainer.addClass('cke_body_width'); + } + + }; + updatePageMode(); var updateTOC = Util.throttle(function () { + var md = Util.clone(metadataMgr.getMetadata()); + var toc = []; $inner.find('h1, h2, h3, a[id][data-cke-saved-name]').each(function (i, el) { if (isAnchor(el)) { @@ -683,7 +854,48 @@ define([ title: Util.stripTags($(el).text()) }); }); - var content = [h('h2', Messages.markdown_toc)]; + var hideBtn = h('button.btn.btn-default.cp-pad-hide.fa.fa-chevron-left'); + var showBtn = h('button.btn.btn-default.cp-pad-show', { + title: Messages.pad_tocHide + }, [ + h('i.fa.fa-list-ul') + ]); + var content = [ + hideBtn, + showBtn, + h('h2', Messages.markdown_toc) + ]; + var store = window.cryptpadStore; + var key = 'hide-pad-toc'; + + // Hidden or visible? check pad settings first, then browser otherwise hide + var hide = false; + var localHide; + if (typeof(md.defaultOutline) === "undefined") { + if (typeof(store.store[key]) === 'undefined') { + hide = true; + } else { + hide = store.store[key] === '1'; + } + } else { + hide = md.defaultOutline === 0; + } + // If we've clicking on the show/hide buttons, always use our last value + if (typeof(localHide) === "boolean") { hide = localHide; } + + $toc.removeClass('hidden'); + if (hide) { $toc.addClass('hidden'); } + + $(hideBtn).click(function () { + $toc.addClass('hidden'); + localHide = true; + if (store) { store.put(key, '1'); } + }); + $(showBtn).click(function () { + $toc.removeClass('hidden'); + localHide = false; + if (store) { store.put(key, '0'); } + }); toc.forEach(function (obj) { var title = (obj.title || "").trim(); if (!title) { return; } @@ -910,6 +1122,8 @@ define([ } }); + updateTOC(); + updatePageMode(); comments.ready(); /*setTimeout(function () { @@ -1148,29 +1362,6 @@ define([ customConfig: '/customize/ckeditor-config.js', }); - editor.addCommand('pagemode', { - exec: function() { - if (!framework) { return; } - var $contentContainer = $('#cke_1_contents'); - var $button = $('.cke_button__pagemode'); - var isLarge = $button.hasClass('cke_button_on'); - if (isLarge) { - $button.addClass('cke_button_off').removeClass('cke_button_on'); - $contentContainer.addClass('cke_body_width'); - } else { - $button.addClass('cke_button_on').removeClass('cke_button_off'); - $contentContainer.removeClass('cke_body_width'); - } - framework._.sfCommon.setAttribute(['pad', 'width'], isLarge); - } - }); - editor.ui.addButton('PageMode', { - label: Messages.pad_useFullWidth, - command: 'pagemode', - icon: '/pad/icons/arrows-h.png', - toolbar: 'document,60' - }); - editor.on('instanceReady', waitFor()); }).nThen(function() { var _getPath = Ckeditor.plugins.getPath; @@ -1213,6 +1404,7 @@ define([ var $mainContainer = $('#cke_editor1 > .cke_inner'); var $ckeToolbar = $('#cke_1_top').find('.cke_toolbox_main'); $mainContainer.prepend($ckeToolbar.addClass('cke_reset_all')); + $contentContainer.append(h('div#cp-app-pad-resize')); $contentContainer.append(h('div#cp-app-pad-comments')); $contentContainer.prepend(h('div#cp-app-pad-toc')); $ckeToolbar.find('.cke_button__image_icon').parent().hide(); diff --git a/www/settings/inner.js b/www/settings/inner.js index 0aa0810d3..2fa0be234 100644 --- a/www/settings/inner.js +++ b/www/settings/inner.js @@ -1241,14 +1241,18 @@ define([ var $ok = $('', { 'class': 'fa fa-check', title: Messages.saved }); var $spinner = $('', { 'class': 'fa fa-spinner fa-pulse' }); + var store = window.cryptpadStore; + var key = 'pad-small-width'; + var isHidden = store.store[key] === '1'; + var $cbox = $(UI.createCheckbox('cp-settings-padwidth', Messages.settings_padWidthLabel, - false, { label: { class: 'noTitle' } })); + isHidden, { label: { class: 'noTitle' } })); var $checkbox = $cbox.find('input').on('change', function() { $spinner.show(); $ok.hide(); var val = $checkbox.is(':checked'); - common.setAttribute(['pad', 'width'], val, function() { + store.put(key, val ? '1' : '0', function () { $spinner.hide(); $ok.show(); }); @@ -1258,13 +1262,6 @@ define([ $ok.hide().appendTo($cbox); $spinner.hide().appendTo($cbox); - - common.getAttribute(['pad', 'width'], function(e, val) { - if (e) { return void console.error(e); } - if (val) { - $checkbox.attr('checked', 'checked'); - } - }); return $div; };