summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/locales/en.json21
-rw-r--r--src/node/handler/ImportHandler.js6
-rw-r--r--src/node/utils/Settings.js2
-rw-r--r--src/node/utils/toolbar.js10
-rw-r--r--src/static/css/pad.css49
-rw-r--r--src/static/css/timeslider.css32
-rw-r--r--src/static/font/opendyslexic.otfbin0 -> 48076 bytes
-rw-r--r--src/static/js/ace.js4
-rw-r--r--src/static/js/ace2_inner.js98
-rw-r--r--src/static/js/broadcast_slider.js6
-rw-r--r--src/static/js/chat.js31
-rw-r--r--src/static/js/gritter.js2
-rw-r--r--src/static/js/pad.js21
-rw-r--r--src/static/js/pad_editbar.js101
-rw-r--r--src/static/js/pad_editor.js72
-rw-r--r--src/static/js/pad_userlist.js24
-rw-r--r--src/static/js/timeslider.js32
-rw-r--r--src/templates/index.html8
-rw-r--r--src/templates/pad.html28
-rw-r--r--src/templates/timeslider.html38
-rw-r--r--tests/frontend/specs/font_type.js2
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
new file mode 100644
index 00000000..1a7c9d41
--- /dev/null
+++ b/src/static/font/opendyslexic.otf
Binary files differ
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">&nbsp;</body></html>');
+ iframeHTML.push('</head><body id="innerdocbody" role="application" class="syntax" spellcheck="false">&nbsp;</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;">-&nbsp;</a>
<a id="titlesticky" onClick="chat.stickToScreen(true);$('#options-stickychat').prop('checked', true);return false;" title="Stick chat to screen">█&nbsp;&nbsp;</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();
});