From 5761e998de575f6eac6d332c4def443a5aae977a Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 11:03:45 +0000 Subject: [PATCH 01/45] first semi working alt f9 functionality --- src/node/utils/toolbar.js | 2 +- src/static/css/pad.css | 13 ++++++++----- src/static/js/ace2_inner.js | 14 ++++++++++++++ src/static/js/pad_editbar.js | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/node/utils/toolbar.js b/src/node/utils/toolbar.js index a5d30f96..65c2c1d5 100644 --- a/src/node/utils/toolbar.js +++ b/src/node/utils/toolbar.js @@ -99,7 +99,7 @@ _.extend(Button.prototype, { }; return tag("li", liAttributes, tag("a", { "class": this.grouping, "data-l10n-id": this.attributes.localizationId }, - tag("span", { "class": " "+ this.attributes.class }) + tag("button", { "class": " "+ this.attributes.class }) ) ); } diff --git a/src/static/css/pad.css b/src/static/css/pad.css index c9ebff4a..7a91c0b5 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -70,10 +70,6 @@ a img { .toolbar ul li { float: left; margin-left: 2px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; height:32px; } .toolbar ul li.separator { @@ -197,6 +193,7 @@ li[data-key=showusers] > a #online_count { #editbar{ display:none; } + #editorcontainer { position: absolute; top: 37px; /* + 1px border */ @@ -742,13 +739,19 @@ table#otheruserstable { height: 16px; display: inline-block; vertical-align: middle; - + border: none; + padding: 0; + background: none; font-family: "fontawesome-etherpad"; font-size: 15px; font-style: normal; font-weight: normal; color: #666; } + +.buttonicon:focus{ + border: 1px solid #fff; +} .buttonicon-bold:before { content: "\e81c"; } diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index be54b0c0..8e4dab5c 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3707,6 +3707,19 @@ function Ace2Inner(){ evt:evt }); specialHandled = (specialHandledInHook&&specialHandledInHook.length>0)?specialHandledInHook[0]:specialHandled; + if ((!specialHandled) && isTypeForSpecialKey && keyCode == 120){ + // Alt F9 focuses on the File Menu and/or editbar. + // Note that while most editors use Alt F10 this is not desirable + // As ubuntu cannot use Alt F10.... + evt.preventDefault(); + // Focus on the editbar. + top.console.log("focusing on first child in menu"); + var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first(); + firstEditbarElement.focus(); + top.console.log(firstEditbarElement); + top.console.log(parent.parent.$(':focus')); + $(this).blur(); + } if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8) { // "delete" key; in mozilla, if we're at the beginning of a line, normalize now, @@ -4951,6 +4964,7 @@ function Ace2Inner(){ // a fix: in IE, clicking on a control like a button outside the // iframe can "blur" the editor, causing it to stop getting // events, though typing still affects it(!). + top.console.log("blur handled"); setSelection(null); } } diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 7d0539af..b2d5ada5 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -155,6 +155,10 @@ var padeditbar = (function() }); }); + $('#editbar').on("keyup", function(evt){ + editbarKeyEvent(evt); + }); + $('#editbar').show(); this.redrawHeight(); @@ -300,6 +304,36 @@ var padeditbar = (function() } }; + function editbarKeyEvent(evt){ + // On arrow keys go to next/previous button item in editbar + if(evt.keyCode !== 39 && evt.keyCode !== 37) return; + + // Get our current Focus (Which editbar icon we're currently on) + var currentFocus = $(':focus'); + + // On left arrow move to next button in editbar + if(evt.keyCode === 37){ + var nextFocus = $(currentFocus).parent().parent().prev(); + // No button in this focus so move on + if(nextFocus.find("button").length === 0){ + $(nextFocus).prev().find("button").focus(); + }else{ + $(currentFocus).parent().parent().prev().find("button").focus(); + } + } + + // On right arrow move to next button in editbar + if(evt.keyCode === 39){ + var nextFocus = $(currentFocus).parent().parent().next(); + // No button in this focus so move on + if(nextFocus.find("button").length === 0){ + $(nextFocus).next().find("button").focus(); + }else{ + $(currentFocus).parent().parent().next().find("button").focus(); + } + } + } + function aceAttributeCommand(cmd, ace) { ace.ace_toggleAttributeOnSelection(cmd); } From b72127c3277a2992a5b7db5aa7858f4a4dd6cba8 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 12:24:20 +0000 Subject: [PATCH 02/45] different font families for people with dyslexia --- src/locales/en.json | 16 ++++++++ src/static/js/pad.js | 16 ++++++-- src/static/js/pad_editor.js | 76 ++++++++++++++++++++++++++++++------- src/templates/pad.html | 15 ++++++++ 4 files changed, 106 insertions(+), 17 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index 23bb3a04..b5713660 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -39,6 +39,22 @@ "pad.settings.fontType": "Font type:", "pad.settings.fontType.normal": "Normal", "pad.settings.fontType.monospaced": "Monospace", + "pad.settings.fontType.comicsans": "Comic Sans", + "pad.settings.fontType.couriernew": "Courier New", + "pad.settings.fontType.georgia": "Georgia", + "pad.settings.fontType.impact": "Impact", + "pad.settings.fontType.lucida": "Lucida", + "pad.settings.fontType.lucidasans": "Lucida Sans", + "pad.settings.fontType.palatino": "Palatino", + "pad.settings.fontType.tahoma": "Tahoma", + "pad.settings.fontType.timesnewroman": "Times New Roman", + "pad.settings.fontType.trebuchet": "Trebuchet", + "pad.settings.fontType.verdana": "Verdana", + "pad.settings.fontType.symbol": "Symbol", + "pad.settings.fontType.webdings": "Webdings", + "pad.settings.fontType.wingdings": "Wingdings", + "pad.settings.fontType.sansserif": "Sans Serif", + "pad.settings.fontType.serif": "Serif", "pad.settings.globalView": "Global View", "pad.settings.language": "Language:", diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 77bfab7f..0e54168b 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -576,9 +576,18 @@ var pad = { if(padcookie.getPref("rtlIsTrue") == true){ pad.changeViewOption('rtlIsTrue', true); } - if(padcookie.getPref("useMonospaceFont") == true){ - pad.changeViewOption('useMonospaceFont', true); - } + + var fonts = ['useMonospaceFont', 'useComicSansFont', 'useCourierNewFont', 'useGeorgiaFont', 'useImpactFont', + 'useLucidaFont', 'useLucidaSansFont', 'usePalatinoFont', 'useTahomaFont', 'useTimesNewRomanFont', + 'useTrebuchetFont', 'useVerdanaFont', 'useSymbolFont', 'useWebdingsFont', 'useWingDingsFont', 'useSansSerifFont', + 'useSerifFont']; + + $.each(fonts, function(i, font){ + if(padcookie.getPref(font) == true){ + pad.changeViewOption(font, true); + } + }) + hooks.aCallAll("postAceInit", {ace: padeditor.ace, pad: pad}); } }, @@ -629,6 +638,7 @@ var pad = { for (var k in opts.view) { pad.padOptions.view[k] = opts.view[k]; +console.log("setpref", k, opts.view[k]); padcookie.setPref(k, opts.view[k]); } padeditor.setViewOptions(pad.padOptions.view); diff --git a/src/static/js/pad_editor.js b/src/static/js/pad_editor.js index b73409ff..51b9355e 100644 --- a/src/static/js/pad_editor.js +++ b/src/static/js/pad_editor.js @@ -28,6 +28,13 @@ var padeditor = (function() var Ace2Editor = undefined; var pad = undefined; var settings = undefined; + + // Array of available fonts + var fonts = ['useMonospaceFont', 'useComicSansFont', 'useCourierNewFont', 'useGeorgiaFont', 'useImpactFont', + 'useLucidaFont', 'useLucidaSansFont', 'usePalatinoFont', 'useTahomaFont', 'useTimesNewRomanFont', + 'useTrebuchetFont', 'useVerdanaFont', 'useSymbolFont', 'useWebdingsFont', 'useWingDingsFont', 'useSansSerifFont', + 'useSerifFont']; + var self = { ace: null, // this is accessed directly from other files @@ -85,10 +92,15 @@ var padeditor = (function() padutils.setCheckbox($("#options-rtlcheck"), ('rtl' == html10n.getDirection())); }) - // font face + // font family change $("#viewfontmenu").change(function() { - pad.changeViewOption('useMonospaceFont', $("#viewfontmenu").val() == 'monospace'); + $.each(fonts, function(i, font){ + var sfont = font.replace("use",""); + sfont = sfont.replace("Font",""); + sfont = sfont.toLowerCase(); + pad.changeViewOption(font, $("#viewfontmenu").val() == sfont); + }); }); // Language @@ -98,12 +110,12 @@ var padeditor = (function() // this does not interfere with html10n's normal value-setting because html10n just ingores s // also, a value which has been set by the user will be not overwritten since a user-edited // does *not* have the editempty-class - $('input[data-l10n-id]').each(function(key, input) - { - input = $(input); - if(input.hasClass("editempty")) - input.val(html10n.get(input.attr("data-l10n-id"))); - }); + $('input[data-l10n-id]').each(function(key, input){ + input = $(input); + if(input.hasClass("editempty")){ + input.val(html10n.get(input.attr("data-l10n-id"))); + } + }); }) $("#languagemenu").val(html10n.getLanguage()); $("#languagemenu").change(function() { @@ -136,13 +148,49 @@ var padeditor = (function() v = getOption('showAuthorColors', true); self.ace.setProperty("showsauthorcolors", v); padutils.setCheckbox($("#options-colorscheck"), v); - // Override from parameters if true - if (settings.noColors !== false) - self.ace.setProperty("showsauthorcolors", !settings.noColors); - v = getOption('useMonospaceFont', false); - self.ace.setProperty("textface", (v ? "monospace" : "Arial, sans-serif")); - $("#viewfontmenu").val(v ? "monospace" : "normal"); + // Override from parameters if true + if (settings.noColors !== false){ + self.ace.setProperty("showsauthorcolors", !settings.noColors); + } + + var normalFont = true; + // Go through each font and see if the option is set.. + $.each(fonts, function(i, font){ + var isEnabled = getOption(font, false); + if(isEnabled){ + font = font.replace("use",""); + font = font.replace("Font",""); + font = font.toLowerCase(); + if(font === "monospace") self.ace.setProperty("textface", "Courier new"); + if(font === "comicsans") self.ace.setProperty("textface", "Comic Sans MS"); + if(font === "georgia") self.ace.setProperty("textface", "Georgia"); + if(font === "impact") self.ace.setProperty("textface", "Impact"); + if(font === "lucida") self.ace.setProperty("textface", "Lucida"); + if(font === "lucidasans") self.ace.setProperty("textface", "Lucida Sans Unicode"); + if(font === "palatino") self.ace.setProperty("textface", "Palatino Linotype"); + if(font === "tahoma") self.ace.setProperty("textface", "Tahoma"); + if(font === "timesnewroman") self.ace.setProperty("textface", "Times New Roman"); + if(font === "trebuchet") self.ace.setProperty("textface", "Trebuchet MS"); + if(font === "verdana") self.ace.setProperty("textface", "Verdana"); + if(font === "symbol") self.ace.setProperty("textface", "Symbol"); + if(font === "webdings") self.ace.setProperty("textface", "Webdings"); + if(font === "wingdings") self.ace.setProperty("textface", "Wingdings"); + if(font === "sansserif") self.ace.setProperty("textface", "MS Sans Serif"); + if(font === "serif") self.ace.setProperty("textface", "MS Serif"); + + // $("#viewfontmenu").val(font); + normalFont = false; + } + }); + + // No font has been previously selected so use the Normal font + if(normalFont){ + console.log("Enabling a normal font"); + self.ace.setProperty("textface", "Arial, sans-serif"); + // $("#viewfontmenu").val("normal"); + } + }, dispose: function() { diff --git a/src/templates/pad.html b/src/templates/pad.html index 7c7257cc..99997615 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -160,6 +160,21 @@ From be73e729d4571e9541cbf703d1737fdc0db62fd7 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 12:25:33 +0000 Subject: [PATCH 03/45] remove console log --- src/static/js/pad.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 0e54168b..71fae678 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -638,7 +638,6 @@ var pad = { for (var k in opts.view) { pad.padOptions.view[k] = opts.view[k]; -console.log("setpref", k, opts.view[k]); padcookie.setPref(k, opts.view[k]); } padeditor.setViewOptions(pad.padOptions.view); From c6cac53ddada4eb89bb4b74dc4a7be9131b30d1d Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 12:25:49 +0000 Subject: [PATCH 04/45] remove console log --- src/static/js/pad_editor.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/static/js/pad_editor.js b/src/static/js/pad_editor.js index 51b9355e..ca7dc2b0 100644 --- a/src/static/js/pad_editor.js +++ b/src/static/js/pad_editor.js @@ -186,7 +186,6 @@ var padeditor = (function() // No font has been previously selected so use the Normal font if(normalFont){ - console.log("Enabling a normal font"); self.ace.setProperty("textface", "Arial, sans-serif"); // $("#viewfontmenu").val("normal"); } From 0c902ced7399ad1aacde688b34096c8851a6d699 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 15:19:52 +0000 Subject: [PATCH 05/45] better logic for handling lr arrows --- src/static/js/pad_editbar.js | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index b2d5ada5..14e33fe1 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -304,34 +304,27 @@ var padeditbar = (function() } }; + var editbarPosition = 0; + function editbarKeyEvent(evt){ // On arrow keys go to next/previous button item in editbar if(evt.keyCode !== 39 && evt.keyCode !== 37) return; - // Get our current Focus (Which editbar icon we're currently on) - var currentFocus = $(':focus'); + // Get all the focusable items in the editbar + var focusItems = $('#editbar').find('button, select'); // On left arrow move to next button in editbar if(evt.keyCode === 37){ - var nextFocus = $(currentFocus).parent().parent().prev(); - // No button in this focus so move on - if(nextFocus.find("button").length === 0){ - $(nextFocus).prev().find("button").focus(); - }else{ - $(currentFocus).parent().parent().prev().find("button").focus(); - } + editbarPosition--; + $(focusItems[editbarPosition]).focus(); } // On right arrow move to next button in editbar if(evt.keyCode === 39){ - var nextFocus = $(currentFocus).parent().parent().next(); - // No button in this focus so move on - if(nextFocus.find("button").length === 0){ - $(nextFocus).next().find("button").focus(); - }else{ - $(currentFocus).parent().parent().next().find("button").focus(); - } + editbarPosition++; + $(focusItems[editbarPosition]).focus(); } + } function aceAttributeCommand(cmd, ace) { From bc760e9494ab66f8ff72d14ec08614c286ebc5d3 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 15:38:19 +0000 Subject: [PATCH 06/45] logic to send focus back to pad on Alt F9 when focus on editbar --- src/static/js/ace2_inner.js | 5 +---- src/static/js/pad_editbar.js | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 8e4dab5c..4c8c5204 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3712,12 +3712,9 @@ function Ace2Inner(){ // Note that while most editors use Alt F10 this is not desirable // As ubuntu cannot use Alt F10.... evt.preventDefault(); - // Focus on the editbar. - top.console.log("focusing on first child in menu"); + // Focus on the editbar. -- TODO: Move Focus back to previous state (we know it so we can use it) var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first(); firstEditbarElement.focus(); - top.console.log(firstEditbarElement); - top.console.log(parent.parent.$(':focus')); $(this).blur(); } if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8) diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 14e33fe1..92e671c4 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -155,7 +155,7 @@ var padeditbar = (function() }); }); - $('#editbar').on("keyup", function(evt){ + $('#editbar').on("keydown", function(evt){ editbarKeyEvent(evt); }); @@ -307,6 +307,13 @@ var padeditbar = (function() var editbarPosition = 0; function editbarKeyEvent(evt){ + // If the event is Alt F9 (we're already in the editbar menu + // Send the users focus back to the pad + if(evt.keyCode === 120){ + // If we're in the editbar already.. + padeditor.ace.focus(); // Sends focus back + } + // On arrow keys go to next/previous button item in editbar if(evt.keyCode !== 39 && evt.keyCode !== 37) return; @@ -338,6 +345,20 @@ var padeditbar = (function() toolbar.registerDropdownCommand("import_export"); toolbar.registerDropdownCommand("embed"); + toolbar.registerCommand("import_export", function () { + setTimeout(function(){ + $('#importfileinput').focus(); + },100); + toolbar.toggleDropDown("import_export"); + }); + + toolbar.registerCommand("showusers", function () { + setTimeout(function(){ + $('#myusernameedit').focus(); // TODO: Not working + },100); + toolbar.toggleDropDown("users"); + }); + toolbar.registerCommand("embed", function () { toolbar.setEmbedLinks(); $('#linkinput').focus().select(); From e9360b6ed2b96e03c68a207e7562a87949e4b87a Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 15:49:41 +0000 Subject: [PATCH 07/45] working f9 logic --- src/static/js/ace2_inner.js | 5 +++-- src/static/js/lodash.js | 1 + src/static/js/pad_editbar.js | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 src/static/js/lodash.js diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 4c8c5204..2b7e2d4a 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3711,11 +3711,12 @@ function Ace2Inner(){ // Alt F9 focuses on the File Menu and/or editbar. // Note that while most editors use Alt F10 this is not desirable // As ubuntu cannot use Alt F10.... - evt.preventDefault(); // Focus on the editbar. -- TODO: Move Focus back to previous state (we know it so we can use it) var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first(); - firstEditbarElement.focus(); + // top.console.log("fEE", firstEditbarElement); $(this).blur(); + firstEditbarElement.focus(); + evt.preventDefault(); } if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8) { diff --git a/src/static/js/lodash.js b/src/static/js/lodash.js new file mode 100644 index 00000000..349f9579 --- /dev/null +++ b/src/static/js/lodash.js @@ -0,0 +1 @@ +module.exports = require('lodash'); diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 92e671c4..70360924 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -63,6 +63,7 @@ ToolbarItem.prototype.bind = function (callback) { if (self.isButton()) { self.$el.click(function (event) { + $(':focus').blur(); callback(self.getCommand(), self); event.preventDefault(); }); @@ -311,6 +312,7 @@ var padeditbar = (function() // Send the users focus back to the pad if(evt.keyCode === 120){ // If we're in the editbar already.. + $(':focus').blur(); // required to do not try to remove! padeditor.ace.focus(); // Sends focus back } From aff802a0b3e4f050a0558db5c91d24884751d516 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 21:15:44 +0000 Subject: [PATCH 08/45] whoops --- src/static/js/lodash.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/static/js/lodash.js diff --git a/src/static/js/lodash.js b/src/static/js/lodash.js deleted file mode 100644 index 349f9579..00000000 --- a/src/static/js/lodash.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('lodash'); From e67ae522e22afedac8585209eabdd3f388a24c78 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Mar 2015 23:30:17 +0000 Subject: [PATCH 09/45] support drop down show events --- src/static/js/ace2_inner.js | 1 - src/static/js/pad_editbar.js | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 2b7e2d4a..e190bfd7 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -4962,7 +4962,6 @@ function Ace2Inner(){ // a fix: in IE, clicking on a control like a button outside the // iframe can "blur" the editor, causing it to stop getting // events, though typing still affects it(!). - top.console.log("blur handled"); setSelection(null); } } diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 70360924..022e9493 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -347,6 +347,13 @@ var padeditbar = (function() toolbar.registerDropdownCommand("import_export"); toolbar.registerDropdownCommand("embed"); + toolbar.registerCommand("settings", function () { + setTimeout(function(){ + $('#options-stickychat').focus(); + },100); + toolbar.toggleDropDown("settings"); + }); + toolbar.registerCommand("import_export", function () { setTimeout(function(){ $('#importfileinput').focus(); @@ -363,7 +370,9 @@ var padeditbar = (function() toolbar.registerCommand("embed", function () { toolbar.setEmbedLinks(); - $('#linkinput').focus().select(); + setTimeout(function(){ + $('#linkinput').focus().select(); + }, 100); toolbar.toggleDropDown("embed"); }); From 69f0392e75534e9340f6349c5af3a765454ec78a Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 26 Mar 2015 11:24:06 +0000 Subject: [PATCH 10/45] escape to exit editbar --- src/static/js/pad_editbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 022e9493..a16cc63f 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -310,7 +310,7 @@ var padeditbar = (function() function editbarKeyEvent(evt){ // If the event is Alt F9 (we're already in the editbar menu // Send the users focus back to the pad - if(evt.keyCode === 120){ + if(evt.keyCode === 120 || evt.keyCode === 27){ // If we're in the editbar already.. $(':focus').blur(); // required to do not try to remove! padeditor.ace.focus(); // Sends focus back From 4362a42f7f0fa2919e26fd7806181bf9bb563cc5 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 26 Mar 2015 11:38:55 +0000 Subject: [PATCH 11/45] make index page accessible for screen readers --- src/templates/index.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/templates/index.html b/src/templates/index.html index 02ecf67a..626630e3 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -70,9 +70,10 @@ } #button { margin: 0 auto; - border-radius: 3px; text-align: center; font: 36px verdana,arial,sans-serif; + width:300px; + border:none; color: white; text-shadow: 0 -1px 0 rgba(0,0,0,.8); height: 70px; @@ -100,6 +101,7 @@ text-align: left; text-shadow: 0 1px 1px #fff; margin: 16px auto 0; + display:block; } #padname{ height:38px; @@ -158,8 +160,8 @@
<% e.begin_block("indexWrapper"); %>
-
-
+ +
From ec1956b4b6a41b92e636297cf5a9e8cf25938f79 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 26 Mar 2015 12:42:07 +0000 Subject: [PATCH 12/45] read for button activity --- src/node/utils/toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/utils/toolbar.js b/src/node/utils/toolbar.js index 65c2c1d5..85af619c 100644 --- a/src/node/utils/toolbar.js +++ b/src/node/utils/toolbar.js @@ -99,7 +99,7 @@ _.extend(Button.prototype, { }; return tag("li", liAttributes, tag("a", { "class": this.grouping, "data-l10n-id": this.attributes.localizationId }, - tag("button", { "class": " "+ this.attributes.class }) + tag("button", { "class": " "+ this.attributes.class, "title": this.attributes.command }) ) ); } From 1a5ea8707fdb2c692f5d69980a057b1c09f81ab7 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 26 Mar 2015 13:16:54 +0000 Subject: [PATCH 13/45] make the pad contents act like an application and not contents, this can probably be togglable but default state should be editable --- src/static/js/ace.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/ace.js b/src/static/js/ace.js index addc412f..376e786b 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -265,7 +265,7 @@ plugins.ensure(function () {\n\ iframeHTML: iframeHTML }); - iframeHTML.push(' '); + iframeHTML.push(' '); // Expose myself to global for my child frame. var thisFunctionsName = "ChildAccessibleAce2Editor"; From 959aa92656365a69d1502c13fa9a0c490c18cd06 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 26 Mar 2015 13:32:45 +0000 Subject: [PATCH 14/45] stop listing URL each time focus is placed back on inner iframe --- src/static/js/ace.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/static/js/ace.js b/src/static/js/ace.js index 376e786b..a9bbb0d9 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -279,6 +279,7 @@ window.onload = function () {\n\ setTimeout(function () {\n\ var iframe = document.createElement("IFRAME");\n\ iframe.name = "ace_inner";\n\ + iframe.title = "pad";\n\ iframe.scrolling = "no";\n\ var outerdocbody = document.getElementById("outerdocbody");\n\ iframe.frameBorder = 0;\n\ From 7b726cbc02e21bec9a267f0ba6fd8ab31a2dbded Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 26 Mar 2015 13:58:57 +0000 Subject: [PATCH 15/45] more working logic and also pretty nice screen reader experience --- src/node/utils/toolbar.js | 2 ++ src/static/js/ace.js | 1 + src/static/js/pad_editbar.js | 2 +- src/templates/pad.html | 4 ++-- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/node/utils/toolbar.js b/src/node/utils/toolbar.js index 85af619c..8905eee1 100644 --- a/src/node/utils/toolbar.js +++ b/src/node/utils/toolbar.js @@ -105,6 +105,8 @@ _.extend(Button.prototype, { } }); + + SelectButton = function (attributes) { this.attributes = attributes; this.options = []; diff --git a/src/static/js/ace.js b/src/static/js/ace.js index a9bbb0d9..c446939a 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -320,6 +320,7 @@ window.onload = function () {\n\ var outerFrame = document.createElement("IFRAME"); outerFrame.name = "ace_outer"; outerFrame.frameBorder = 0; // for IE + outerFrame.title = "Ether"; info.frame = outerFrame; document.getElementById(containerId).appendChild(outerFrame); diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index a16cc63f..c71d2b8a 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -325,7 +325,7 @@ var padeditbar = (function() // On left arrow move to next button in editbar if(evt.keyCode === 37){ editbarPosition--; - $(focusItems[editbarPosition]).focus(); + $(focusItems[editbarPosition]).focus() } // On right arrow move to next button in editbar diff --git a/src/templates/pad.html b/src/templates/pad.html index 99997615..c18a67d9 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -61,12 +61,12 @@
-
-
+
From 19e83d54059df5a653d7f4f7fc9cd60bf012b1fb Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 26 Mar 2015 16:58:13 +0000 Subject: [PATCH 19/45] much better chat focus toggle behavior --- src/static/js/ace2_inner.js | 5 +++-- src/static/js/chat.js | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index cb09432b..5442dd08 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3636,6 +3636,7 @@ function Ace2Inner(){ var charCode = evt.charCode; var keyCode = evt.keyCode; var which = evt.which; + var altKey = evt.altKey; // prevent ESC key if (keyCode == 27) @@ -3718,11 +3719,11 @@ function Ace2Inner(){ firstEditbarElement.focus(); evt.preventDefault(); } - if ((!specialHandled) && isTypeForSpecialKey && keyCode == 67){ + if ((!specialHandled) && altKey && keyCode == 67){ // Alt c focuses on the Chat window + $(this).blur(); parent.parent.chat.show(); parent.parent.chat.focus(); - $(this).blur(); evt.preventDefault(); } if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8) diff --git a/src/static/js/chat.js b/src/static/js/chat.js index 021a906a..7edf73ba 100644 --- a/src/static/js/chat.js +++ b/src/static/js/chat.js @@ -18,6 +18,7 @@ var padutils = require('./pad_utils').padutils; var padcookie = require('./pad_cookie').padcookie; var Tinycon = require('tinycon/tinycon'); var hooks = require('./pluginfw/hooks'); +var padeditor = require('./pad_editor').padeditor; var chat = (function() { @@ -38,7 +39,11 @@ var chat = (function() }, focus: function () { - $("#chatinput").focus(); + // I'm not sure why we need a setTimeout here but without it we don't get focus... + // Animation maybe? + setTimeout(function(){ + $("#chatinput").focus(); + },100); }, stickToScreen: function(fromInitialCall) // Make chat stick to right hand side of screen { @@ -209,8 +214,18 @@ var chat = (function() init: function(pad) { this._pad = pad; - $("#chatinput").keypress(function(evt) + $("#chatinput").keyup(function(evt) { + // If the event is Alt C or Escape & we're already in the chat menu + // Send the users focus back to the pad + if((evt.altKey == true && evt.which === 67) || evt.which === 27){ + // If we're in chat already.. + $(':focus').blur(); // required to do not try to remove! + padeditor.ace.focus(); // Sends focus back to pad + } + }); + + $("#chatinput").keypress(function(evt){ //if the user typed enter, fire the send if(evt.which == 13 || evt.which == 10) { From f9071aebe6deff70e84d38b5508d730edadc4902 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 30 Mar 2015 14:56:35 +0100 Subject: [PATCH 20/45] fix issue with showControls false not working --- src/static/css/pad.css | 6 ++++++ src/static/js/pad.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/static/css/pad.css b/src/static/css/pad.css index 1b730c3c..5b5d7dec 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -1262,3 +1262,9 @@ input[type=checkbox] { -moz-osx-font-smoothing: grayscale; } +.hideControlsEditor{ + top:0px !important; +} +.hideControlsEditbar{ + display:none !important; +} diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 71fae678..0d896a60 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -110,7 +110,7 @@ function randomString() // callback: the function to call when all above succeeds, `val` is the value supplied by the user var getParameters = [ { name: "noColors", checkVal: "true", callback: function(val) { settings.noColors = true; $('#clearAuthorship').hide(); } }, - { name: "showControls", checkVal: "false", callback: function(val) { $('#editbar').hide(); $('#editorcontainer').css({"top":"0px"}); } }, + { name: "showControls", checkVal: "false", callback: function(val) { $('#editbar').addClass('hideControlsEditbar'); $('#editorcontainer').addClass('hideControlsEditor'); } }, { name: "showChat", checkVal: "false", callback: function(val) { $('#chaticon').hide(); } }, { name: "showLineNumbers", checkVal: "false", callback: function(val) { settings.LineNumbersDisabled = true; } }, { name: "useMonospaceFont", checkVal: "true", callback: function(val) { settings.useMonospaceFontGlobal = true; } }, From a82e692bdd39feced285b6bd25c3ccb39b63434b Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 13:21:41 +0100 Subject: [PATCH 21/45] dont use nasty settimeouts use a callback instead for focus --- src/static/js/pad_editbar.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index aa9f183b..8df6e693 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -352,32 +352,30 @@ var padeditbar = (function() toolbar.registerDropdownCommand("embed"); toolbar.registerCommand("settings", function () { - setTimeout(function(){ + toolbar.toggleDropDown("settings", function(){ $('#options-stickychat').focus(); - },100); - toolbar.toggleDropDown("settings"); + }); }); toolbar.registerCommand("import_export", function () { - setTimeout(function(){ - $('#importfileinput').focus(); - },100); - toolbar.toggleDropDown("import_export"); + toolbar.toggleDropDown("import_export", function(){ + setTimeout(function(){ + $('#importfileinput').focus(); + }, 100); + }); }); toolbar.registerCommand("showusers", function () { - setTimeout(function(){ - $('#myusernameedit').focus(); // TODO: Not working - },100); - toolbar.toggleDropDown("users"); + toolbar.toggleDropDown("users", function(){ + $('#myusernameedit').focus(); + }); }); toolbar.registerCommand("embed", function () { toolbar.setEmbedLinks(); - setTimeout(function(){ + toolbar.toggleDropDown("embed", function(){ $('#linkinput').focus().select(); - }, 100); - toolbar.toggleDropDown("embed"); + }); }); toolbar.registerCommand("savedRevision", function () { From 35948989b398534cbd2a2817dc8553abc8077c93 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 13:45:11 +0100 Subject: [PATCH 22/45] make Alt C and Alt F9 and Escape work from anywhere --- src/static/js/ace2_inner.js | 1 + src/static/js/chat.js | 10 ++++++++++ src/static/js/pad_editbar.js | 10 ++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 5442dd08..a5e53eec 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -4960,6 +4960,7 @@ function Ace2Inner(){ function focus() { + top.console.log("window.focus there is a bug with me in FF"); window.focus(); } diff --git a/src/static/js/chat.js b/src/static/js/chat.js index 7edf73ba..42cd50f4 100644 --- a/src/static/js/chat.js +++ b/src/static/js/chat.js @@ -225,6 +225,16 @@ var chat = (function() } }); + $('body:not(#chatinput)').on("keydown", function(evt){ + if (evt.altKey && evt.which == 67){ + // Alt c focuses on the Chat window + $(this).blur(); + parent.parent.chat.show(); + parent.parent.chat.focus(); + evt.preventDefault(); + } + }); + $("#chatinput").keypress(function(evt){ //if the user typed enter, fire the send if(evt.which == 13 || evt.which == 10) diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 8df6e693..991c8594 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -156,8 +156,8 @@ var padeditbar = (function() }); }); - $('#editbar, .popup').on("keydown", function(evt){ - editbarKeyEvent(evt); + $('body:not(#editorcontainerbox)').on("keydown", function(evt){ + bodyKeyEvent(evt); }); $('#editbar').show(); @@ -307,10 +307,10 @@ var padeditbar = (function() var editbarPosition = 0; - function editbarKeyEvent(evt){ + function bodyKeyEvent(evt){ // If the event is Alt F9 or Escape & we're already in the editbar menu // Send the users focus back to the pad - if(evt.keyCode === 120 || evt.keyCode === 27){ + if((evt.keyCode === 120 && evt.altKey) || evt.keyCode === 27){ // If we're in the editbar already.. // Close any dropdowns we have open.. padeditbar.toggleDropDown("none"); @@ -318,6 +318,8 @@ var padeditbar = (function() // Shift focus away from any drop downs $(':focus').blur(); // required to do not try to remove! padeditor.ace.focus(); // Sends focus back to pad + // The above focus doesn't always work in FF, you have to hit enter afterwards + // This still needs fixing cake } // On arrow keys go to next/previous button item in editbar From ef38bcad9ff6e929ad0aa87b260ca73154270774 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 13:57:18 +0100 Subject: [PATCH 23/45] make buttons i18n friendly and a better experience --- src/node/utils/toolbar.js | 2 +- src/static/css/pad.css | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node/utils/toolbar.js b/src/node/utils/toolbar.js index 8905eee1..5d735323 100644 --- a/src/node/utils/toolbar.js +++ b/src/node/utils/toolbar.js @@ -99,7 +99,7 @@ _.extend(Button.prototype, { }; return tag("li", liAttributes, tag("a", { "class": this.grouping, "data-l10n-id": this.attributes.localizationId }, - tag("button", { "class": " "+ this.attributes.class, "title": this.attributes.command }) + tag("button", { "class": " "+ this.attributes.class, "alt": this.attributes.command, "data-l10n-id": this.attributes.localizationId }) ) ); } diff --git a/src/static/css/pad.css b/src/static/css/pad.css index 5b5d7dec..ee0a0a96 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -747,6 +747,7 @@ table#otheruserstable { font-style: normal; font-weight: normal; color: #666; + cursor: pointer; } .buttonicon::-moz-focus-inner { From 3126d7196ef97f4a2720a968d4ece405747655e4 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 14:06:02 +0100 Subject: [PATCH 24/45] fix alt and focus issues --- src/static/js/ace2_inner.js | 4 +--- src/static/js/pad_editbar.js | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index a5e53eec..32492e34 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3708,13 +3708,12 @@ function Ace2Inner(){ evt:evt }); specialHandled = (specialHandledInHook&&specialHandledInHook.length>0)?specialHandledInHook[0]:specialHandled; - if ((!specialHandled) && isTypeForSpecialKey && keyCode == 120){ + if ((!specialHandled) && altKey && isTypeForSpecialKey && keyCode == 120){ // Alt F9 focuses on the File Menu and/or editbar. // Note that while most editors use Alt F10 this is not desirable // As ubuntu cannot use Alt F10.... // Focus on the editbar. -- TODO: Move Focus back to previous state (we know it so we can use it) var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first(); - // top.console.log("fEE", firstEditbarElement); $(this).blur(); firstEditbarElement.focus(); evt.preventDefault(); @@ -4960,7 +4959,6 @@ function Ace2Inner(){ function focus() { - top.console.log("window.focus there is a bug with me in FF"); window.focus(); } diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 991c8594..75bf40f0 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -320,6 +320,7 @@ var padeditbar = (function() padeditor.ace.focus(); // Sends focus back to pad // The above focus doesn't always work in FF, you have to hit enter afterwards // This still needs fixing cake + evt.preventDefault(); } // On arrow keys go to next/previous button item in editbar From 0f0a6c73ac461227d496881f244e1b9cfa2be7f7 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 14:11:49 +0100 Subject: [PATCH 25/45] make user list a document so it's easy to navigate by screen readers --- src/static/css/pad.css | 2 +- src/templates/pad.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/css/pad.css b/src/static/css/pad.css index ee0a0a96..01da9332 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -756,7 +756,7 @@ table#otheruserstable { } .buttonicon:focus{ - border: 1px solid #fff; + border: 1px solid #666; } .buttonicon-bold:before { content: "\e81c"; diff --git a/src/templates/pad.html b/src/templates/pad.html index 32cf7296..babccd0f 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -88,7 +88,7 @@
-
+
From 73073dcbc1e741d4a9e62afad7f76f2838f2237d Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 14:47:00 +0100 Subject: [PATCH 26/45] Timeslider accessibility and Bugfixes --- src/static/css/pad.css | 15 ++++++++++++++- src/static/js/broadcast_slider.js | 1 - src/static/js/pad_editbar.js | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/static/css/pad.css b/src/static/css/pad.css index 01da9332..e5e765a1 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -137,8 +137,21 @@ a img { top: 1px; } .toolbar ul li a .buttontext { - color: #222; + color: #666; font-size: 14px; + border:none; + background:none; + margin-top:1px; + color:#666; +} +.buttontext::-moz-focus-inner { + padding: 0; + border: 0; +} +.buttontext:focus{ + border: 1px solid #666; +} + } .toolbar ul li a.grouped-left { border-radius: 3px 0 0 3px; diff --git a/src/static/js/broadcast_slider.js b/src/static/js/broadcast_slider.js index 7f0e48bc..a1418140 100644 --- a/src/static/js/broadcast_slider.js +++ b/src/static/js/broadcast_slider.js @@ -330,7 +330,6 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) } } else if (code == 32) playpause(); - }); $(window).resize(function() diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 75bf40f0..027fce82 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -308,6 +308,10 @@ var padeditbar = (function() var editbarPosition = 0; function bodyKeyEvent(evt){ + // Check we're on a pad and not on the timeslider + // Or some other window I haven't thought about! + if(typeof pad === 'undefined') return false; + // If the event is Alt F9 or Escape & we're already in the editbar menu // Send the users focus back to the pad if((evt.keyCode === 120 && evt.altKey) || evt.keyCode === 27){ From 24e6e1728a020e38e023df0a09ad38941ba0dd82 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 15:00:43 +0100 Subject: [PATCH 27/45] I came to bring the rain.. Let me get my coat... Fix focus on timeslider import export --- src/static/css/timeslider.css | 19 ++++++++++++++++++- src/static/js/pad_editbar.js | 18 ++++++++++++------ src/templates/timeslider.html | 6 +++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/static/css/timeslider.css b/src/static/css/timeslider.css index 49f89421..7bff7341 100644 --- a/src/static/css/timeslider.css +++ b/src/static/css/timeslider.css @@ -78,6 +78,7 @@ width: 44px; text-align:center; vertical-align:middle; + background:none; } #playpause_button { right: 77px; @@ -125,7 +126,7 @@ font-family: fontawesome-etherpad; border-radius:2px; border: #666 solid 1px; - line-height:18px; +/* line-height:18px; */ text-align:center; height:22px; color:#666; @@ -337,3 +338,19 @@ OL { .list-number6 { list-style-type: lower-roman } + +button{ + margin:0; + padding:0; + cursor:pointer; +} + +button::-moz-focus-inner { + padding: 0; + border: 0 +} + +button:focus{ + border: 1px solid #666; +} + diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 027fce82..fadbc09d 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -308,9 +308,6 @@ var padeditbar = (function() var editbarPosition = 0; function bodyKeyEvent(evt){ - // Check we're on a pad and not on the timeslider - // Or some other window I haven't thought about! - if(typeof pad === 'undefined') return false; // If the event is Alt F9 or Escape & we're already in the editbar menu // Send the users focus back to the pad @@ -319,6 +316,10 @@ var padeditbar = (function() // Close any dropdowns we have open.. padeditbar.toggleDropDown("none"); + // Check we're on a pad and not on the timeslider + // Or some other window I haven't thought about! + if(typeof pad === 'undefined') return false; + // Shift focus away from any drop downs $(':focus').blur(); // required to do not try to remove! padeditor.ace.focus(); // Sends focus back to pad @@ -366,9 +367,14 @@ var padeditbar = (function() toolbar.registerCommand("import_export", function () { toolbar.toggleDropDown("import_export", function(){ - setTimeout(function(){ - $('#importfileinput').focus(); - }, 100); + // If Import file input exists then focus on it.. + if($('#importfileinput').length !== 0){ + setTimeout(function(){ + $('#importfileinput').focus(); + }, 100); + }else{ + $('.exportlink').first().focus(); + } }); }); diff --git a/src/templates/timeslider.html b/src/templates/timeslider.html index a619c702..20688ea8 100644 --- a/src/templates/timeslider.html +++ b/src/templates/timeslider.html @@ -61,11 +61,11 @@
-
+
-
-
+ +
From 498e7f4961379822e7a3ab03cc9963dceddf2e32 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 16:12:05 +0100 Subject: [PATCH 28/45] MVP of alt A behavior to show author of line --- src/static/js/ace2_inner.js | 40 ++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 32492e34..919fa4c7 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3677,7 +3677,6 @@ function Ace2Inner(){ if (keyCode == 13 && browser.opera && (type == "keypress")){ return; // This stops double enters in Opera but double Tabs still show on single tab keypress, adding keyCode == 9 to this doesn't help as the event is fired twice } - var specialHandled = false; var isTypeForSpecialKey = ((browser.msie || browser.safari || browser.chrome) ? (type == "keydown") : (type == "keypress")); var isTypeForCmdKey = ((browser.msie || browser.safari || browser.chrome) ? (type == "keydown") : (type == "keypress")); @@ -3725,6 +3724,45 @@ function Ace2Inner(){ parent.parent.chat.focus(); evt.preventDefault(); } + if ((!specialHandled) && altKey && keyCode == 65 && type === "keydown"){ + // Alt A shows a gritter popup showing a line author + var lineNumber = rep.selEnd[0]; + var alineAttrs = rep.alines[lineNumber]; + var apool = rep.apool; + + // TODO: support selection ranges + // TODO: Support multiple authors + // TODO: Still work when authorship colors have been cleared + // TODO: i18n + // TODO: There appears to be a race condition or so. + + var author = null; + if (alineAttrs) { + var opIter = Changeset.opIterator(alineAttrs); + if (opIter.hasNext()) { + var op = opIter.next(); + authorId = Changeset.opAttributeValue(op, 'author', apool); + } + } + if(authorId.length === 0){ + author = "not available"; + }else{ + var authorObj = parent.parent.clientVars.collab_client_vars.historicalAuthorData[authorId]; + author = authorObj.name; + if(author === "") author = "not available"; + } + + parent.parent.$.gritter.add({ + // (string | mandatory) the heading of the notification + title: 'Authors', + // (string | mandatory) the text inside the notification + text: 'The author of this line is ' + author, + // (bool | optional) if you want it to fade out on its own or just sit there + sticky: false, + // (int | optional) the time you want it to be alive for before fading out + time: '4000' + }); + } if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8) { // "delete" key; in mozilla, if we're at the beginning of a line, normalize now, From 662216b6cfa9f35ecda27eca83b10acd09b5bd9b Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 16:36:44 +0100 Subject: [PATCH 29/45] slightly different alt stuff --- src/node/utils/toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/utils/toolbar.js b/src/node/utils/toolbar.js index 5d735323..3bae0b1c 100644 --- a/src/node/utils/toolbar.js +++ b/src/node/utils/toolbar.js @@ -99,7 +99,7 @@ _.extend(Button.prototype, { }; return tag("li", liAttributes, tag("a", { "class": this.grouping, "data-l10n-id": this.attributes.localizationId }, - tag("button", { "class": " "+ this.attributes.class, "alt": this.attributes.command, "data-l10n-id": this.attributes.localizationId }) + tag("button", { "class": " "+ this.attributes.class, "data-l10n-id": this.attributes.localizationId }) ) ); } From 37c7c7eabec8327869253c4715b755e8a5aa944b Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 17:06:04 +0100 Subject: [PATCH 30/45] i18n for timeslider steppers --- src/locales/en.json | 4 ++++ src/templates/timeslider.html | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index b5713660..828844b0 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -121,6 +121,10 @@ "timeslider.version": "Version {{version}}", "timeslider.saved": "Saved {{month}} {{day}}, {{year}}", + "timeslider.playpause": "Playback / Pause Pad Contents", + "timeslider.backrevision":"Go back a revision in this Pad", + "timeslider.forwardrevision":"Go forward a revision in this Pad", + "timeslider.dateformat": "{{month}}/{{day}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}", "timeslider.month.january": "January", "timeslider.month.february": "February", diff --git a/src/templates/timeslider.html b/src/templates/timeslider.html index 20688ea8..45d7832d 100644 --- a/src/templates/timeslider.html +++ b/src/templates/timeslider.html @@ -61,11 +61,11 @@
- +
- - + +
From 48862dac6f69ff80507c0bad6608968f54430cd6 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 18:50:20 +0100 Subject: [PATCH 31/45] better handling for inputs and left and right arrows --- src/static/js/pad_editbar.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index fadbc09d..e426824e 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -324,7 +324,6 @@ var padeditbar = (function() $(':focus').blur(); // required to do not try to remove! padeditor.ace.focus(); // Sends focus back to pad // The above focus doesn't always work in FF, you have to hit enter afterwards - // This still needs fixing cake evt.preventDefault(); } @@ -336,13 +335,23 @@ var padeditbar = (function() // On left arrow move to next button in editbar if(evt.keyCode === 37){ + // If a dropdown is visible or we're in an input don't move to the next button + if($('.popup').is(":visible") || evt.target.localName === "input") return; + editbarPosition--; + // Allow focus to shift back to end of row and start of row + if(editbarPosition === -1) editbarPosition = focusItems.length -1; $(focusItems[editbarPosition]).focus() } // On right arrow move to next button in editbar if(evt.keyCode === 39){ + // If a dropdown is visible or we're in an input don't move to the next button + if($('.popup').is(":visible") || evt.target.localName === "input") return; + editbarPosition++; + // Allow focus to shift back to end of row and start of row + if(editbarPosition >= focusItems.length) editbarPosition = 0; $(focusItems[editbarPosition]).focus(); } From 64034ee1c6701e05a57f2d332a2cd3ca58f318dc Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 18:50:50 +0100 Subject: [PATCH 32/45] doh caps --- src/locales/en.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index 828844b0..24c56edf 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -121,9 +121,9 @@ "timeslider.version": "Version {{version}}", "timeslider.saved": "Saved {{month}} {{day}}, {{year}}", - "timeslider.playpause": "Playback / Pause Pad Contents", - "timeslider.backrevision":"Go back a revision in this Pad", - "timeslider.forwardrevision":"Go forward a revision in this Pad", + "timeslider.playPause": "Playback / Pause Pad Contents", + "timeslider.backRevision":"Go back a revision in this Pad", + "timeslider.forwardRevision":"Go forward a revision in this Pad", "timeslider.dateformat": "{{month}}/{{day}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}", "timeslider.month.january": "January", From e9d8c3b53a3d43096f4a8334de20e47b682111d3 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 20:26:55 +0100 Subject: [PATCH 33/45] expose method for getting a full user list on the client including historical data --- src/static/js/ace2_inner.js | 59 +++++++++++++++++++++++++++++------ src/static/js/pad.js | 4 +++ src/static/js/pad_userlist.js | 24 ++++++++++++++ 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 919fa4c7..3c6c7cb8 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3731,32 +3731,71 @@ function Ace2Inner(){ var apool = rep.apool; // TODO: support selection ranges - // TODO: Support multiple authors // TODO: Still work when authorship colors have been cleared // TODO: i18n // TODO: There appears to be a race condition or so. var author = null; if (alineAttrs) { + var authors = []; + var authorNames = []; var opIter = Changeset.opIterator(alineAttrs); - if (opIter.hasNext()) { + + while (opIter.hasNext()){ var op = opIter.next(); authorId = Changeset.opAttributeValue(op, 'author', apool); + + // Only push unique authors and ones with values + if(authors.indexOf(authorId) === -1 && authorId !== ""){ + authors.push(authorId); + } + } + } - if(authorId.length === 0){ - author = "not available"; - }else{ - var authorObj = parent.parent.clientVars.collab_client_vars.historicalAuthorData[authorId]; - author = authorObj.name; - if(author === "") author = "not available"; + + // No author information is available IE on a new pad. + if(authors.length === 0){ + var authorString = "No author information is available"; } + else{ + // Known authors info, both current and historical + var padAuthors = parent.parent.pad.userList(); + var authorObj = {}; + authors.forEach(function(authorId){ + padAuthors.forEach(function(padAuthor){ + // If the person doing the lookup is the author.. + if(padAuthor.userId === authorId){ + if(parent.parent.clientVars.userId === authorId){ + authorObj = { + name: "Me" + } + }else{ + authorObj = padAuthor; + } + } + }); + if(!authorObj){ + author = "Unknown"; + return; + } + author = authorObj.name; + if(!author) author = "Unknown"; + authorNames.push(author); + }) + } + if(authors.length === 1){ + var authorString = "The author of this line is " + authorNames; + } + if(authors.length > 1){ + var authorString = "The authors of this line are " + authorNames.join(" & "); + } parent.parent.$.gritter.add({ // (string | mandatory) the heading of the notification - title: 'Authors', + title: 'Line Authors', // (string | mandatory) the text inside the notification - text: 'The author of this line is ' + author, + text: authorString, // (bool | optional) if you want it to fade out on its own or just sit there sticky: false, // (int | optional) the time you want it to be alive for before fading out diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 0d896a60..5ac9d03d 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -433,6 +433,10 @@ var pad = { { return pad.myUserInfo.name; }, + userList: function() + { + return paduserlist.users(); + }, sendClientReady: function(isReconnect, messageType) { messageType = typeof messageType !== 'undefined' ? messageType : 'CLIENT_READY'; diff --git a/src/static/js/pad_userlist.js b/src/static/js/pad_userlist.js index d306256a..22dab40a 100644 --- a/src/static/js/pad_userlist.js +++ b/src/static/js/pad_userlist.js @@ -508,6 +508,30 @@ var paduserlist = (function() }); // }, + users: function(){ + // Returns an object of users who have been on this pad + // Firstly we have to get live data.. + var userList = otherUsersInfo; + // Now we need to add ourselves.. + userList.push(myUserInfo); + // Now we add historical authors + var historical = clientVars.collab_client_vars.historicalAuthorData; + for (var key in historical){ + var userId = historical[key].userId; + // Check we don't already have this author in our array + var exists = false; + + userList.forEach(function(user){ + if(user.userId === userId) exists = true; + }); + + if(exists === false){ + userList.push(historical[key]); + } + + } + return userList; + }, setMyUserInfo: function(info) { //translate the colorId From 733deb613e395543ea98690dee0b7eb16f6c36a8 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 31 Mar 2015 23:51:40 +0100 Subject: [PATCH 34/45] fix font type test --- tests/frontend/specs/font_type.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/frontend/specs/font_type.js b/tests/frontend/specs/font_type.js index 25d9df05..41b1de34 100644 --- a/tests/frontend/specs/font_type.js +++ b/tests/frontend/specs/font_type.js @@ -24,7 +24,7 @@ describe("font select", function(){ //check if font changed to monospace var fontFamily = inner$("body").css("font-family").toLowerCase(); - expect(fontFamily).to.be("monospace"); + expect(fontFamily).to.be("courier new"); done(); }); From fef746e80e010baffc4874f6eb8175ce2453ac15 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 1 Apr 2015 00:19:42 +0100 Subject: [PATCH 35/45] fix import issue with txt files and abiword #2572 --- src/node/handler/ImportHandler.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/node/handler/ImportHandler.js b/src/node/handler/ImportHandler.js index 67698651..2dad8b3d 100644 --- a/src/node/handler/ImportHandler.js +++ b/src/node/handler/ImportHandler.js @@ -148,6 +148,9 @@ exports.doImport = function(req, res, padId) if(!importHandledByPlugin || !directDatabaseAccess){ var fileEnding = path.extname(srcFile).toLowerCase(); var fileIsHTML = (fileEnding === ".html" || fileEnding === ".htm"); + var fileIsTXT = (fileEnding === ".txt"); + if (fileIsTXT) abiword = false; // Don't use abiword for text files + // See https://github.com/ether/etherpad-lite/issues/2572 if (abiword && !fileIsHTML) { abiword.convertFile(srcFile, destFile, "htm", function(err) { //catch convert errors @@ -213,7 +216,7 @@ exports.doImport = function(req, res, padId) // Title needs to be stripped out else it appends it to the pad.. text = text.replace("", "<!-- <title>"); text = text.replace("","-->"); - + //node on windows has a delay on releasing of the file lock. //We add a 100ms delay to work around this if(os.type().indexOf("Windows") > -1){ @@ -245,7 +248,6 @@ exports.doImport = function(req, res, padId) padManager.getPad(padId, function(err, _pad){ var pad = _pad; padManager.unloadPad(padId); - // direct Database Access means a pad user should perform a switchToPad // and not attempt to recieve updated pad data.. if(!directDatabaseAccess){ From f6b4b5603dfe34ef04f88166579f81e0abcf64ec Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 2 Apr 2015 00:03:34 +0100 Subject: [PATCH 36/45] fix timeslider title issues --- src/static/js/timeslider.js | 6 ++++++ src/templates/timeslider.html | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/static/js/timeslider.js b/src/static/js/timeslider.js index ec237df5..580a7a03 100644 --- a/src/static/js/timeslider.js +++ b/src/static/js/timeslider.js @@ -157,6 +157,12 @@ function handleClientVars(message) fireWhenAllScriptsAreLoaded[i](); } $("#ui-slider-handle").css('left', $("#ui-slider-bar").width() - 2); + + // Translate some strings where we only want to set the title not the actual values + $('#playpause_button_icon').attr("title", html10n.get("timeslider.playPause")); + $('#leftstep').attr("title", html10n.get("timeslider.backRevision")); + $('#rightstep').attr("title", html10n.get("timeslider.forwardRevision")); + } exports.baseURL = ''; diff --git a/src/templates/timeslider.html b/src/templates/timeslider.html index 45d7832d..20688ea8 100644 --- a/src/templates/timeslider.html +++ b/src/templates/timeslider.html @@ -61,11 +61,11 @@
- +
- - + +
From 85fc012bac0dbeefac611314f4ab35f276de871b Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 2 Apr 2015 15:13:16 +0100 Subject: [PATCH 37/45] change to alt shit and a to show authors --- src/static/js/ace2_inner.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index eef99b1b..b37c737c 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3616,6 +3616,7 @@ function Ace2Inner(){ var keyCode = evt.keyCode; var which = evt.which; var altKey = evt.altKey; + var shiftKey = evt.shiftKey; // prevent ESC key if (keyCode == 27) @@ -3703,8 +3704,8 @@ function Ace2Inner(){ parent.parent.chat.focus(); evt.preventDefault(); } - if ((!specialHandled) && altKey && keyCode == 65 && type === "keydown"){ - // Alt A shows a gritter popup showing a line author + if ((!specialHandled) && altKey && shiftKey && keyCode == 65 && type === "keydown"){ + // Alt-Shift-A shows a gritter popup showing a line author var lineNumber = rep.selEnd[0]; var alineAttrs = rep.alines[lineNumber]; var apool = rep.apool; From f79e2c7de201ed948e827437c18aa96f312a6b51 Mon Sep 17 00:00:00 2001 From: John McLear Date: Fri, 3 Apr 2015 12:29:47 +0100 Subject: [PATCH 38/45] final accessibility for Timeslider hopefully --- src/static/js/broadcast_slider.js | 5 ++ src/static/js/pad_editbar.js | 84 ++++++++++++++++++------------- 2 files changed, 54 insertions(+), 35 deletions(-) diff --git a/src/static/js/broadcast_slider.js b/src/static/js/broadcast_slider.js index a1418140..eff20b52 100644 --- a/src/static/js/broadcast_slider.js +++ b/src/static/js/broadcast_slider.js @@ -290,6 +290,11 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) $(document).keyup(function(e) { + // If focus is on editbar, don't do anything + var target = $(':focus'); + if($(target).parents(".toolbar").length === 1){ + return; + } var code = -1; if (!e) var e = window.event; if (e.keyCode) code = e.keyCode; diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index e426824e..e418969e 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -312,47 +312,61 @@ var padeditbar = (function() // If the event is Alt F9 or Escape & we're already in the editbar menu // Send the users focus back to the pad if((evt.keyCode === 120 && evt.altKey) || evt.keyCode === 27){ - // If we're in the editbar already.. - // Close any dropdowns we have open.. - padeditbar.toggleDropDown("none"); - - // Check we're on a pad and not on the timeslider - // Or some other window I haven't thought about! - if(typeof pad === 'undefined') return false; - - // Shift focus away from any drop downs - $(':focus').blur(); // required to do not try to remove! - padeditor.ace.focus(); // Sends focus back to pad - // The above focus doesn't always work in FF, you have to hit enter afterwards - evt.preventDefault(); + if($(':focus').parents(".toolbar").length === 1){ + // If we're in the editbar already.. + // Close any dropdowns we have open.. + padeditbar.toggleDropDown("none"); + // Check we're on a pad and not on the timeslider + // Or some other window I haven't thought about! + if(typeof pad === 'undefined'){ + // Timeslider probably.. + // Shift focus away from any drop downs + $(':focus').blur(); // required to do not try to remove! + $('#padmain').focus(); // Focus back onto the pad + }else{ + // Shift focus away from any drop downs + $(':focus').blur(); // required to do not try to remove! + padeditor.ace.focus(); // Sends focus back to pad + // The above focus doesn't always work in FF, you have to hit enter afterwards + evt.preventDefault(); + } + }else{ + // Focus on the editbar :) + var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first(); + $(this).blur(); + firstEditbarElement.focus(); + evt.preventDefault(); + } } + // Are we in the toolbar?? + if($(':focus').parents(".toolbar").length === 1){ + // On arrow keys go to next/previous button item in editbar + if(evt.keyCode !== 39 && evt.keyCode !== 37) return; - // On arrow keys go to next/previous button item in editbar - if(evt.keyCode !== 39 && evt.keyCode !== 37) return; + // Get all the focusable items in the editbar + var focusItems = $('#editbar').find('button, select'); - // Get all the focusable items in the editbar - var focusItems = $('#editbar').find('button, select'); + // On left arrow move to next button in editbar + if(evt.keyCode === 37){ + // If a dropdown is visible or we're in an input don't move to the next button + if($('.popup').is(":visible") || evt.target.localName === "input") return; - // On left arrow move to next button in editbar - if(evt.keyCode === 37){ - // If a dropdown is visible or we're in an input don't move to the next button - if($('.popup').is(":visible") || evt.target.localName === "input") return; + editbarPosition--; + // Allow focus to shift back to end of row and start of row + if(editbarPosition === -1) editbarPosition = focusItems.length -1; + $(focusItems[editbarPosition]).focus() + } - editbarPosition--; - // Allow focus to shift back to end of row and start of row - if(editbarPosition === -1) editbarPosition = focusItems.length -1; - $(focusItems[editbarPosition]).focus() - } + // On right arrow move to next button in editbar + if(evt.keyCode === 39){ + // If a dropdown is visible or we're in an input don't move to the next button + if($('.popup').is(":visible") || evt.target.localName === "input") return; - // On right arrow move to next button in editbar - if(evt.keyCode === 39){ - // If a dropdown is visible or we're in an input don't move to the next button - if($('.popup').is(":visible") || evt.target.localName === "input") return; - - editbarPosition++; - // Allow focus to shift back to end of row and start of row - if(editbarPosition >= focusItems.length) editbarPosition = 0; - $(focusItems[editbarPosition]).focus(); + editbarPosition++; + // Allow focus to shift back to end of row and start of row + if(editbarPosition >= focusItems.length) editbarPosition = 0; + $(focusItems[editbarPosition]).focus(); + } } } From 9090d76dcf65492f99385b1e9a81e20d34cd2630 Mon Sep 17 00:00:00 2001 From: John McLear Date: Fri, 3 Apr 2015 12:33:31 +0100 Subject: [PATCH 39/45] temp solution for alt 9 to show editbar label --- src/templates/pad.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templates/pad.html b/src/templates/pad.html index babccd0f..cdaeb058 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -56,7 +56,7 @@ <% e.begin_block("body"); %> -
+
From c65ddad7d6727e9994a32ab2f450e9dd23cfc240 Mon Sep 17 00:00:00 2001 From: John McLear Date: Fri, 3 Apr 2015 13:06:03 +0100 Subject: [PATCH 40/45] title for chat --- src/templates/pad.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templates/pad.html b/src/templates/pad.html index cdaeb058..697caf3b 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -321,7 +321,7 @@ <% e.end_block(); %>
-
+
0 From db0bcdd696282ec5d8ab7ab4c2cbeb5043131a96 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 5 Apr 2015 13:39:20 +0100 Subject: [PATCH 41/45] fix issue where focus on timeslider wouldnt work --- src/static/css/pad.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/static/css/pad.css b/src/static/css/pad.css index e5e765a1..2e68ed00 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -144,15 +144,17 @@ a img { margin-top:1px; color:#666; } + .buttontext::-moz-focus-inner { padding: 0; border: 0; } + .buttontext:focus{ - border: 1px solid #666; + /* Not sure why important is required here but it is */ + border: 1px solid #666 !important; } -} .toolbar ul li a.grouped-left { border-radius: 3px 0 0 3px; } From e49bb4017c5cd054ca2b1880c78148e10417de1f Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 5 Apr 2015 13:42:26 +0100 Subject: [PATCH 42/45] use ctrl shift 2 instead of alt a --- src/static/js/ace2_inner.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index b37c737c..7773074e 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3704,8 +3704,8 @@ function Ace2Inner(){ parent.parent.chat.focus(); evt.preventDefault(); } - if ((!specialHandled) && altKey && shiftKey && keyCode == 65 && type === "keydown"){ - // Alt-Shift-A shows a gritter popup showing a line author + if ((!specialHandled) && evt.ctrlKey && shiftKey && keyCode == 50 && type === "keydown"){ + // Control-Shift-2 shows a gritter popup showing a line author var lineNumber = rep.selEnd[0]; var alineAttrs = rep.alines[lineNumber]; var apool = rep.apool; From 41bb4ef094ebd22c5d0068dd9e0ca13816519c81 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 5 Apr 2015 14:03:09 +0100 Subject: [PATCH 43/45] support for open dyslexic font --- src/locales/en.json | 1 + src/static/css/pad.css | 6 ++++++ src/static/font/opendyslexic.otf | Bin 0 -> 48076 bytes src/static/js/pad.js | 2 +- src/static/js/pad_editor.js | 3 ++- src/templates/pad.html | 1 + 6 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 src/static/font/opendyslexic.otf diff --git a/src/locales/en.json b/src/locales/en.json index 24c56edf..3e16c5de 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -38,6 +38,7 @@ "pad.settings.rtlcheck": "Read content from right to left?", "pad.settings.fontType": "Font type:", "pad.settings.fontType.normal": "Normal", + "pad.settings.fontType.opendyslexic": "Open Dyslexic", "pad.settings.fontType.monospaced": "Monospace", "pad.settings.fontType.comicsans": "Comic Sans", "pad.settings.fontType.couriernew": "Courier New", diff --git a/src/static/css/pad.css b/src/static/css/pad.css index 2e68ed00..96e2122b 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -1284,3 +1284,9 @@ input[type=checkbox] { .hideControlsEditbar{ display:none !important; } + + +@font-face { + font-family: opendyslexic; + src: url("../font/opendyslexic.otf") format("opentype"); +} diff --git a/src/static/font/opendyslexic.otf b/src/static/font/opendyslexic.otf new file mode 100644 index 0000000000000000000000000000000000000000..1a7c9d411b225f4e596478314151e9c4d57e3a9f GIT binary patch literal 48076 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 F{~vP7>ly$6 literal 0 HcmV?d00001 diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 5ac9d03d..f1de80f0 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -581,7 +581,7 @@ var pad = { pad.changeViewOption('rtlIsTrue', true); } - var fonts = ['useMonospaceFont', 'useComicSansFont', 'useCourierNewFont', 'useGeorgiaFont', 'useImpactFont', + var fonts = ['useMonospaceFont', 'useOpenDyslexicFont', 'useComicSansFont', 'useCourierNewFont', 'useGeorgiaFont', 'useImpactFont', 'useLucidaFont', 'useLucidaSansFont', 'usePalatinoFont', 'useTahomaFont', 'useTimesNewRomanFont', 'useTrebuchetFont', 'useVerdanaFont', 'useSymbolFont', 'useWebdingsFont', 'useWingDingsFont', 'useSansSerifFont', 'useSerifFont']; diff --git a/src/static/js/pad_editor.js b/src/static/js/pad_editor.js index ca7dc2b0..b1ea09f7 100644 --- a/src/static/js/pad_editor.js +++ b/src/static/js/pad_editor.js @@ -30,7 +30,7 @@ var padeditor = (function() var settings = undefined; // Array of available fonts - var fonts = ['useMonospaceFont', 'useComicSansFont', 'useCourierNewFont', 'useGeorgiaFont', 'useImpactFont', + var fonts = ['useMonospaceFont', 'useOpenDyslexicFont', 'useComicSansFont', 'useCourierNewFont', 'useGeorgiaFont', 'useImpactFont', 'useLucidaFont', 'useLucidaSansFont', 'usePalatinoFont', 'useTahomaFont', 'useTimesNewRomanFont', 'useTrebuchetFont', 'useVerdanaFont', 'useSymbolFont', 'useWebdingsFont', 'useWingDingsFont', 'useSansSerifFont', 'useSerifFont']; @@ -163,6 +163,7 @@ var padeditor = (function() font = font.replace("Font",""); font = font.toLowerCase(); if(font === "monospace") self.ace.setProperty("textface", "Courier new"); + if(font === "opendyslexic") self.ace.setProperty("textface", "OpenDyslexic"); if(font === "comicsans") self.ace.setProperty("textface", "Comic Sans MS"); if(font === "georgia") self.ace.setProperty("textface", "Georgia"); if(font === "impact") self.ace.setProperty("textface", "Impact"); diff --git a/src/templates/pad.html b/src/templates/pad.html index 697caf3b..dd260414 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -160,6 +160,7 @@
+ + + + +
-
+ + + +