diff options
-rw-r--r-- | src/locales/en.json | 21 | ||||
-rw-r--r-- | src/node/handler/ImportHandler.js | 6 | ||||
-rw-r--r-- | src/node/utils/Settings.js | 2 | ||||
-rw-r--r-- | src/node/utils/toolbar.js | 10 | ||||
-rw-r--r-- | src/static/css/pad.css | 49 | ||||
-rw-r--r-- | src/static/css/timeslider.css | 32 | ||||
-rw-r--r-- | src/static/font/opendyslexic.otf | bin | 0 -> 48076 bytes | |||
-rw-r--r-- | src/static/js/ace.js | 4 | ||||
-rw-r--r-- | src/static/js/ace2_inner.js | 98 | ||||
-rw-r--r-- | src/static/js/broadcast_slider.js | 6 | ||||
-rw-r--r-- | src/static/js/chat.js | 31 | ||||
-rw-r--r-- | src/static/js/gritter.js | 2 | ||||
-rw-r--r-- | src/static/js/pad.js | 21 | ||||
-rw-r--r-- | src/static/js/pad_editbar.js | 101 | ||||
-rw-r--r-- | src/static/js/pad_editor.js | 72 | ||||
-rw-r--r-- | src/static/js/pad_userlist.js | 24 | ||||
-rw-r--r-- | src/static/js/timeslider.js | 32 | ||||
-rw-r--r-- | src/templates/index.html | 8 | ||||
-rw-r--r-- | src/templates/pad.html | 28 | ||||
-rw-r--r-- | src/templates/timeslider.html | 38 | ||||
-rw-r--r-- | tests/frontend/specs/font_type.js | 2 |
21 files changed, 530 insertions, 57 deletions
diff --git a/src/locales/en.json b/src/locales/en.json index 23bb3a04..3e16c5de 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -38,7 +38,24 @@ "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", + "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:", @@ -105,6 +122,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/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>", "<!-- <title>"); text = text.replace("</title>","</title>-->"); - + //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){ diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 5382d819..14e43305 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -95,7 +95,7 @@ exports.toolbar = { ["showusers"] ], timeslider: [ - ["timeslider_export", "timeslider_returnToPad"] + ["timeslider_export", "timeslider_settings", "timeslider_returnToPad"] ] } diff --git a/src/node/utils/toolbar.js b/src/node/utils/toolbar.js index a5d30f96..07b86496 100644 --- a/src/node/utils/toolbar.js +++ b/src/node/utils/toolbar.js @@ -99,12 +99,14 @@ _.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, "data-l10n-id": this.attributes.localizationId }) ) ); } }); + + SelectButton = function (attributes) { this.attributes = attributes; this.options = []; @@ -208,6 +210,12 @@ module.exports = { class: "buttonicon buttonicon-import_export" }, + timeslider_settings: { + command: "settings", + localizationId: "pad.toolbar.settings.title", + class: "buttonicon buttonicon-settings" + }, + timeslider_returnToPad: { command: "timeslider_returnToPad", localizationId: "timeslider.toolbar.returnbutton", diff --git a/src/static/css/pad.css b/src/static/css/pad.css index c9ebff4a..ff8ab5ab 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 { @@ -141,9 +137,24 @@ 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{ + /* 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; } @@ -197,6 +208,7 @@ li[data-key=showusers] > a #online_count { #editbar{ display:none; } + #editorcontainer { position: absolute; top: 37px; /* + 1px border */ @@ -742,12 +754,24 @@ 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; + cursor: pointer; +} + +.buttonicon::-moz-focus-inner { + padding: 0; + border: 0 +} + +.buttonicon:focus{ + border: 1px solid #666; } .buttonicon-bold:before { content: "\e81c"; @@ -1217,6 +1241,11 @@ input[type=checkbox] { /* End of gritter stuff */ @font-face { + font-family: opendyslexic; + src: url("../../static/font/opendyslexic.otf") format("opentype"); +} + +@font-face { font-family: "fontawesome-etherpad"; src:url("../font/fontawesome-etherpad.eot"); src:url("../font/fontawesome-etherpad.eot?#iefix") format("embedded-opentype"), @@ -1254,3 +1283,11 @@ input[type=checkbox] { -moz-osx-font-smoothing: grayscale; } +.hideControlsEditor{ + top:0px !important; +} +.hideControlsEditbar{ + display:none !important; +} + + diff --git a/src/static/css/timeslider.css b/src/static/css/timeslider.css index 49f89421..9f4e4683 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; @@ -204,12 +205,9 @@ stepper:active{ float:right; height:30px; } -#settings, -#import_export, -#embed, -#connectivity, -#users { - top: 62px; +#import_export, #settings{ + top: 115px; + position: fixed; } #import_export .popup { width: 183px; @@ -218,9 +216,7 @@ stepper:active{ border-radius: 0 0 0 6px; } #import_export { - top: 115px; width: 185px; - position: fixed; } .timeslider-bar { background: #f7f7f7; @@ -236,7 +232,7 @@ stepper:active{ .timeslider-bar #editbar { border-bottom: none; float: right; - width: 170px; + width: 180px; } .timeslider-bar h1 { margin: 5px @@ -337,3 +333,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/font/opendyslexic.otf b/src/static/font/opendyslexic.otf Binary files differnew file mode 100644 index 00000000..1a7c9d41 --- /dev/null +++ b/src/static/font/opendyslexic.otf diff --git a/src/static/js/ace.js b/src/static/js/ace.js index addc412f..c446939a 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('</head><body id="innerdocbody" class="syntax" spellcheck="false"> </body></html>'); + iframeHTML.push('</head><body id="innerdocbody" role="application" class="syntax" spellcheck="false"> </body></html>'); // Expose myself to global for my child frame. var thisFunctionsName = "ChildAccessibleAce2Editor"; @@ -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\ @@ -319,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/ace2_inner.js b/src/static/js/ace2_inner.js index 14ebc404..cf062d26 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3618,6 +3618,8 @@ function Ace2Inner(){ var charCode = evt.charCode; var keyCode = evt.keyCode; var which = evt.which; + var altKey = evt.altKey; + var shiftKey = evt.shiftKey; // prevent ESC key if (keyCode == 27) @@ -3658,7 +3660,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")); @@ -3689,6 +3690,101 @@ function Ace2Inner(){ evt:evt }); specialHandled = (specialHandledInHook&&specialHandledInHook.length>0)?specialHandledInHook[0]:specialHandled; + 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(); + $(this).blur(); + firstEditbarElement.focus(); + evt.preventDefault(); + } + if ((!specialHandled) && altKey && keyCode == 67){ + // Alt c focuses on the Chat window + $(this).blur(); + parent.parent.chat.show(); + parent.parent.chat.focus(); + evt.preventDefault(); + } + 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; + + // TODO: support selection ranges + // 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); + + 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); + } + + } + + } + + // 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: 'Line Authors', + // (string | mandatory) the text inside the notification + 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 + time: '4000' + }); + } if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8) { // "delete" key; in mozilla, if we're at the beginning of a line, normalize now, diff --git a/src/static/js/broadcast_slider.js b/src/static/js/broadcast_slider.js index 7f0e48bc..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; @@ -330,7 +335,6 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) } } else if (code == 32) playpause(); - }); $(window).resize(function() diff --git a/src/static/js/chat.js b/src/static/js/chat.js index 811b1320..42cd50f4 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() { @@ -36,6 +37,14 @@ var chat = (function() chatMentions = 0; Tinycon.setBubble(0); }, + focus: function () + { + // 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 { chat.show(); @@ -205,8 +214,28 @@ 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 + } + }); + + $('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/gritter.js b/src/static/js/gritter.js index 9778707e..7f8c5b6e 100644 --- a/src/static/js/gritter.js +++ b/src/static/js/gritter.js @@ -78,7 +78,7 @@ _tpl_close: '<div class="gritter-close"></div>', _tpl_title: '<span class="gritter-title">[[title]]</span>', _tpl_item: '<div id="gritter-item-[[number]]" class="gritter-item-wrapper [[item_class]]" style="display:none"><div class="gritter-top"></div><div class="gritter-item">[[close]][[image]]<div class="[[class_name]]">[[title]]<p>[[text]]</p></div><div style="clear:both"></div></div><div class="gritter-bottom"></div></div>', - _tpl_wrap: '<div id="gritter-notice-wrapper"></div>', + _tpl_wrap: '<div id="gritter-notice-wrapper" aria-live="polite" aria-atomic="false" aria-relevant="additions" role="log"></div>', /** * Add a gritter notification to the screen diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 77bfab7f..f1de80f0 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; } }, @@ -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'; @@ -576,9 +580,18 @@ var pad = { if(padcookie.getPref("rtlIsTrue") == true){ pad.changeViewOption('rtlIsTrue', true); } - if(padcookie.getPref("useMonospaceFont") == true){ - pad.changeViewOption('useMonospaceFont', true); - } + + var fonts = ['useMonospaceFont', 'useOpenDyslexicFont', '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}); } }, diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 7d0539af..e418969e 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(); }); @@ -155,6 +156,10 @@ var padeditbar = (function() }); }); + $('body:not(#editorcontainerbox)').on("keydown", function(evt){ + bodyKeyEvent(evt); + }); + $('#editbar').show(); this.redrawHeight(); @@ -300,6 +305,72 @@ var padeditbar = (function() } }; + var editbarPosition = 0; + + 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.altKey) || evt.keyCode === 27){ + 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; + + // 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; + + 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(); + } + } + + } + function aceAttributeCommand(cmd, ace) { ace.ace_toggleAttributeOnSelection(cmd); } @@ -311,10 +382,36 @@ var padeditbar = (function() toolbar.registerDropdownCommand("import_export"); toolbar.registerDropdownCommand("embed"); + toolbar.registerCommand("settings", function () { + toolbar.toggleDropDown("settings", function(){ + $('#options-stickychat').focus(); + }); + }); + + toolbar.registerCommand("import_export", function () { + toolbar.toggleDropDown("import_export", function(){ + // If Import file input exists then focus on it.. + if($('#importfileinput').length !== 0){ + setTimeout(function(){ + $('#importfileinput').focus(); + }, 100); + }else{ + $('.exportlink').first().focus(); + } + }); + }); + + toolbar.registerCommand("showusers", function () { + toolbar.toggleDropDown("users", function(){ + $('#myusernameedit').focus(); + }); + }); + toolbar.registerCommand("embed", function () { toolbar.setEmbedLinks(); - $('#linkinput').focus().select(); - toolbar.toggleDropDown("embed"); + toolbar.toggleDropDown("embed", function(){ + $('#linkinput').focus().select(); + }); }); toolbar.registerCommand("savedRevision", function () { diff --git a/src/static/js/pad_editor.js b/src/static/js/pad_editor.js index b73409ff..b1ea09f7 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', 'useOpenDyslexicFont', '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 <input>s // also, a value which has been set by the user will be not overwritten since a user-edited <input> // 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) + 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 === "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"); + 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){ + self.ace.setProperty("textface", "Arial, sans-serif"); + // $("#viewfontmenu").val("normal"); + } - v = getOption('useMonospaceFont', false); - self.ace.setProperty("textface", (v ? "monospace" : "Arial, sans-serif")); - $("#viewfontmenu").val(v ? "monospace" : "normal"); }, dispose: function() { 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 diff --git a/src/static/js/timeslider.js b/src/static/js/timeslider.js index ec237df5..75c20022 100644 --- a/src/static/js/timeslider.js +++ b/src/static/js/timeslider.js @@ -157,6 +157,38 @@ 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")); + + // font family change + $("#viewfontmenu").change(function(){ + var font = $("#viewfontmenu").val(); + if(font === "monospace") setFont("Courier new"); + if(font === "opendyslexic") setFont("OpenDyslexic"); + if(font === "comicsans") setFont("Comic Sans MS"); + if(font === "georgia") setFont("Georgia"); + if(font === "impact") setFont("Impact"); + if(font === "lucida") setFont("Lucida"); + if(font === "lucidasans") setFont("Lucida Sans Unicode"); + if(font === "palatino") setFont("Palatino Linotype"); + if(font === "tahoma") setFont("Tahoma"); + if(font === "timesnewroman") setFont("Times New Roman"); + if(font === "trebuchet") setFont("Trebuchet MS"); + if(font === "verdana") setFont("Verdana"); + if(font === "symbol") setFont("Symbol"); + if(font === "webdings") setFont("Webdings"); + if(font === "wingdings") setFont("Wingdings"); + if(font === "sansserif") setFont("MS Sans Serif"); + if(font === "serif") setFont("MS Serif"); + }); + +} + +function setFont(font){ + $('#padcontent').css("font-family", font); } exports.baseURL = ''; 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 @@ <div id="wrapper"> <% e.begin_block("indexWrapper"); %> <div id="inner"> - <div id="button" onclick="go2Random()" data-l10n-id="index.newPad"></div> - <div id="label" data-l10n-id="index.createOpenPad"></div> + <buttOn id="button" onclick="go2Random()" data-l10n-id="index.newPad"></button> + <label id="label" for="padname" data-l10n-id="index.createOpenPad"></label> <form action="#" onsubmit="go2Name();return false;"> <input type="text" id="padname" autofocus x-webkit-speech> <button type="submit">OK</button> diff --git a/src/templates/pad.html b/src/templates/pad.html index 7c7257cc..dd260414 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -56,17 +56,17 @@ <!-- head and body had been removed intentionally --> <% e.begin_block("body"); %> - <div id="editbar" class="toolbar"> + <div id="editbar" class="toolbar" title="Toolbar (Alt F9)"> <div id="overlay"> <div id="overlay-inner"></div> </div> - <ul class="menu_left"> + <ul class="menu_left" role="toolbar"> <% e.begin_block("editbarMenuLeft"); %> <%- toolbar.menu(settings.toolbar.left) %> <% e.end_block(); %> </ul> - <ul class="menu_right"> + <ul class="menu_right" role="toolbar"> <% e.begin_block("editbarMenuRight"); %> <%- toolbar.menu(settings.toolbar.right) %> <% e.end_block(); %> @@ -88,7 +88,7 @@ <div id="myusernameform"><input type="text" id="myusernameedit" disabled="disabled" data-l10n-id="pad.userlist.entername"></div> <div id="mystatusform"><input type="text" id="mystatusedit" disabled="disabled"></div> </div> - <div id="otherusers"> + <div id="otherusers" aria-role="document"> <div id="guestprompts"></div> <table id="otheruserstable" cellspacing="0" cellpadding="0" border="0"> <tr><td></td></tr> @@ -160,6 +160,22 @@ <select id="viewfontmenu"> <option value="normal" data-l10n-id="pad.settings.fontType.normal"></option> <option value="monospace" data-l10n-id="pad.settings.fontType.monospaced"></option> + <option value="opendyslexic" data-l10n-id="pad.settings.fontType.opendyslexic"></option> + <option value="comicsans" data-l10n-id="pad.settings.fontType.comicsans"></option> + <option value="georgia" data-l10n-id="pad.settings.fontType.georgia"></option> + <option value="impact" data-l10n-id="pad.settings.fontType.impact"></option> + <option value="lucida" data-l10n-id="pad.settings.fontType.lucida"></option> + <option value="lucidasans" data-l10n-id="pad.settings.fontType.lucidasans"></option> + <option value="palatino" data-l10n-id="pad.settings.fontType.palatino"></option> + <option value="tahoma" data-l10n-id="pad.settings.fontType.tahoma"></option> + <option value="timesnewroman" data-l10n-id="pad.settings.fontType.timesnewroman"></option> + <option value="trebuchet" data-l10n-id="pad.settings.fontType.trebuchet"></option> + <option value="verdana" data-l10n-id="pad.settings.fontType.verdana"></option> + <option value="symbol" data-l10n-id="pad.settings.fontType.symbol"></option> + <option value="webdings" data-l10n-id="pad.settings.fontType.webdings"></option> + <option value="wingdings" data-l10n-id="pad.settings.fontType.wingdings"></option> + <option value="sansserif" data-l10n-id="pad.settings.fontType.sansserif"></option> + <option value="serif" data-l10n-id="pad.settings.fontType.serif"></option> </select> </td> </tr> @@ -306,7 +322,7 @@ <% e.end_block(); %> </div> - <div id="chaticon" onclick="chat.show();return false;"> + <div id="chaticon" onclick="chat.show();return false;" title="Chat (Alt C)"> <span id="chatlabel" data-l10n-id="pad.chat"></span> <span class="buttonicon buttonicon-chat"></span> <span id="chatcounter">0</span> @@ -317,7 +333,7 @@ <a id="titlecross" onClick="chat.hide();return false;">- </a> <a id="titlesticky" onClick="chat.stickToScreen(true);$('#options-stickychat').prop('checked', true);return false;" title="Stick chat to screen">█ </a> </div> - <div id="chattext" class="authorColors"> + <div id="chattext" class="authorColors" aria-live="polite" aria-relevant="additions removals text" role="log" aria-atomic="false"> <div alt="loading.." id="chatloadmessagesball" class="chatloadmessages loadingAnimation" align="top"></div> <button id="chatloadmessagesbutton" class="chatloadmessages" data-l10n-id="pad.chat.loadmessages"></button> </div> diff --git a/src/templates/timeslider.html b/src/templates/timeslider.html index a619c702..6ec27c05 100644 --- a/src/templates/timeslider.html +++ b/src/templates/timeslider.html @@ -61,11 +61,11 @@ <div id="ui-slider-bar"></div> </div> <div id="playpause_button"> - <div id="playpause_button_icon" class=""></div> + <button id="playpause_button_icon" class=""></button> </div> <div id="steppers"> - <div class="stepper" id="leftstep"></div> - <div class="stepper" id="rightstep"></div> + <button class="stepper" id="leftstep"></button> + <button class="stepper" id="rightstep"></button> </div> </div> @@ -176,11 +176,41 @@ <% e.end_block(); %> </div> +<div class="popup" id="settings"> + <tr> + <td> + <label for="viewfontmenu" data-l10n-id="pad.settings.fontType">Font type:</label> + </td> + <td> + <select id="viewfontmenu"> + <option value="normal" data-l10n-id="pad.settings.fontType.normal"></option> + <option value="monospace" data-l10n-id="pad.settings.fontType.monospaced"></option> + <option value="opendyslexic" data-l10n-id="pad.settings.fontType.opendyslexic"></option> + <option value="comicsans" data-l10n-id="pad.settings.fontType.comicsans"></option> + <option value="georgia" data-l10n-id="pad.settings.fontType.georgia"></option> + <option value="impact" data-l10n-id="pad.settings.fontType.impact"></option> + <option value="lucida" data-l10n-id="pad.settings.fontType.lucida"></option> + <option value="lucidasans" data-l10n-id="pad.settings.fontType.lucidasans"></option> + <option value="palatino" data-l10n-id="pad.settings.fontType.palatino"></option> + <option value="tahoma" data-l10n-id="pad.settings.fontType.tahoma"></option> + <option value="timesnewroman" data-l10n-id="pad.settings.fontType.timesnewroman"></option> + <option value="trebuchet" data-l10n-id="pad.settings.fontType.trebuchet"></option> + <option value="verdana" data-l10n-id="pad.settings.fontType.verdana"></option> + <option value="symbol" data-l10n-id="pad.settings.fontType.symbol"></option> + <option value="webdings" data-l10n-id="pad.settings.fontType.webdings"></option> + <option value="wingdings" data-l10n-id="pad.settings.fontType.wingdings"></option> + <option value="sansserif" data-l10n-id="pad.settings.fontType.sansserif"></option> + <option value="serif" data-l10n-id="pad.settings.fontType.serif"></option> + </select> + </td> + </tr> +</div> + <!-- export code --> <div id="import_export"> - <div id="export" class="popup"> <p data-l10n-id="timeslider.exportCurrent"></p> + <a id="exportetherpada" target="_blank" class="exportlink"><div class="exporttype" id="exportetherpad" data-l10n-id="pad.importExport.exportetherpad"></div></a> <a id="exporthtmla" target="_blank" class="exportlink"><div class="exporttype" id="exporthtml" data-l10n-id="pad.importExport.exporthtml"></div></a> <a id="exportplaina" target="_blank" class="exportlink"><div class="exporttype" id="exportplain" data-l10n-id="pad.importExport.exportplain"></div></a> <a id="exportworda" target="_blank" class="exportlink"><div class="exporttype" id="exportword" data-l10n-id="pad.importExport.exportword"></div></a> 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(); }); |