From a4f2ebe57ee304ca5d8d415e4f4f1bab443f9fb8 Mon Sep 17 00:00:00 2001 From: jdittrich Date: Wed, 26 Mar 2014 18:22:41 +0100 Subject: [PATCH 01/58] Update package.json updated the underscore version number to 1.5.1 (from 1.3.1). Not lifted to most current version because frontend tests broke from 1.5.2 upwards. --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index f47ec474..d8aa26e9 100644 --- a/src/package.json +++ b/src/package.json @@ -34,7 +34,7 @@ "semver" : "1.0.13", "security" : "1.0.0", "tinycon" : "0.0.1", - "underscore" : "1.3.1", + "underscore" : "1.5.1", "unorm" : "1.0.0", "languages4translatewiki" : "0.1.3", "swagger-node-express" : "1.2.3", From 287a7805c9c47dea2290ea8492df7e50155862f3 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sat, 9 Aug 2014 14:05:04 +0200 Subject: [PATCH 02/58] Fix position of import/export popup in timeslider --- src/static/css/timeslider.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/static/css/timeslider.css b/src/static/css/timeslider.css index f97d4f2b..9f5b570d 100644 --- a/src/static/css/timeslider.css +++ b/src/static/css/timeslider.css @@ -168,8 +168,9 @@ width: 185px } #importexport { - top: 118px; + top: 100px; width: 185px; + position: fixed; } .timeslider-bar { background: #f7f7f7; From 0d95c8d1ec51b5bbb3e1f6c3ae8f36e087298f18 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sun, 14 Sep 2014 20:26:35 +0200 Subject: [PATCH 03/58] Revert change on position of imp/exp overlay --- src/static/css/timeslider.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/css/timeslider.css b/src/static/css/timeslider.css index 9f5b570d..87944a87 100644 --- a/src/static/css/timeslider.css +++ b/src/static/css/timeslider.css @@ -168,7 +168,7 @@ width: 185px } #importexport { - top: 100px; + top: 118px; width: 185px; position: fixed; } From 8af34a2295f2ff85cf0bd3212ce12da11a7d0756 Mon Sep 17 00:00:00 2001 From: Prateek Saxena Date: Tue, 14 Oct 2014 18:14:47 +0530 Subject: [PATCH 04/58] Replace "-" with "+" in tooltips with keyboard shortcuts Ctrl-Shift-L seems counter intuitive as you have to press the keys together. --- src/locales/en.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index 9f9cea84..d9b98389 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -2,16 +2,16 @@ "index.newPad": "New Pad", "index.createOpenPad": "or create/open a Pad with the name:", - "pad.toolbar.bold.title": "Bold (Ctrl-B)", - "pad.toolbar.italic.title": "Italic (Ctrl-I)", - "pad.toolbar.underline.title": "Underline (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Strikethrough (Ctrl-5)", - "pad.toolbar.ol.title": "Ordered list (Ctrl-Shift-N)", - "pad.toolbar.ul.title": "Unordered List (Ctrl-Shift-L)", + "pad.toolbar.bold.title": "Bold (Ctrl+B)", + "pad.toolbar.italic.title": "Italic (Ctrl+I)", + "pad.toolbar.underline.title": "Underline (Ctrl+U)", + "pad.toolbar.strikethrough.title": "Strikethrough (Ctrl+5)", + "pad.toolbar.ol.title": "Ordered list (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Unordered List (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Indent (TAB)", "pad.toolbar.unindent.title": "Outdent (Shift+TAB)", - "pad.toolbar.undo.title": "Undo (Ctrl-Z)", - "pad.toolbar.redo.title": "Redo (Ctrl-Y)", + "pad.toolbar.undo.title": "Undo (Ctrl+Z)", + "pad.toolbar.redo.title": "Redo (Ctrl+Y)", "pad.toolbar.clearAuthorship.title": "Clear Authorship Colors", "pad.toolbar.import_export.title": "Import/Export from/to different file formats", "pad.toolbar.timeslider.title": "Timeslider", From 6f5f89bc6bea456cf8af9d034780b5b259ca74a5 Mon Sep 17 00:00:00 2001 From: Prateek Saxena Date: Tue, 14 Oct 2014 18:36:26 +0530 Subject: [PATCH 05/58] Use 'evt.shiftKey' instead of matching 'charCodes' The shortcut wasn't running consistently and was blocking 'Cmd+L' on Chrome 38. Instead of going to the location bar it would tooggle the list. Strangely, it did not override 'Cmd+N'. Using `evt.shiftKey` instead of matching the `charCode` to the uppercase letter solves the problem. --- 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 5244cbca..fb6dd080 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3749,7 +3749,7 @@ function Ace2Inner(){ toggleAttributeOnSelection('strikethrough'); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which) == "L" && (evt.metaKey || evt.ctrlKey)) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "l" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) { // cmd-shift-L (unorderedlist) fastIncorp(9); @@ -3757,7 +3757,7 @@ function Ace2Inner(){ doInsertUnorderedList() specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which) == "N" && (evt.metaKey || evt.ctrlKey)) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "n" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) { // cmd-shift-N (orderedlist) fastIncorp(9); From 2dd874376a1d03de8998751ca5dac9d1818705cc Mon Sep 17 00:00:00 2001 From: Prateek Saxena Date: Tue, 14 Oct 2014 18:42:51 +0530 Subject: [PATCH 06/58] Update frontend language tests for new keyboard shortcut convention 8af34a2295f2ff85cf0b introduced a failing test frontend test- https://travis-ci.org/ether/etherpad-lite/builds/37931978 This commit updates both the German and English strings even though the German locale files haven't been updated yet. The tests will continue to fail but will stop as soon as translatewiki catches up. --- tests/frontend/specs/language.js | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/frontend/specs/language.js b/tests/frontend/specs/language.js index d607ff98..41a19d11 100644 --- a/tests/frontend/specs/language.js +++ b/tests/frontend/specs/language.js @@ -11,31 +11,31 @@ describe("Language select and change", function(){ helper.newPad(cb); this.timeout(60000); }); - + // Destroy language cookies it("makes text german", function(done) { var inner$ = helper.padInner$; var chrome$ = helper.padChrome$; - + //click on the settings button to make settings visible var $settingsButton = chrome$(".buttonicon-settings"); $settingsButton.click(); - + //click the language button var $language = chrome$("#languagemenu"); var $languageoption = $language.find("[value=de]"); - + //select german $languageoption.attr('selected','selected'); $language.change(); - - helper.waitFor(function() { + + helper.waitFor(function() { return chrome$(".buttonicon-bold").parent()[0]["title"] == "Fett (Strg-B)"; }) .done(function(){ //get the value of the bold button var $boldButton = chrome$(".buttonicon-bold").parent(); - + //get the title of the bold button var boldButtonTitle = $boldButton[0]["title"]; @@ -44,58 +44,58 @@ describe("Language select and change", function(){ done(); }); }); - + it("makes text English", function(done) { var inner$ = helper.padInner$; var chrome$ = helper.padChrome$; - + //click on the settings button to make settings visible var $settingsButton = chrome$(".buttonicon-settings"); $settingsButton.click(); - + //click the language button var $language = chrome$("#languagemenu"); //select english $language.val("en"); $language.change(); - + //get the value of the bold button var $boldButton = chrome$(".buttonicon-bold").parent(); - helper.waitFor(function() { return $boldButton[0]["title"] != "Fett (Strg-B)";}) + helper.waitFor(function() { return $boldButton[0]["title"] != "Fett (Strg+B)";}) .done(function(){ - + //get the value of the bold button var $boldButton = chrome$(".buttonicon-bold").parent(); - + //get the title of the bold button var boldButtonTitle = $boldButton[0]["title"]; - + //check if the language is now English - expect(boldButtonTitle).to.be("Bold (Ctrl-B)"); + expect(boldButtonTitle).to.be("Bold (Ctrl+B)"); done(); - + }); }); - + it("changes direction when picking an rtl lang", function(done) { var inner$ = helper.padInner$; var chrome$ = helper.padChrome$; - + //click on the settings button to make settings visible var $settingsButton = chrome$(".buttonicon-settings"); $settingsButton.click(); - + //click the language button var $language = chrome$("#languagemenu"); var $languageoption = $language.find("[value=ar]"); - + //select arabic // $languageoption.attr('selected','selected'); // Breaks the test.. $language.val("ar"); $languageoption.change(); - helper.waitFor(function() { + helper.waitFor(function() { return chrome$("html")[0]["dir"] != 'ltr'; }) .done(function(){ From 086bf83e6ccd4e576b579b3fb718ed10e5f6daee Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Mon, 20 Oct 2014 18:57:22 +0200 Subject: [PATCH 07/58] Localisation updates from https://translatewiki.net. --- src/locales/bcc.json | 122 +++++++++++++++++++++++++++++++++++++++++++ src/locales/lki.json | 75 ++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 src/locales/bcc.json create mode 100644 src/locales/lki.json diff --git a/src/locales/bcc.json b/src/locales/bcc.json new file mode 100644 index 00000000..10349ae5 --- /dev/null +++ b/src/locales/bcc.json @@ -0,0 +1,122 @@ +{ + "@metadata": { + "authors": [ + "Baloch Afghanistan" + ] + }, + "index.newPad": "دفترچه یادداشت تازه", + "index.createOpenPad": "یا ایجاد/بازکردن یک دفترچه یادداشت با نام:", + "pad.toolbar.bold.title": "پررنگ (Ctrl-B)", + "pad.toolbar.italic.title": "کج (Ctrl-I)", + "pad.toolbar.underline.title": "زیرخط (Ctrl-U)", + "pad.toolbar.strikethrough.title": "خط خورده", + "pad.toolbar.ol.title": "فهرست مرتب شده", + "pad.toolbar.ul.title": "فهرست مرتب نشده", + "pad.toolbar.indent.title": "تورفتگی (TAB)", + "pad.toolbar.unindent.title": "بیرون رفتگی (Shift+TAB)", + "pad.toolbar.undo.title": "باطل‌کردن (Ctrl-Z)", + "pad.toolbar.redo.title": "از نو (Ctrl-Y)", + "pad.toolbar.clearAuthorship.title": "پاک‌کردن رنگ‌های نویسندگی", + "pad.toolbar.import_export.title": "درون‌ریزی/برون‌ریزی از/به قالب‌های مختلف", + "pad.toolbar.timeslider.title": "لغزندهٔ زمان", + "pad.toolbar.savedRevision.title": "ذخیره‌سازی نسخه", + "pad.toolbar.settings.title": "تنظیمات", + "pad.toolbar.embed.title": "اشتراک و جاسازی این دفترچه یادداشت", + "pad.toolbar.showusers.title": "نمایش کاربران در این دفترچه یادداشت", + "pad.colorpicker.save": "زاپاس کورتین", + "pad.colorpicker.cancel": "کنسیل", + "pad.loading": "...بار بیت", + "pad.passwordRequired": "برای دسترسی به این دفترچه یادداشت نیاز به یک گذرواژه دارید", + "pad.permissionDenied": "شرمنده، شما را اجازت په دسترسی ای صفحه نیست.", + "pad.wrongPassword": "گذرواژه‌ی شما درست نیست", + "pad.settings.padSettings": "تنظیمات دفترچه یادداشت", + "pad.settings.myView": "نمای من", + "pad.settings.stickychat": "گفتگو همیشه روی صفحه نمایش باشد", + "pad.settings.colorcheck": "رنگ‌های نویسندگی", + "pad.settings.linenocheck": "شماره‌ی خطوط", + "pad.settings.rtlcheck": "خواندن محتوا از راست به چپ؟", + "pad.settings.fontType": "نوع قلم:", + "pad.settings.fontType.normal": "نرمال", + "pad.settings.fontType.monospaced": "Monospace", + "pad.settings.globalView": "نمای سراسری", + "pad.settings.language": "زبان:", + "pad.importExport.import_export": "درون‌ریزی/برون‌ریزی", + "pad.importExport.import": "بارگذاری پرونده‌ی متنی یا سند", + "pad.importExport.importSuccessful": "موفقیت آمیز بود!", + "pad.importExport.export": "برون‌ریزی این دفترچه یادداشت با قالب:", + "pad.importExport.exporthtml": "HTML", + "pad.importExport.exportplain": "سادگین متن", + "pad.importExport.exportword": "Microsoft Word", + "pad.importExport.exportpdf": "PDF", + "pad.importExport.exportopen": "ODF (قالب سند باز)", + "pad.importExport.exportdokuwiki": "DokuWiki", + "pad.importExport.abiword.innerHTML": "شما تنها می‌توانید از قالب متن ساده یا اچ‌تی‌ام‌ال درون‌ریزی کنید. برای بیشتر شدن ویژگی‌های درون‌ریزی پیشرفته AbiWord را نصب کنید.", + "pad.modals.connected": "متصل شد.", + "pad.modals.reconnecting": "در حال اتصال دوباره به دفترچه یادداشت شما..", + "pad.modals.forcereconnect": "واداشتن به اتصال دوباره", + "pad.modals.userdup": "در پنجره‌ای دیگر باز شد", + "pad.modals.userdup.explanation": "گمان می‌رود این دفترچه یادداشت در بیش از یک پنجره‌ی مرورگر باز شده‌است.", + "pad.modals.userdup.advice": "برای استفاده از این پنجره دوباره وصل شوید.", + "pad.modals.unauth": "مجاز نیست", + "pad.modals.unauth.explanation": "دسترسی شما در حین مشاهده‌ی این برگه تغییر یافته‌است. دوباره متصل شوید.", + "pad.modals.looping.explanation": "مشکلاتی ارتباطی با سرور همگام‌سازی وجود دارد.", + "pad.modals.looping.cause": "شاید شما از طریق یک فایروال یا پروکسی ناسازگار متصل شده‌اید.", + "pad.modals.initsocketfail": "سرور در دسترس نیست.", + "pad.modals.initsocketfail.explanation": "نمی‌توان به سرور همگام سازی وصل شد.", + "pad.modals.initsocketfail.cause": "شاید این به خاطر مشکلی در مرورگر یا اتصال اینترنتی شما باشد.", + "pad.modals.slowcommit.explanation": "سرور پاسخ نمی‌دهد.", + "pad.modals.slowcommit.cause": "این می‌تواند به خاطر مشکلاتی در اتصال به شبکه باشد.", + "pad.modals.badChangeset.explanation": "ویرایشی که شما انجام داده‌اید توسط سرور همگام‌سازی نادرست طیقه‌بندی شده‌است.", + "pad.modals.badChangeset.cause": "این می‌تواند به دلیل پیکربندی اشتباه یا سایر رفتارهای غیرمنتظره باشد. اگر فکر می‌کنید این یک خطا است لطفاً با مدیر خدمت تماس بگیرید. برای ادامهٔ ویرایش سعی کنید که دوباره متصل شوید.", + "pad.modals.corruptPad.explanation": "پدی که شما سعی دارید دسترسی پیدا کنید خراب است.", + "pad.modals.corruptPad.cause": "این احتمالاً به دلیل تنظیمات اشتباه کارساز یا سایر رفتارهای غیرمنتظره است. لطفاً با مدیر خدمت تماس حاصل کنید.", + "pad.modals.deleted": "پاک کورتین", + "pad.modals.deleted.explanation": "این دفترچه یادداشت پاک شده‌است.", + "pad.modals.disconnected": "اتصال شما قطع شده‌است.", + "pad.modals.disconnected.explanation": "اتصال به سرور قطع شده‌است.", + "pad.modals.disconnected.cause": "ممکن است سرور در دسترس نباشد. اگر این مشکل باز هم رخ داد مدیر حدمت را آگاه کنید.", + "pad.share": "به اشتراک‌گذاری این دفترچه یادداشت", + "pad.share.readonly": "فقط خواندنی", + "pad.share.link": "پیوند", + "pad.share.emebdcode": "جاسازی نشانی", + "pad.chat": "گفتگو", + "pad.chat.title": "بازکردن گفتگو برای این دفترچه یادداشت", + "pad.chat.loadmessages": "بارگیری پیام‌های بیشتر", + "timeslider.pageTitle": "لغزندهٔ زمان {{appTitle}}", + "timeslider.toolbar.returnbutton": "بازگشت به دفترچه یادداشت", + "timeslider.toolbar.authors": "نویسوک:", + "timeslider.toolbar.authorsList": "بدون نویسنده", + "timeslider.toolbar.exportlink.title": "درگیزگ", + "timeslider.exportCurrent": "برون‌ریزی نگارش کنونی به عنوان:", + "timeslider.version": "نگارش {{version}}", + "timeslider.saved": "{{month}} {{day}}، {{year}} ذخیره شد", + "timeslider.dateformat": "{{month}}/{{day}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}", + "timeslider.month.january": "جنوری", + "timeslider.month.february": "پیبروری", + "timeslider.month.march": "مارچ", + "timeslider.month.april": "آپریل", + "timeslider.month.may": "می", + "timeslider.month.june": "جون", + "timeslider.month.july": "جولای", + "timeslider.month.august": "آگوست", + "timeslider.month.september": "سپٹامبر", + "timeslider.month.october": "اکتوبر", + "timeslider.month.november": "نوامبر", + "timeslider.month.december": "دسمبر", + "timeslider.unnamedauthors": "{{num}} نویسندهٔ بی‌نام", + "pad.savedrevs.marked": "این بازنویسی هم اکنون به عنوان ذخیره شده علامت‌گذاری شد", + "pad.userlist.entername": "وتی یوزرنامء بلک ات", + "pad.userlist.unnamed": "بدون نام", + "pad.userlist.guest": "مهمان", + "pad.userlist.deny": "رد کردن", + "pad.userlist.approve": "تایید", + "pad.editbar.clearcolors": "رنگ نویسندگی از همه‌ی سند پاک شود؟", + "pad.impexp.importbutton": "هم اکنون درون‌ریزی کن", + "pad.impexp.importing": "در حال درون‌ریزی...", + "pad.impexp.confirmimport": "با درون‌ریزی یک پرونده نوشتهٔ کنونی دفترچه پاک می‌شود. آیا می‌خواهید ادامه دهید؟", + "pad.impexp.convertFailed": "ما نمی‌توانیم این پرونده را درون‌ریزی کنیم. خواهشمندیم قالب دیگری برای سندتان انتخاب کرده یا بصورت دستی آنرا کپی کنید", + "pad.impexp.uploadFailed": "آپلود انجام نشد، دوباره تلاش کنید", + "pad.impexp.importfailed": "درون‌ریزی انجام نشد", + "pad.impexp.copypaste": "کپی پیست کنید", + "pad.impexp.exportdisabled": "برون‌ریزی با قالب {{type}} از کار افتاده است. برای جزئیات بیشتر با مدیر سیستمتان تماس بگیرید." +} diff --git a/src/locales/lki.json b/src/locales/lki.json new file mode 100644 index 00000000..b7436298 --- /dev/null +++ b/src/locales/lki.json @@ -0,0 +1,75 @@ +{ + "@metadata": { + "authors": [ + "Hosseinblue" + ] + }, + "index.newPad": "تازۀpad", + "index.createOpenPad": ":ئۀ وسیلۀ نؤمpadسازین/وآز کردن یه گلۀ", + "pad.toolbar.bold.title": "پررنگ-تئژ(Ctrl-B)", + "pad.toolbar.italic.title": "ایتالیک (Ctrl-I)", + "pad.toolbar.underline.title": "ژئر خطی(Ctrl-U)", + "pad.toolbar.strikethrough.title": "خط هوواردئ", + "pad.toolbar.ol.title": "فئرست رزگی-مرتب", + "pad.toolbar.ul.title": "نۀچنریا-نامرتب", + "pad.toolbar.indent.title": "تورفتگی-ئه نؤم چئن (TAB)", + "pad.toolbar.unindent.title": "(Shift+TAB)بیرون آمدگی-درچئن", + "pad.toolbar.undo.title": "گِلّا دائن-ئآهۀتن(Ctrl-Z)", + "pad.toolbar.redo.title": "ئۀ نوواهۀتن (Ctrl-Y)", + "pad.toolbar.clearAuthorship.title": "پاکاکردن رنگۀل تالیفی", + "pad.toolbar.import_export.title": "دربردن/ئه نؤم ئآووردن ئۀ/ئِِژ فرمتۀل گوناگون", + "pad.toolbar.timeslider.title": "اسلایدر وختی-زمانی", + "pad.toolbar.savedRevision.title": "ذخیرل دسکاریۀل", + "pad.toolbar.settings.title": "تنظیمۀل", + "pad.toolbar.embed.title": "بۀشاکردن ؤ نیائن(اشتراک ونشاندن)ئۀ نؤم سایت", + "pad.toolbar.showusers.title": "نیشان دائن کاربر ئۀ نؤم ئئ\npad", + "pad.colorpicker.save": "ذخیرۀ", + "pad.colorpicker.cancel": "ئآهووسانن-لغو", + "pad.loading": "...(loading)بارنیائن", + "pad.passwordRequired": "هؤمۀ رمزتؤنه گرۀکۀ-لازمۀ ئۀرا اتصال ئئ \npad", + "pad.wrongPassword": "رمزۀ تؤن دؤرس نیۀ", + "pad.settings.padSettings": "pad تنظیمۀل", + "pad.settings.myView": "نمایش-سئرکردن مه", + "pad.settings.stickychat": "چت همؤیشۀ ئۀ ولگۀ نمایش بوو", + "pad.settings.colorcheck": "رنگۀل تالیفی", + "pad.settings.linenocheck": "شؤمارۀل خطی", + "pad.settings.fontType": ":شئؤۀ فؤنت", + "pad.settings.fontType.normal": "عادی", + "pad.settings.fontType.monospaced": "پئنی-پهنا", + "pad.settings.globalView": "نمایش جئ هانی", + "pad.settings.language": ":زوون", + "pad.importExport.import_export": "در بردن/ئه نؤم ئآووردن", + "pad.importExport.import": "بارنیائن هر جور نوشته یا سندئ", + "pad.importExport.importSuccessful": "! موفق بی-پیرووز بی", + "pad.importExport.exporthtml": "html", + "pad.importExport.exportplain": "متن پئن-درئژ", + "pad.importExport.exportword": "مایکروسافت وورد", + "pad.importExport.exportpdf": "پی دی اف", + "pad.modals.connected": "وصل بیۀ", + "pad.modals.deleted": "پاک بیا-حذف بی", + "pad.share.readonly": "تنیا بخؤۀن", + "pad.share.link": "لینک", + "pad.chat": "گپ", + "pad.chat.loadmessages": "پئامۀلئ تر باره سۀر", + "timeslider.toolbar.exportlink.title": "در بِردن", + "timeslider.month.january": "دی)نورووژ)", + "timeslider.month.february": "(خاکه لێه(بهمن", + "timeslider.month.march": "(مانگ ئێد(اسفندگان", + "timeslider.month.april": "(په نجه(فروردین", + "timeslider.month.may": "(مێرێان(اردیبهشت", + "timeslider.month.june": "(گاکوور(خرداد", + "timeslider.month.july": "تیر)ئاگرانی)", + "timeslider.month.august": "مرداد)مردار)", + "timeslider.month.september": "(ماڵه ژێر(شهریور", + "timeslider.month.october": "(ماڵه ژێر دوماێنه(مهر", + "timeslider.month.november": "آبان)تویل ته کن)", + "timeslider.month.december": "(مانگه سێه(آذر", + "pad.userlist.entername": "نؤم تؤن وارد کۀن", + "pad.userlist.unnamed": "بئ نؤم", + "pad.userlist.guest": "مئمان", + "pad.userlist.deny": "رد کردن", + "pad.userlist.approve": "راووا داشتن-تصویب کردن", + "pad.impexp.importbutton": "ایسۀ وارد کۀ", + "pad.impexp.importing": "...وارد مۀهه", + "pad.impexp.importfailed": "وارد نؤنئ-خطای واردکردن" +} From 3fce9f83092b693e9b3ed5e4e7bb0b243f7e2b0c Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Thu, 23 Oct 2014 21:32:44 +0200 Subject: [PATCH 08/58] Localisation updates from https://translatewiki.net. --- src/locales/es.json | 6 +++--- src/locales/ja.json | 16 ++++++++-------- src/locales/pt.json | 10 ++++++---- src/locales/tr.json | 11 ++++++----- src/locales/zh-hans.json | 6 +++--- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/locales/es.json b/src/locales/es.json index 85abebf7..62e255ea 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -18,9 +18,9 @@ "pad.toolbar.bold.title": "Negrita (Ctrl-B)", "pad.toolbar.italic.title": "Cursiva (Ctrl-I)", "pad.toolbar.underline.title": "Subrayado (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Tachado", - "pad.toolbar.ol.title": "Lista ordenada", - "pad.toolbar.ul.title": "Lista desordenada", + "pad.toolbar.strikethrough.title": "Tachado (Ctrl+5)", + "pad.toolbar.ol.title": "Lista ordenada (Ctrl+Mayús+N)", + "pad.toolbar.ul.title": "Lista desordenada (Ctrl+Mayús+L)", "pad.toolbar.indent.title": "Sangría (TAB)", "pad.toolbar.unindent.title": "Eliminar sangría (Shift+TAB)", "pad.toolbar.undo.title": "Deshacer (Ctrl-Z)", diff --git a/src/locales/ja.json b/src/locales/ja.json index f9d63cd2..011c935a 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -6,16 +6,16 @@ }, "index.newPad": "新規作成", "index.createOpenPad": "または作成/編集するパッド名を入力:", - "pad.toolbar.bold.title": "太字 (Ctrl-B)", - "pad.toolbar.italic.title": "斜体 (Ctrl-I)", - "pad.toolbar.underline.title": "下線 (Ctrl-U)", - "pad.toolbar.strikethrough.title": "取り消し線", - "pad.toolbar.ol.title": "番号付きリスト", - "pad.toolbar.ul.title": "番号なしリスト", + "pad.toolbar.bold.title": "太字 (Ctrl+B)", + "pad.toolbar.italic.title": "斜体 (Ctrl+I)", + "pad.toolbar.underline.title": "下線 (Ctrl+U)", + "pad.toolbar.strikethrough.title": "取り消し線 (Ctrl+5)", + "pad.toolbar.ol.title": "番号付きリスト (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "番号なしリスト (Ctrl+Shift+L)", "pad.toolbar.indent.title": "インデント (Tab)", "pad.toolbar.unindent.title": "インデント解除 (Shift+Tab)", - "pad.toolbar.undo.title": "元に戻す (Ctrl-Z)", - "pad.toolbar.redo.title": "やり直し (Ctrl-Y)", + "pad.toolbar.undo.title": "元に戻す (Ctrl+Z)", + "pad.toolbar.redo.title": "やり直し (Ctrl+Y)", "pad.toolbar.clearAuthorship.title": "作者の色分けを消去", "pad.toolbar.import_export.title": "他の形式のファイルのインポート/エクスポート", "pad.toolbar.timeslider.title": "タイムスライダー", diff --git a/src/locales/pt.json b/src/locales/pt.json index 949bb7bc..69a4dca1 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -5,7 +5,8 @@ "Luckas", "Tuliouel", "Waldir", - "Imperadeiro98" + "Imperadeiro98", + "Macofe" ] }, "index.newPad": "Nova Nota", @@ -13,9 +14,9 @@ "pad.toolbar.bold.title": "Negrito (Ctrl-B)", "pad.toolbar.italic.title": "Itálico (Ctrl-I)", "pad.toolbar.underline.title": "Sublinhado (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Riscar", - "pad.toolbar.ol.title": "Lista ordenada", - "pad.toolbar.ul.title": "Lista desordenada", + "pad.toolbar.strikethrough.title": "Riscar (Ctrl+5)", + "pad.toolbar.ol.title": "Lista ordenada (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Lista desordenada (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Avançar (TAB)", "pad.toolbar.unindent.title": "Recuar (Shift+TAB)", "pad.toolbar.undo.title": "Desfazer (Ctrl-Z)", @@ -71,6 +72,7 @@ "pad.modals.disconnected.cause": "O servidor pode estar indisponível. Por favor, notifique o administrador de serviço se isto continuar a acontecer.", "pad.share": "Compartilhar este pad", "pad.share.readonly": "Somente para leitura", + "pad.share.link": "Ligação", "pad.chat": "Bate-papo", "pad.chat.title": "Abrir o bate-papo para este pad.", "pad.chat.loadmessages": "Carregar mais mensagens", diff --git a/src/locales/tr.json b/src/locales/tr.json index 89c1f0df..a83c7313 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -4,7 +4,8 @@ "Emperyan", "Erdemaslancan", "Joseph", - "Meelo" + "Meelo", + "Trockya" ] }, "index.newPad": "Yeni Bloknot", @@ -12,13 +13,13 @@ "pad.toolbar.bold.title": "Kalın (Ctrl-B)", "pad.toolbar.italic.title": "Eğik (Ctrl-I)", "pad.toolbar.underline.title": "Altı Çizili (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Üstü Çizili", - "pad.toolbar.ol.title": "Sıralı liste", - "pad.toolbar.ul.title": "Sırasız Liste", + "pad.toolbar.strikethrough.title": "Üstü Çizili (Ctrl+5)", + "pad.toolbar.ol.title": "Sıralı liste (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Sırasız Liste (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Girintiyi arttır (TAB)", "pad.toolbar.unindent.title": "Girintiyi azalt (Shift+TAB)", "pad.toolbar.undo.title": "Geri Al (Ctrl-Z)", - "pad.toolbar.redo.title": "Yenile (Ctrl-Y)", + "pad.toolbar.redo.title": "Yinele (Ctrl+Y)", "pad.toolbar.clearAuthorship.title": "Yazarlık Renklerini Temizle", "pad.toolbar.import_export.title": "Farklı dosya biçimlerini içeri/dışarı aktar", "pad.toolbar.timeslider.title": "Zaman Çizelgesi", diff --git a/src/locales/zh-hans.json b/src/locales/zh-hans.json index 556ab8a1..61aa99fc 100644 --- a/src/locales/zh-hans.json +++ b/src/locales/zh-hans.json @@ -18,9 +18,9 @@ "pad.toolbar.bold.title": "粗体(Ctrl-B)", "pad.toolbar.italic.title": "斜体 (Ctrl-I)", "pad.toolbar.underline.title": "下划线(Ctrl-U)", - "pad.toolbar.strikethrough.title": "删除线", - "pad.toolbar.ol.title": "有序列表", - "pad.toolbar.ul.title": "无序列表", + "pad.toolbar.strikethrough.title": "删除线(Ctrl+5)", + "pad.toolbar.ol.title": "有序列表(Ctrl+Shift+N)", + "pad.toolbar.ul.title": "无序列表(Ctrl+Shift+L)", "pad.toolbar.indent.title": "增加缩进(TAB)", "pad.toolbar.unindent.title": "减少缩进(Shift+TAB)", "pad.toolbar.undo.title": "撤消 (Ctrl-Z)", From ac2e949c3ef1e73b19f3a8bdcd1575ed563311f0 Mon Sep 17 00:00:00 2001 From: John McLear Date: Fri, 24 Oct 2014 00:13:34 +0100 Subject: [PATCH 09/58] chrome browser change wrapping type --- src/static/js/ace2_inner.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index fb6dd080..6a37ac7a 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -152,7 +152,6 @@ function Ace2Inner(){ var dmesg = noop; window.dmesg = noop; - var scheduler = parent; // hack for opera required var textFace = 'monospace'; @@ -597,6 +596,13 @@ function Ace2Inner(){ fixView(); }); }, 0); + + // Chrome can't handle the truth.. If CSS rule white-space:pre-wrap + // is true then any paste event will insert two lines.. + if(browser.chrome){ + $("#innerdocbody").css({"white-space":"normal"}); + } + } function setStyled(newVal) From 45611561e63bd47dbb58beef12318b76b5494f57 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Mon, 27 Oct 2014 18:53:33 +0100 Subject: [PATCH 10/58] Localisation updates from https://translatewiki.net. --- src/locales/fr.json | 45 +++++++++++++++++++++++---------------------- src/locales/he.json | 6 +++--- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/locales/fr.json b/src/locales/fr.json index 757cd15a..b6b1a720 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -16,7 +16,8 @@ "Rastus Vernon", "Stephane Cottin", "Tux-tn", - "Maxim21" + "Maxim21", + "Boniface" ] }, "index.newPad": "Nouveau pad", @@ -24,9 +25,9 @@ "pad.toolbar.bold.title": "Gras (Ctrl-B)", "pad.toolbar.italic.title": "Italique (Ctrl-I)", "pad.toolbar.underline.title": "Souligné (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Barré", - "pad.toolbar.ol.title": "Liste ordonnée", - "pad.toolbar.ul.title": "Liste non ordonnée", + "pad.toolbar.strikethrough.title": "Barré (Ctrl+5)", + "pad.toolbar.ol.title": "Liste ordonnée (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Liste non ordonnée (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Indenter (TAB)", "pad.toolbar.unindent.title": "Désindenter (Maj+TAB)", "pad.toolbar.undo.title": "Annuler (Ctrl-Z)", @@ -49,7 +50,7 @@ "pad.settings.stickychat": "Toujours afficher le chat", "pad.settings.colorcheck": "Couleurs d’identification", "pad.settings.linenocheck": "Numéros de lignes", - "pad.settings.rtlcheck": "Lecture de droite à gauche", + "pad.settings.rtlcheck": "Le contenu doit-il être lu de droite à gauche ?", "pad.settings.fontType": "Police :", "pad.settings.fontType.normal": "Normal", "pad.settings.fontType.monospaced": "Monospace", @@ -57,7 +58,7 @@ "pad.settings.language": "Langue :", "pad.importExport.import_export": "Importer/Exporter", "pad.importExport.import": "Charger un texte ou un document", - "pad.importExport.importSuccessful": "Réussi!", + "pad.importExport.importSuccessful": "Réussi !", "pad.importExport.export": "Exporter le pad actuel comme :", "pad.importExport.exporthtml": "HTML", "pad.importExport.exportplain": "Texte brut", @@ -83,7 +84,7 @@ "pad.modals.slowcommit.cause": "Ce problème peut venir d'une mauvaise connectivité au réseau.", "pad.modals.badChangeset.explanation": "Une modification que vous avez effectuée a été classée comme illégale par le serveur de synchronisation.", "pad.modals.badChangeset.cause": "Cela peut être dû à une mauvaise configuration du serveur ou à un autre comportement inattendu. Veuillez contacter l’administrateur du service, si vous pensez que c’est une erreur. Essayez de vous reconnecter pour continuer à modifier.", - "pad.modals.corruptPad.explanation": "Le bloc auquel vous essayez d’accéder est corrompu.", + "pad.modals.corruptPad.explanation": "Le pad auquel vous essayez d’accéder est corrompu.", "pad.modals.corruptPad.cause": "Cela peut être dû à une mauvaise configuration du serveur ou à un autre comportement inattendu. Veuillez contacter l’administrateur du service.", "pad.modals.deleted": "Supprimé.", "pad.modals.deleted.explanation": "Ce pad a été supprimé.", @@ -102,22 +103,22 @@ "timeslider.toolbar.authors": "Auteurs :", "timeslider.toolbar.authorsList": "Aucun auteur", "timeslider.toolbar.exportlink.title": "Exporter", - "timeslider.exportCurrent": "Exporter la version actuelle en :", + "timeslider.exportCurrent": "Exporter la version actuelle sous :", "timeslider.version": "Version {{version}}", "timeslider.saved": "Enregistré le {{day}} {{month}} {{year}}", "timeslider.dateformat": "{{day}}/{{month}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}", - "timeslider.month.january": "Janvier", - "timeslider.month.february": "Février", - "timeslider.month.march": "Mars", - "timeslider.month.april": "Avril", - "timeslider.month.may": "Mai", - "timeslider.month.june": "Juin", - "timeslider.month.july": "Juillet", - "timeslider.month.august": "Août", - "timeslider.month.september": "Septembre", - "timeslider.month.october": "Octobre", - "timeslider.month.november": "Novembre", - "timeslider.month.december": "Décembre", + "timeslider.month.january": "janvier", + "timeslider.month.february": "février", + "timeslider.month.march": "mars", + "timeslider.month.april": "avril", + "timeslider.month.may": "mai", + "timeslider.month.june": "juin", + "timeslider.month.july": "juillet", + "timeslider.month.august": "août", + "timeslider.month.september": "septembre", + "timeslider.month.october": "octobre", + "timeslider.month.november": "novembre", + "timeslider.month.december": "décembre", "timeslider.unnamedauthors": "{{num}} {[plural(num) one: auteur anonyme, other: auteurs anonymes ]}", "pad.savedrevs.marked": "Cette révision est maintenant marquée comme révision enregistrée", "pad.userlist.entername": "Entrez votre nom", @@ -128,10 +129,10 @@ "pad.editbar.clearcolors": "Effacer les couleurs de paternité dans tout le document ?", "pad.impexp.importbutton": "Importer maintenant", "pad.impexp.importing": "Import en cours...", - "pad.impexp.confirmimport": "Importer un fichier écrasera le texte actuel du pad. Êtes-vous sûr de vouloir le faire?", + "pad.impexp.confirmimport": "Importer un fichier écrasera le texte actuel du pad. Êtes-vous sûr de vouloir le faire ?", "pad.impexp.convertFailed": "Nous ne pouvons pas importer ce fichier. Veuillez utiliser un autre format de document ou faire un copier/coller manuel", "pad.impexp.uploadFailed": "Le téléchargement a échoué, veuillez réessayer", "pad.impexp.importfailed": "Échec de l'importation", "pad.impexp.copypaste": "Veuillez copier/coller", - "pad.impexp.exportdisabled": "Exporter au format {{type}} est désactivé. Veuillez contacter votre administrateur système pour plus de détails." + "pad.impexp.exportdisabled": "L'option d'export au format {{type}} est désactivée. Veuillez contacter votre administrateur système pour plus de détails." } diff --git a/src/locales/he.json b/src/locales/he.json index 555cb5f5..7d7f2b78 100644 --- a/src/locales/he.json +++ b/src/locales/he.json @@ -12,9 +12,9 @@ "pad.toolbar.bold.title": "בולט (Ctrl-B)", "pad.toolbar.italic.title": "נטוי (Ctrl-I)", "pad.toolbar.underline.title": "קו תחתי (Ctrl-U)", - "pad.toolbar.strikethrough.title": "קו מוחק", - "pad.toolbar.ol.title": "רשימה ממוספרת", - "pad.toolbar.ul.title": "רשימה", + "pad.toolbar.strikethrough.title": "קו מוחק (Ctrl+5)", + "pad.toolbar.ol.title": "רשימה ממוספרת (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "רשימת תבליטים (Ctrl+Shift+L)", "pad.toolbar.indent.title": "הזחה (טאב)", "pad.toolbar.unindent.title": "צמצום הזחה (שיפט–טאב)", "pad.toolbar.undo.title": "ביטול (Ctrl-Z)", From 9a01f905ebe7814db3d49e14b4703bcb47d91c17 Mon Sep 17 00:00:00 2001 From: Trevor Alexander Date: Tue, 28 Oct 2014 13:07:02 -1000 Subject: [PATCH 11/58] Added explicit reference to plugins and themes in readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 71c0b3e1..4b739729 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,10 @@ You can initially modify the settings in `settings.json`. (If you need to handle You should use a dedicated database such as "mysql", if you are planning on using etherpad-in a production environment, since the "dirtyDB" database driver is only for testing and/or development purposes. +## Plugins and themes + +Etherpad is very customizable through plugins. Instructions for installing themes and plugins can be found [here](https://github.com/ether/etherpad-lite/wiki/Available-Plugins). + ## Helpful resources The [wiki](https://github.com/ether/etherpad-lite/wiki) is your one-stop resource for Tutorials and How-to's, really check it out! Also, feel free to improve these wiki pages. From 69b17f508876731c415a40690650645c69ae64e4 Mon Sep 17 00:00:00 2001 From: talexand Date: Tue, 28 Oct 2014 15:13:05 -1000 Subject: [PATCH 12/58] changed link wording for readme plugin reference --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b739729..3ed1077f 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ You should use a dedicated database such as "mysql", if you are planning on usin ## Plugins and themes -Etherpad is very customizable through plugins. Instructions for installing themes and plugins can be found [here](https://github.com/ether/etherpad-lite/wiki/Available-Plugins). +Etherpad is very customizable through plugins. Instructions for installing themes and plugins can be found in [the plugin wiki article](https://github.com/ether/etherpad-lite/wiki/Available-Plugins). ## Helpful resources The [wiki](https://github.com/ether/etherpad-lite/wiki) is your one-stop resource for Tutorials and How-to's, really check it out! Also, feel free to improve these wiki pages. From f1046442975f1a9d826b5dfcdd4640ea91f01c88 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 29 Oct 2014 12:15:53 +0000 Subject: [PATCH 13/58] Fix for MySQL issues See https://github.com/Pita/ueberDB/issues/63 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 18556aad..7fd1204f 100644 --- a/src/package.json +++ b/src/package.json @@ -16,7 +16,7 @@ "require-kernel" : "1.0.5", "resolve" : "0.2.x", "socket.io" : "0.9.x", - "ueberDB" : ">=0.2.2", + "ueberDB" : ">=0.2.4", "express" : "3.1.0", "async" : "0.1.x", "connect" : "2.7.x", From cd8ea040ad686f3498ae8235986edab1fda018ab Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 30 Oct 2014 14:41:21 +0000 Subject: [PATCH 14/58] bump ueber to require working mysql --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 7fd1204f..848bd53d 100644 --- a/src/package.json +++ b/src/package.json @@ -16,7 +16,7 @@ "require-kernel" : "1.0.5", "resolve" : "0.2.x", "socket.io" : "0.9.x", - "ueberDB" : ">=0.2.4", + "ueberDB" : ">=0.2.5", "express" : "3.1.0", "async" : "0.1.x", "connect" : "2.7.x", From 51b9af9df09173140e900c935ab85ac86f3e9fe4 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 30 Oct 2014 16:12:17 +0000 Subject: [PATCH 15/58] bump ueberdb again --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 848bd53d..11faa9e6 100644 --- a/src/package.json +++ b/src/package.json @@ -16,7 +16,7 @@ "require-kernel" : "1.0.5", "resolve" : "0.2.x", "socket.io" : "0.9.x", - "ueberDB" : ">=0.2.5", + "ueberDB" : ">=0.2.6", "express" : "3.1.0", "async" : "0.1.x", "connect" : "2.7.x", From 41b7f99204e2bc1abbf644109d594d460947c8cc Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 16:25:14 +0000 Subject: [PATCH 16/58] Bump resolve Update dep fixes https://github.com/ether/etherpad-lite/issues/2050 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 11faa9e6..ec618db4 100644 --- a/src/package.json +++ b/src/package.json @@ -14,7 +14,7 @@ "yajsml" : "1.1.6", "request" : "2.9.100", "require-kernel" : "1.0.5", - "resolve" : "0.2.x", + "resolve" : ">=1.0.0", "socket.io" : "0.9.x", "ueberDB" : ">=0.2.6", "express" : "3.1.0", From bf380eea504662ea41aa431e30d7e30ad6a36cd3 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 18:07:34 +0000 Subject: [PATCH 17/58] take line breaks and treat them appropriatly instead of creating a space for them.. --- src/static/js/contentcollector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index ee0a1c27..5e393670 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -89,7 +89,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class function textify(str) { return sanitizeUnicode( - str.replace(/[\n\r ]/g, ' ').replace(/\xa0/g, ' ').replace(/\t/g, ' ')); + str.replace(/\n/g, '').replace(/[\n\r ]/g, ' ').replace(/\xa0/g, ' ').replace(/\t/g, ' ')); } function getAssoc(node, name) From d54bb52b759bd68a1ec78735008f88eb9cb22d1f Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 18:18:25 +0000 Subject: [PATCH 18/58] Fixes #1414 https://github.com/ether/etherpad-lite/issues/1414 --- src/static/js/pad_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/pad_utils.js b/src/static/js/pad_utils.js index c2ff6fd0..343e5fce 100644 --- a/src/static/js/pad_utils.js +++ b/src/static/js/pad_utils.js @@ -482,7 +482,7 @@ var padutils = { }, bindCheckboxChange: function(node, func) { - $(node).bind("click change", func); + $(node).change(func); }, encodeUserId: function(userId) { From a22b558a2c3659b7b374e262e9a6bf01c0821c36 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 20:21:48 +0000 Subject: [PATCH 19/58] change to proper IE check --- src/static/js/pad.js | 2 +- src/static/js/pad_utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 73fcd3d6..0f5fbe72 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -67,7 +67,7 @@ function createCookie(name, value, days, path){ /* Warning Internet Explorer doe } //Check if the browser is IE and if so make sure the full path is set in the cookie - if(navigator.appName=='Microsoft Internet Explorer'){ + if((navigator.appName == 'Microsoft Internet Explorer') || ((navigator.appName == 'Netscape') && (new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null))){ document.cookie = name + "=" + value + expires + "; path="+document.location; } else{ diff --git a/src/static/js/pad_utils.js b/src/static/js/pad_utils.js index 343e5fce..ff60ca7c 100644 --- a/src/static/js/pad_utils.js +++ b/src/static/js/pad_utils.js @@ -55,7 +55,7 @@ function createCookie(name, value, days, path){ /* Used by IE */ } //Check if the browser is IE and if so make sure the full path is set in the cookie - if(navigator.appName=='Microsoft Internet Explorer'){ + if((navigator.appName == 'Microsoft Internet Explorer') || ((navigator.appName == 'Netscape') && (new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null))){ document.cookie = name + "=" + value + expires + "; path=/"; /* Note this bodge fix for IE is temporary until auth is rewritten */ } else{ From ff549db261d0945c08b97a99789624aec96b6fcb Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 20:58:56 +0000 Subject: [PATCH 20/58] use latest jsdom --- src/node/utils/ImportHtml.js | 4 +--- src/package.json | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/node/utils/ImportHtml.js b/src/node/utils/ImportHtml.js index abba2ac1..e2629791 100644 --- a/src/node/utils/ImportHtml.js +++ b/src/node/utils/ImportHtml.js @@ -14,10 +14,8 @@ * limitations under the License. */ -var jsdom = require('jsdom-nocontextifiy').jsdom; +var jsdom = require('jsdom').jsdom; var log4js = require('log4js'); - - var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var contentcollector = require("ep_etherpad-lite/static/js/contentcollector"); diff --git a/src/package.json b/src/package.json index 652aebaf..b035da88 100644 --- a/src/package.json +++ b/src/package.json @@ -25,7 +25,7 @@ "formidable" : "1.0.9", "log4js" : "0.6.6", "nodemailer" : "0.3.x", - "jsdom-nocontextifiy" : "0.2.10", + "jsdom" : ">=1.1.0", "async-stacktrace" : "0.0.2", "npm" : "1.4.x", "ejs" : "0.6.1", From 124ae311379b6e55fe4e550bc06229c37e660879 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 21:15:31 +0000 Subject: [PATCH 21/58] blah push back for imports --- src/node/utils/ImportHtml.js | 2 +- src/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/utils/ImportHtml.js b/src/node/utils/ImportHtml.js index e2629791..48188dfd 100644 --- a/src/node/utils/ImportHtml.js +++ b/src/node/utils/ImportHtml.js @@ -14,7 +14,7 @@ * limitations under the License. */ -var jsdom = require('jsdom').jsdom; +var jsdom = require('jsdom-nocontextifiy').jsdom; var log4js = require('log4js'); var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var contentcollector = require("ep_etherpad-lite/static/js/contentcollector"); diff --git a/src/package.json b/src/package.json index b035da88..652aebaf 100644 --- a/src/package.json +++ b/src/package.json @@ -25,7 +25,7 @@ "formidable" : "1.0.9", "log4js" : "0.6.6", "nodemailer" : "0.3.x", - "jsdom" : ">=1.1.0", + "jsdom-nocontextifiy" : "0.2.10", "async-stacktrace" : "0.0.2", "npm" : "1.4.x", "ejs" : "0.6.1", From a67e805da0f356cb584aa338c7c448d1969eb577 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 21:25:49 +0000 Subject: [PATCH 22/58] basics, still not working --- src/node/hooks/express/socketio.js | 2 ++ src/package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/node/hooks/express/socketio.js b/src/node/hooks/express/socketio.js index 524bab3d..39b32580 100644 --- a/src/node/hooks/express/socketio.js +++ b/src/node/hooks/express/socketio.js @@ -42,6 +42,7 @@ exports.expressCreateServer = function (hook_name, args, cb) { io.set('transports', settings.socketTransportProtocols ); var socketIOLogger = log4js.getLogger("socket.io"); + /* io.set('logger', { debug: function (str) { @@ -60,6 +61,7 @@ exports.expressCreateServer = function (hook_name, args, cb) { socketIOLogger.error.apply(socketIOLogger, arguments); }, }); + */ //minify socket.io javascript if(settings.minify) diff --git a/src/package.json b/src/package.json index 652aebaf..1adbe891 100644 --- a/src/package.json +++ b/src/package.json @@ -15,7 +15,7 @@ "request" : "2.9.100", "require-kernel" : "1.0.5", "resolve" : ">=1.0.0", - "socket.io" : "0.9.x", + "socket.io" : ">=1.2.0", "ueberDB" : ">=0.2.6", "express" : "3.1.0", "async" : "0.1.x", From 2c801cc558bd358d1de6a0cdfcd3de8201739f7b Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 1 Nov 2014 22:36:19 +0000 Subject: [PATCH 23/58] no errors but no connections --- src/node/hooks/express/socketio.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/node/hooks/express/socketio.js b/src/node/hooks/express/socketio.js index 39b32580..17ce3864 100644 --- a/src/node/hooks/express/socketio.js +++ b/src/node/hooks/express/socketio.js @@ -16,6 +16,7 @@ exports.expressCreateServer = function (hook_name, args, cb) { /* Require an express session cookie to be present, and load the * session. See http://www.danielbaulig.de/socket-ioexpress for more * info */ + /* io.set('authorization', function (data, accept) { if (!data.headers.cookie) return accept('No session cookie transmitted.', false); @@ -35,11 +36,12 @@ exports.expressCreateServer = function (hook_name, args, cb) { }); }); }); + */ // there shouldn't be a browser that isn't compatible to all // transports in this list at once // e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling - io.set('transports', settings.socketTransportProtocols ); + // io.set('transports', settings.socketTransportProtocols ); var socketIOLogger = log4js.getLogger("socket.io"); /* @@ -65,7 +67,7 @@ exports.expressCreateServer = function (hook_name, args, cb) { //minify socket.io javascript if(settings.minify) - io.enable('browser client minification'); + // io.enable('browser client minification'); //Initalize the Socket.IO Router socketIORouter.setSocketIO(io); From b61d8d99d17833d9fb45d21e9fb213ae59acd9f1 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 3 Nov 2014 17:15:22 +0000 Subject: [PATCH 24/58] Update package.json --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 652aebaf..bb136989 100644 --- a/src/package.json +++ b/src/package.json @@ -16,7 +16,7 @@ "require-kernel" : "1.0.5", "resolve" : ">=1.0.0", "socket.io" : "0.9.x", - "ueberDB" : ">=0.2.6", + "ueberDB" : ">=0.2.8", "express" : "3.1.0", "async" : "0.1.x", "connect" : "2.7.x", From b59f6a4d6f6a33824ea0caf3b668b635bbfb0823 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 15:50:53 +0000 Subject: [PATCH 25/58] Update ace2_inner.js --- src/static/js/ace2_inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index fb6dd080..4ef0a087 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3816,7 +3816,7 @@ function Ace2Inner(){ } updateBrowserSelectionFromRep(); var myselection = document.getSelection(); // get the current caret selection, can't use rep. here because that only gives us the start position not the current - var caretOffsetTop = myselection.focusNode.parentNode.offsetTop | myselection.focusNode.offsetTop; // get the carets selection offset in px IE 214 + var caretOffsetTop = myselection.focusNode.parentNode.offsetTop || myselection.focusNode.offsetTop; // get the carets selection offset in px IE 214 // top.console.log(caretOffsetTop); setScrollY(caretOffsetTop); // set the scrollY offset of the viewport on the document From c7061e47db8aa7828461fc3344e69a6b4dc6d319 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 17:06:47 +0000 Subject: [PATCH 26/58] use request and a remote ep plugin only endpoint --- src/static/js/pluginfw/installer.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/static/js/pluginfw/installer.js b/src/static/js/pluginfw/installer.js index 9f7ac939..7480e152 100644 --- a/src/static/js/pluginfw/installer.js +++ b/src/static/js/pluginfw/installer.js @@ -1,6 +1,7 @@ var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins"); var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks"); var npm = require("npm"); +var request = require("request"); var npmIsLoaded = false; var withNpm = function (npmfn) { @@ -60,17 +61,16 @@ exports.availablePlugins = null; var cacheTimestamp = 0; exports.getAvailablePlugins = function(maxCacheAge, cb) { - withNpm(function (er) { + request("http://etherpad.org/plugins.json", function(er, response, plugins){ if (er) return cb && cb(er); if(exports.availablePlugins && maxCacheAge && Math.round(+new Date/1000)-cacheTimestamp <= maxCacheAge) { return cb && cb(null, exports.availablePlugins) } - npm.commands.search(['ep_'], /*silent?*/true, function(er, results) { - if(er) return cb && cb(er); - exports.availablePlugins = results; + console.log("plugins", plugins); + plugins = JSON.parse(plugins); + exports.availablePlugins = plugins; cacheTimestamp = Math.round(+new Date/1000); - cb && cb(null, results) - }) + cb && cb(null, plugins) }); }; From 1e53c4f5f0440b00a30037793783f862f3cced7d Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 17:57:18 +0000 Subject: [PATCH 27/58] identify which parts are causing issues and comment them out, obviously this needs fixing --- src/node/handler/PadMessageHandler.js | 8 +++++++- src/node/handler/SocketIORouter.js | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index e1ac994e..c81c9d17 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1015,6 +1015,7 @@ function handleClientReady(client, message) return callback(); //Check if this author is already on the pad, if yes, kick the other sessions! +/* var roomClients = socketio.sockets.clients(padIds.padId); for(var i = 0; i < roomClients.length; i++) { var sinfo = sessioninfos[roomClients[i].id]; @@ -1025,6 +1026,7 @@ function handleClientReady(client, message) roomClients[i].json.send({disconnect:"userdup"}); } } +*/ //Save in sessioninfos that this session belonges to this pad sessioninfos[client.id].padId = padIds.padId; @@ -1032,6 +1034,7 @@ function handleClientReady(client, message) sessioninfos[client.id].readonly = padIds.readonly; //Log creation/(re-)entering of a pad +/* client.get('remoteAddress', function(er, ip) { //Anonymize the IP address if IP logging is disabled if(settings.disableIPlogging) { @@ -1045,6 +1048,7 @@ function handleClientReady(client, message) accessLogger.info('[CREATE] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" created the pad'); } }) +*/ //If this is a reconnect, we don't have to send the client the ClientVars again if(message.reconnect == true) @@ -1100,7 +1104,7 @@ function handleClientReady(client, message) // tell the client the number of the latest chat-message, which will be // used to request the latest 100 chat-messages later (GET_CHAT_MESSAGES) "chatHead": pad.chatHead, - "numConnectedUsers": roomClients.length, + "numConnectedUsers": 0, "readOnlyId": padIds.readOnlyPadId, "readonly": padIds.readonly, "serverTimestamp": new Date().getTime(), @@ -1165,6 +1169,7 @@ function handleClientReady(client, message) client.broadcast.to(padIds.padId).json.send(messageToTheOtherUsers); //Run trough all sessions of this pad +/* async.forEach(socketio.sockets.clients(padIds.padId), function(roomClient, callback) { var author; @@ -1211,6 +1216,7 @@ function handleClientReady(client, message) } ], callback); }, callback); +*/ } ],function(err) { diff --git a/src/node/handler/SocketIORouter.js b/src/node/handler/SocketIORouter.js index b3e046d2..96260254 100644 --- a/src/node/handler/SocketIORouter.js +++ b/src/node/handler/SocketIORouter.js @@ -56,11 +56,13 @@ exports.setSocketIO = function(_socket) { socket.sockets.on('connection', function(client) { + +// Broken: See http://stackoverflow.com/questions/4647348/send-message-to-specific-client-with-socket-io-and-node-js if(settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined){ - client.set('remoteAddress', client.handshake.headers['x-forwarded-for']); +// client.set('remoteAddress', client.handshake.headers['x-forwarded-for']); } else{ - client.set('remoteAddress', client.handshake.address.address); +// client.set('remoteAddress', client.handshake.address); } var clientAuthorized = false; From adef0af227a765b8d2ddfece29449bf6b4053313 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 18:01:41 +0000 Subject: [PATCH 28/58] more stuff required to stop it crashing, now we have identified what needs fixing we can fix it --- src/node/handler/PadMessageHandler.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index c81c9d17..da2a7a14 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -115,6 +115,7 @@ exports.handleDisconnect = function(client) //if this connection was already etablished with a handshake, send a disconnect message to the others if(session && session.author) { + /* client.get('remoteAddress', function(er, ip) { //Anonymize the IP address if IP logging is disabled if(settings.disableIPlogging) { @@ -123,6 +124,7 @@ exports.handleDisconnect = function(client) accessLogger.info('[LEAVE] Pad "'+session.padId+'": Author "'+session.author+'" on client '+client.id+' with IP "'+ip+'" left the pad') }) + */ //get the author color out of the db authorManager.getAuthorColorId(session.author, function(err, color) @@ -752,6 +754,7 @@ function handleUserChanges(data, cb) exports.updatePadClients = function(pad, callback) { + /* //skip this step if noone is on this pad var roomClients = socketio.sockets.clients(pad.id); if(roomClients.length==0) @@ -827,6 +830,7 @@ exports.updatePadClients = function(pad, callback) callback ); },callback); + */ } /** From 5d0ccb5f8f7b029ed71b0cd5bc668a3fe088a96f Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 18:17:39 +0000 Subject: [PATCH 29/58] auth fix --- src/node/hooks/express/socketio.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node/hooks/express/socketio.js b/src/node/hooks/express/socketio.js index 17ce3864..32c5fd88 100644 --- a/src/node/hooks/express/socketio.js +++ b/src/node/hooks/express/socketio.js @@ -16,8 +16,9 @@ exports.expressCreateServer = function (hook_name, args, cb) { /* Require an express session cookie to be present, and load the * session. See http://www.danielbaulig.de/socket-ioexpress for more * info */ - /* - io.set('authorization', function (data, accept) { + + io.use(function(socket, accept) { + var data = socket.request; if (!data.headers.cookie) return accept('No session cookie transmitted.', false); // Use connect's cookie parser, because it knows how to parse signed cookies @@ -36,7 +37,6 @@ exports.expressCreateServer = function (hook_name, args, cb) { }); }); }); - */ // there shouldn't be a browser that isn't compatible to all // transports in this list at once From cb28d109631e7bd5357fcd754b60fd89e820e7e6 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 18:32:26 +0000 Subject: [PATCH 30/58] move logging into debug environment variable .. sighs --- src/node/utils/Settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index c455617b..1f22ccfd 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -228,6 +228,7 @@ exports.reloadSettings = function reloadSettings() { log4js.configure(exports.logconfig);//Configure the logging appenders log4js.setGlobalLogLevel(exports.loglevel);//set loglevel + process.env['DEBUG'] = 'socket.io:' + exports.loglevel; // Used by SocketIO for Debug log4js.replaceConsole(); if(!exports.sessionKey){ // If the secretKey isn't set we also create yet another unique value here From 95e7b0f15609fc850b71717a672abd02237a0f33 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 19:11:06 +0000 Subject: [PATCH 31/58] transports --- src/node/hooks/express/socketio.js | 39 +++++++++--------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/node/hooks/express/socketio.js b/src/node/hooks/express/socketio.js index 32c5fd88..98146bbb 100644 --- a/src/node/hooks/express/socketio.js +++ b/src/node/hooks/express/socketio.js @@ -1,10 +1,17 @@ var log4js = require('log4js'); -var socketio = require('socket.io'); var settings = require('../../utils/Settings'); var socketIORouter = require("../../handler/SocketIORouter"); var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks"); var webaccess = require("ep_etherpad-lite/node/hooks/express/webaccess"); +// there shouldn't be a browser that isn't compatible to all +// transports in this list at once +// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling + +var socketio = require('socket.io')({ + transports: settings.socketTransportProtocols +}); + var padMessageHandler = require("../../handler/PadMessageHandler"); var connect = require('connect'); @@ -38,32 +45,10 @@ exports.expressCreateServer = function (hook_name, args, cb) { }); }); - // there shouldn't be a browser that isn't compatible to all - // transports in this list at once - // e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling - // io.set('transports', settings.socketTransportProtocols ); - - var socketIOLogger = log4js.getLogger("socket.io"); - /* - io.set('logger', { - debug: function (str) - { - socketIOLogger.debug.apply(socketIOLogger, arguments); - }, - info: function (str) - { - socketIOLogger.info.apply(socketIOLogger, arguments); - }, - warn: function (str) - { - socketIOLogger.warn.apply(socketIOLogger, arguments); - }, - error: function (str) - { - socketIOLogger.error.apply(socketIOLogger, arguments); - }, - }); - */ + // var socketIOLogger = log4js.getLogger("socket.io"); + // Debug logging now has to be set at an environment level, this is stupid. + // https://github.com/Automattic/socket.io/wiki/Migrating-to-1.0 + // This debug logging environment is set in Settings.js //minify socket.io javascript if(settings.minify) From 68eaa09708241b0551f5d345f45d8f7ba00913d2 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 19:55:05 +0000 Subject: [PATCH 32/58] Begin to repair damage done to rooms logic --- src/node/handler/PadMessageHandler.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index da2a7a14..2072a784 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -754,9 +754,14 @@ function handleUserChanges(data, cb) exports.updatePadClients = function(pad, callback) { - /* //skip this step if noone is on this pad - var roomClients = socketio.sockets.clients(pad.id); + var roomClients = [], room = socketio.sockets.adapter.rooms[pad.id]; + if (room) { + for (var id in room) { + roomClients.push(socketio.sockets.adapter.nsp.connected[id]); + } + } + if(roomClients.length==0) return callback(); @@ -769,10 +774,8 @@ exports.updatePadClients = function(pad, callback) var revCache = {}; //go trough all sessions on this pad - async.forEach(roomClients, function(client, callback) - { + async.forEach(roomClients, function(client, callback){ var sid = client.id; - //https://github.com/caolan/async#whilst //send them all new changesets async.whilst( @@ -802,7 +805,8 @@ exports.updatePadClients = function(pad, callback) if(author == sessioninfos[sid].author) { - client.json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); + // client.json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); + socketio.in(pad).send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); } else { @@ -817,7 +821,9 @@ exports.updatePadClients = function(pad, callback) timeDelta: currentTime - sessioninfos[sid].time }}; - client.json.send(wireMsg); + // client.json.send(wireMsg); + socketio.in(pad).send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); + } sessioninfos[sid].time = currentTime; @@ -830,7 +836,6 @@ exports.updatePadClients = function(pad, callback) callback ); },callback); - */ } /** From a6cbb4af409b5448e2b27d4f28234efd8c0e3c17 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 19:58:38 +0000 Subject: [PATCH 33/58] working messages --- src/node/handler/PadMessageHandler.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 2072a784..0dc18d7e 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -805,8 +805,7 @@ exports.updatePadClients = function(pad, callback) if(author == sessioninfos[sid].author) { - // client.json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); - socketio.in(pad).send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); + client.json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); } else { @@ -821,9 +820,7 @@ exports.updatePadClients = function(pad, callback) timeDelta: currentTime - sessioninfos[sid].time }}; - // client.json.send(wireMsg); - socketio.in(pad).send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); - + client.json.send(wireMsg); } sessioninfos[sid].time = currentTime; From 8391f902fbda5f687bb9efd3152352ddcdc11a81 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 22:31:09 +0000 Subject: [PATCH 34/58] re-apply roomsize --- src/node/handler/PadMessageHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 0dc18d7e..af83dfac 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1110,7 +1110,7 @@ function handleClientReady(client, message) // tell the client the number of the latest chat-message, which will be // used to request the latest 100 chat-messages later (GET_CHAT_MESSAGES) "chatHead": pad.chatHead, - "numConnectedUsers": 0, + "numConnectedUsers": roomClients.length, "readOnlyId": padIds.readOnlyPadId, "readonly": padIds.readonly, "serverTimestamp": new Date().getTime(), From af3e8e5e15b66ccae2306ba6b956d8acd8143eed Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 22:34:43 +0000 Subject: [PATCH 35/58] fix room client leave --- src/node/handler/PadMessageHandler.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index af83dfac..8657460c 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1021,8 +1021,13 @@ function handleClientReady(client, message) return callback(); //Check if this author is already on the pad, if yes, kick the other sessions! -/* - var roomClients = socketio.sockets.clients(padIds.padId); + var roomClients = [], room = socketio.sockets.adapter.rooms[pad.id]; + if (room) { + for (var id in room) { + roomClients.push(socketio.sockets.adapter.nsp.connected[id]); + } + } + for(var i = 0; i < roomClients.length; i++) { var sinfo = sessioninfos[roomClients[i].id]; if(sinfo && sinfo.author == author) { @@ -1032,7 +1037,6 @@ function handleClientReady(client, message) roomClients[i].json.send({disconnect:"userdup"}); } } -*/ //Save in sessioninfos that this session belonges to this pad sessioninfos[client.id].padId = padIds.padId; From f418dfa2053c4b40bd46d586b960a2de8167388c Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 22:37:10 +0000 Subject: [PATCH 36/58] fix author notification handler --- src/node/handler/PadMessageHandler.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 8657460c..3c39c4d8 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1179,8 +1179,14 @@ function handleClientReady(client, message) client.broadcast.to(padIds.padId).json.send(messageToTheOtherUsers); //Run trough all sessions of this pad -/* - async.forEach(socketio.sockets.clients(padIds.padId), function(roomClient, callback) + var roomClients = [], room = socketio.sockets.adapter.rooms[pad.id]; + if (room) { + for (var id in room) { + roomClients.push(socketio.sockets.adapter.nsp.connected[id]); + } + } + + async.forEach(roomClients, function(roomClient, callback) { var author; @@ -1226,7 +1232,6 @@ function handleClientReady(client, message) } ], callback); }, callback); -*/ } ],function(err) { From 9fa77cdea251b5e32a351298bbe97a88abec3e56 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 23:25:18 +0000 Subject: [PATCH 37/58] working handling of setting client ip and anonymizing etc --- src/node/handler/PadMessageHandler.js | 21 ++++++++++++--------- src/node/handler/SocketIORouter.js | 9 ++++++--- src/node/hooks/express/socketio.js | 8 +++++--- src/node/utils/RemoteAddress.js | 1 + 4 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 src/node/utils/RemoteAddress.js diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 3c39c4d8..b4e6243f 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -37,6 +37,7 @@ var _ = require('underscore'); var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js"); var channels = require("channels"); var stats = require('../stats'); +var remoteAddress = require("../utils/RemoteAddress").remoteAddress; /** * A associative array that saves informations about a session @@ -115,16 +116,18 @@ exports.handleDisconnect = function(client) //if this connection was already etablished with a handshake, send a disconnect message to the others if(session && session.author) { - /* - client.get('remoteAddress', function(er, ip) { - //Anonymize the IP address if IP logging is disabled - if(settings.disableIPlogging) { - ip = 'ANONYMOUS'; - } - accessLogger.info('[LEAVE] Pad "'+session.padId+'": Author "'+session.author+'" on client '+client.id+' with IP "'+ip+'" left the pad') - }) - */ +console.log(remoteAddress); + + // Get the IP address from our persistant object + var ip = remoteAddress[client.id]; + + // Anonymize the IP address if IP logging is disabled + if(settings.disableIPlogging) { + ip = 'ANONYMOUS'; + } + + accessLogger.info('[LEAVE] Pad "'+session.padId+'": Author "'+session.author+'" on client '+client.id+' with IP "'+ip+'" left the pad') //get the author color out of the db authorManager.getAuthorColorId(session.author, function(err, color) diff --git a/src/node/handler/SocketIORouter.js b/src/node/handler/SocketIORouter.js index 96260254..0a7361f4 100644 --- a/src/node/handler/SocketIORouter.js +++ b/src/node/handler/SocketIORouter.js @@ -24,6 +24,7 @@ var log4js = require('log4js'); var messageLogger = log4js.getLogger("message"); var securityManager = require("../db/SecurityManager"); var readOnlyManager = require("../db/ReadOnlyManager"); +var remoteAddress = require("../utils/RemoteAddress").remoteAddress; var settings = require('../utils/Settings'); /** @@ -57,12 +58,14 @@ exports.setSocketIO = function(_socket) { socket.sockets.on('connection', function(client) { -// Broken: See http://stackoverflow.com/questions/4647348/send-message-to-specific-client-with-socket-io-and-node-js + // Broken: See http://stackoverflow.com/questions/4647348/send-message-to-specific-client-with-socket-io-and-node-js + // Fixed by having a persistant object, ideally this would actually be in the database layer + // TODO move to database layer if(settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined){ -// client.set('remoteAddress', client.handshake.headers['x-forwarded-for']); + remoteAddress[client.id] = client.handshake.headers['x-forwarded-for']; } else{ -// client.set('remoteAddress', client.handshake.address); + remoteAddress[client.id] = client.handshake.address; } var clientAuthorized = false; diff --git a/src/node/hooks/express/socketio.js b/src/node/hooks/express/socketio.js index 98146bbb..e88a3f4c 100644 --- a/src/node/hooks/express/socketio.js +++ b/src/node/hooks/express/socketio.js @@ -51,9 +51,11 @@ exports.expressCreateServer = function (hook_name, args, cb) { // This debug logging environment is set in Settings.js //minify socket.io javascript - if(settings.minify) - // io.enable('browser client minification'); - + // Due to a shitty decision by the SocketIO team minification is + // no longer available, details available at: + // http://stackoverflow.com/questions/23981741/minify-socket-io-socket-io-js-with-1-0 + // if(settings.minify) io.enable('browser client minification'); + //Initalize the Socket.IO Router socketIORouter.setSocketIO(io); socketIORouter.addComponent("pad", padMessageHandler); diff --git a/src/node/utils/RemoteAddress.js b/src/node/utils/RemoteAddress.js new file mode 100644 index 00000000..86a4a5b2 --- /dev/null +++ b/src/node/utils/RemoteAddress.js @@ -0,0 +1 @@ +exports.remoteAddress = {}; From 053ff3097d097ad89337740a0209c50f4726399d Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 23:29:45 +0000 Subject: [PATCH 38/58] whoops I missed this one --- src/node/handler/PadMessageHandler.js | 28 ++++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index b4e6243f..36da4842 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -117,8 +117,6 @@ exports.handleDisconnect = function(client) if(session && session.author) { -console.log(remoteAddress); - // Get the IP address from our persistant object var ip = remoteAddress[client.id]; @@ -1047,21 +1045,19 @@ function handleClientReady(client, message) sessioninfos[client.id].readonly = padIds.readonly; //Log creation/(re-)entering of a pad -/* - client.get('remoteAddress', function(er, ip) { - //Anonymize the IP address if IP logging is disabled - if(settings.disableIPlogging) { - ip = 'ANONYMOUS'; - } + var ip = remoteAddress[client.id]; - if(pad.head > 0) { - accessLogger.info('[ENTER] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" entered the pad'); - } - else if(pad.head == 0) { - accessLogger.info('[CREATE] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" created the pad'); - } - }) -*/ + //Anonymize the IP address if IP logging is disabled + if(settings.disableIPlogging) { + ip = 'ANONYMOUS'; + } + + if(pad.head > 0) { + accessLogger.info('[ENTER] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" entered the pad'); + } + else if(pad.head == 0) { + accessLogger.info('[CREATE] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" created the pad'); + } //If this is a reconnect, we don't have to send the client the ClientVars again if(message.reconnect == true) From 57f56d8fe11ee28b9f3f2a1e969f86038ca27d34 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 4 Nov 2014 23:42:40 +0000 Subject: [PATCH 39/58] bump express to a working version --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 1adbe891..4639abcf 100644 --- a/src/package.json +++ b/src/package.json @@ -17,7 +17,7 @@ "resolve" : ">=1.0.0", "socket.io" : ">=1.2.0", "ueberDB" : ">=0.2.6", - "express" : "3.1.0", + "express" : ">3.1.0 <3.9.0", "async" : "0.1.x", "connect" : "2.7.x", "clean-css" : "0.3.2", From 7d04d7309f872dca337c8a648aff9f1aee5cd370 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 6 Nov 2014 14:32:20 +0000 Subject: [PATCH 40/58] reflow buttons based on browser size, much better --- src/static/css/pad.css | 43 +++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/static/css/pad.css b/src/static/css/pad.css index 599b9fd4..228c035f 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -59,7 +59,7 @@ a img { height: 32px; } .toolbar ul { - position: relative; + position: absolute; list-style: none; padding-right: 3px; padding-left: 1px; @@ -67,9 +67,6 @@ a img { overflow: hidden; float: left } -.toolbar ul.menu_right { - float: right -} .toolbar ul li { float: left; margin-left: 2px; @@ -84,6 +81,7 @@ a img { visibility: hidden; width: 0px; padding: 5px; + height:20px; } .toolbar ul li a:hover { text-decoration: none; @@ -164,6 +162,15 @@ a img { border: 1px solid #ccc; outline: none; } +.toolbar ul.menu_left { + left:0px; + right:250px; +} + +.toolbar ul.menu_right { + right:0px; +} + li[data-key=showusers] > a { min-width: 30px; text-align: left; @@ -843,12 +850,16 @@ input[type=checkbox] { width: 185px !important; } @media screen and (max-width: 600px) { - .toolbar ul li.separator { - display: none; - } - .toolbar ul li a { - padding: 4px 1px - } + .toolbar ul li.separator { + display: none; + } + .toolbar ul li a { + padding: 4px 1px + } + .toolbar ul.menu_left { + left:0px; + right:150px; + } } @media all and (max-width: 400px){ #gritter-notice-wrapper{ @@ -894,9 +905,13 @@ input[type=checkbox] { #editbar { height: 62px; } + .toolbar ul.menu_left { + left:0px; + right:100px; + } + .toolbar ul.menu_right { - float: left; - margin-top:2px; + right:0px; } .popup { width:100%; @@ -917,6 +932,8 @@ input[type=checkbox] { #editorcontainer { margin-bottom: 33px } + .toolbar ul.menu_left { + } .toolbar ul.menu_right { background: #f7f7f7; background: -webkit-linear-gradient(#f7f7f7, #f1f1f1 80%); @@ -1076,4 +1093,4 @@ input[type=checkbox] { text-shadow: none; } -/* End of gritter stuff */ \ No newline at end of file +/* End of gritter stuff */ From 9170effb27dee076ac7401a34f0e857be50330eb Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 6 Nov 2014 15:09:44 +0000 Subject: [PATCH 41/58] working redraw and draw on startup --- src/static/js/pad.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 73fcd3d6..5292e75d 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -370,6 +370,18 @@ function handshake() $('#readonlyinput').on('click',function(){ padeditbar.setEmbedLinks(); }); + // Listen for resize events (sucks but needed as iFrame ace_inner has to be position absolute + // A CSS fix for this would be nice but I'm not sure how we'd do it. + $(window).resize(function(){ + redrawEditbar(); + }); + redrawEditbar(); +} + +var redrawEditbar = function(){ + var height = $('.menu_left').height() + 4 + "px"; + $('#editbar').css("height", height); + $('#editorcontainer').css("top", height); } $.extend($.gritter.options, { @@ -937,4 +949,3 @@ exports.handshake = handshake; exports.pad = pad; exports.init = init; exports.alertBar = alertBar; - From 96d6e7c1b7df59e96c394608a343cb698c848576 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 6 Nov 2014 15:12:40 +0000 Subject: [PATCH 42/58] cleaner reflow --- src/static/js/pad.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 5292e75d..6a3a2e0e 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -379,9 +379,10 @@ function handshake() } var redrawEditbar = function(){ - var height = $('.menu_left').height() + 4 + "px"; - $('#editbar').css("height", height); - $('#editorcontainer').css("top", height); + var editbarHeight = $('.menu_left').height() + 2 + "px"; + var containerTop = $('.menu_left').height() + 5 + "px"; + $('#editbar').css("height", editbarHeight); + $('#editorcontainer').css("top", containerTop); } $.extend($.gritter.options, { From 0685e563ed947a42377fe1a5eb6fca10f3e8e833 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 6 Nov 2014 15:43:21 +0000 Subject: [PATCH 43/58] working on resize --- src/static/css/pad.css | 1 + src/static/js/pad.js | 13 ------------- src/static/js/pad_editbar.js | 15 ++++++++++++++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/static/css/pad.css b/src/static/css/pad.css index 228c035f..11705e06 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -933,6 +933,7 @@ input[type=checkbox] { margin-bottom: 33px } .toolbar ul.menu_left { + right:0px; } .toolbar ul.menu_right { background: #f7f7f7; diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 6a3a2e0e..649d8c82 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -370,19 +370,6 @@ function handshake() $('#readonlyinput').on('click',function(){ padeditbar.setEmbedLinks(); }); - // Listen for resize events (sucks but needed as iFrame ace_inner has to be position absolute - // A CSS fix for this would be nice but I'm not sure how we'd do it. - $(window).resize(function(){ - redrawEditbar(); - }); - redrawEditbar(); -} - -var redrawEditbar = function(){ - var editbarHeight = $('.menu_left').height() + 2 + "px"; - var containerTop = $('.menu_left').height() + 5 + "px"; - $('#editbar').css("height", editbarHeight); - $('#editorcontainer').css("top", containerTop); } $.extend($.gritter.options, { diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index 6352b129..c067bbba 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -140,7 +140,12 @@ var padeditbar = (function() init: function() { var self = this; self.dropdowns = []; - + // Listen for resize events (sucks but needed as iFrame ace_inner has to be position absolute + // A CSS fix for this would be nice but I'm not sure how we'd do it. + $(window).resize(function(){ + self.redrawHeight(); + }); + $("#editbar .editbarbutton").attr("unselectable", "on"); // for IE $("#editbar").removeClass("disabledtoolbar").addClass("enabledtoolbar"); $("#editbar [data-key]").each(function () { @@ -149,6 +154,8 @@ var padeditbar = (function() }); }); + this.redrawHeight(); + registerDefaultCommands(self); hooks.callAll("postToolbarInit", { @@ -170,6 +177,12 @@ var padeditbar = (function() this.commands[cmd] = callback; return this; }, + redrawHeight: function(){ + var editbarHeight = $('.menu_left').height() + 2 + "px"; + var containerTop = $('.menu_left').height() + 5 + "px"; + $('#editbar').css("height", editbarHeight); + $('#editorcontainer').css("top", containerTop); + }, registerDropdownCommand: function (cmd, dropdown) { dropdown = dropdown || cmd; self.dropdowns.push(dropdown) From d13b6162f0b7869942ec4bcb6ab7b5267b448b86 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 6 Nov 2014 15:50:55 +0000 Subject: [PATCH 44/58] this looks way better --- src/static/css/pad.css | 3 +++ src/static/js/pad_editbar.js | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/static/css/pad.css b/src/static/css/pad.css index 11705e06..91c97c5e 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -182,6 +182,9 @@ li[data-key=showusers] > a #online_count { top: 2px; padding-left: 2px; } +#editbar{ + display:none; +} #editorcontainer { position: absolute; top: 37px; /* + 1px border */ diff --git a/src/static/js/pad_editbar.js b/src/static/js/pad_editbar.js index c067bbba..d39bfecd 100644 --- a/src/static/js/pad_editbar.js +++ b/src/static/js/pad_editbar.js @@ -154,6 +154,8 @@ var padeditbar = (function() }); }); + $('#editbar').show(); + this.redrawHeight(); registerDefaultCommands(self); From 3eb0652b218bb050396da1a749fbe131ca58af5f Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 6 Nov 2014 16:38:31 +0000 Subject: [PATCH 45/58] fix pg --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index bb136989..7cabf6e6 100644 --- a/src/package.json +++ b/src/package.json @@ -16,7 +16,7 @@ "require-kernel" : "1.0.5", "resolve" : ">=1.0.0", "socket.io" : "0.9.x", - "ueberDB" : ">=0.2.8", + "ueberDB" : ">=0.2.9", "express" : "3.1.0", "async" : "0.1.x", "connect" : "2.7.x", From fc5152c2f3199ec6056fc97a04eda3afd733eae0 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 6 Nov 2014 17:38:38 +0000 Subject: [PATCH 46/58] remove logging --- src/static/js/pluginfw/installer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/static/js/pluginfw/installer.js b/src/static/js/pluginfw/installer.js index 7480e152..c1a9adad 100644 --- a/src/static/js/pluginfw/installer.js +++ b/src/static/js/pluginfw/installer.js @@ -66,7 +66,6 @@ exports.getAvailablePlugins = function(maxCacheAge, cb) { if(exports.availablePlugins && maxCacheAge && Math.round(+new Date/1000)-cacheTimestamp <= maxCacheAge) { return cb && cb(null, exports.availablePlugins) } - console.log("plugins", plugins); plugins = JSON.parse(plugins); exports.availablePlugins = plugins; cacheTimestamp = Math.round(+new Date/1000); From 2d597a4cab4f5df29cf063dca879ce2cc02483e4 Mon Sep 17 00:00:00 2001 From: Prateek Saxena Date: Fri, 7 Nov 2014 14:01:32 +0530 Subject: [PATCH 47/58] Add keyboard shortcut to Clear Authorship Colors. Fixes #2292 --- src/static/js/ace2_inner.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 4ef0a087..ad5dd905 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3757,7 +3757,7 @@ function Ace2Inner(){ doInsertUnorderedList() specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "n" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "n" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) { // cmd-shift-N (orderedlist) fastIncorp(9); @@ -3765,6 +3765,12 @@ function Ace2Inner(){ doInsertOrderedList() specialHandled = true; } + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "c" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) { + // cmd-shift-C (clearauthorship) + fastIncorp(9); + evt.preventDefault(); + CMDS.clearauthorship(); + } if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "h" && (evt.ctrlKey)) { // cmd-H (backspace) From d246a191c6cc9a6e2d84451058e2252f7c552095 Mon Sep 17 00:00:00 2001 From: Cristo Date: Sat, 8 Nov 2014 01:12:40 +0100 Subject: [PATCH 48/58] Added option to restore revisions #1791 --- src/node/db/API.js | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/node/db/API.js b/src/node/db/API.js index 4a912368..2aadc483 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -576,6 +576,104 @@ exports.deletePad = function(padID, callback) }); } +exports.restoreRevision = function(padID, rev, callback) +{ + var Changeset = require("ep_etherpad-lite/static/js/Changeset"); + + //check if rev is a number + if(rev !== undefined && typeof rev != "number") + { + //try to parse the number + if(!isNaN(parseInt(rev))) + { + rev = parseInt(rev); + } + else + { + callback(new customError("rev is not a number", "apierror")); + return; + } + } + + //ensure this is not a negativ number + if(rev !== undefined && rev < 0) + { + callback(new customError("rev is a negativ number","apierror")); + return; + } + + //ensure this is not a float value + if(rev !== undefined && !is_int(rev)) + { + callback(new customError("rev is a float value","apierror")); + return; + } + + //get the pad + getPadSafe(padID, true, function(err, pad) + { + if(ERR(err, callback)) return; + + + //check if this is a valid revision + if(rev > pad.getHeadRevisionNumber()) + { + callback(new customError("rev is higher than the head revision of the pad","apierror")); + return; + } + + pad.getInternalRevisionAText(rev, function(err, atext) + { + if(ERR(err, callback)) return; + + var oldText = pad.text(); + atext.text += "\n"; + function eachAttribRun(attribs, func) + { + var attribsIter = Changeset.opIterator(attribs); + var textIndex = 0; + var newTextStart = 0; + var newTextEnd = atext.text.length; + while (attribsIter.hasNext()) + { + var op = attribsIter.next(); + var nextIndex = textIndex + op.chars; + if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) + { + func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); + } + textIndex = nextIndex; + } + } + + // create a new changeset with a helper builder object + var builder = Changeset.builder(oldText.length); + + // assemble each line into the builder + eachAttribRun(atext.attribs, function(start, end, attribs) + { + builder.insert(atext.text.substring(start, end), attribs); + }); + + var lastNewlinePos = oldText.lastIndexOf('\n'); + if (lastNewlinePos < 0) { + builder.remove(oldText.length-1,0); + } else { + builder.remove(lastNewlinePos, oldText.match(/\n/g).length-1); + builder.remove(oldText.length - lastNewlinePos-1,0); + } + + var changeset = builder.toString(); + + //append the changeset + pad.appendRevision(changeset); + // + callback(null, changeset); + }); + + }); +}; + /** copyPad(sourceID, destinationID[, force=false]) copies a pad. If force is true, the destination will be overwritten if it exists. From c33c6e085ec533056cb5bf75dc76350e9cdf03ba Mon Sep 17 00:00:00 2001 From: Cristo Date: Sat, 8 Nov 2014 01:39:27 +0100 Subject: [PATCH 49/58] comment addded --- src/node/db/API.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 2aadc483..8ad6e2eb 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -575,7 +575,14 @@ exports.deletePad = function(padID, callback) pad.remove(callback); }); } +/** + restoreRevision(padID, [rev]) Restores revision from past as new changeset + Example returns: + + {code:0, message:"ok", data:null} + {code: 1, message:"padID does not exist", data: null} + */ exports.restoreRevision = function(padID, rev, callback) { var Changeset = require("ep_etherpad-lite/static/js/Changeset"); @@ -668,7 +675,7 @@ exports.restoreRevision = function(padID, rev, callback) //append the changeset pad.appendRevision(changeset); // - callback(null, changeset); + callback(null, null); }); }); From 46bc328896877630169c4cea60431be981859352 Mon Sep 17 00:00:00 2001 From: Cristo Date: Sat, 8 Nov 2014 01:41:23 +0100 Subject: [PATCH 50/58] new api ver --- src/node/handler/APIHandler.js | 48 +++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 273a58a6..76af4aa1 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -345,10 +345,56 @@ var version = , "getChatHistory" : ["padID", "start", "end"] , "getChatHead" : ["padID"] } + , "1.2.11": + { "createGroup" : [] + , "createGroupIfNotExistsFor" : ["groupMapper"] + , "deleteGroup" : ["groupID"] + , "listPads" : ["groupID"] + , "listAllPads" : [] + , "createDiffHTML" : ["padID", "startRev", "endRev"] + , "createPad" : ["padID", "text"] + , "createGroupPad" : ["groupID", "padName", "text"] + , "createAuthor" : ["name"] + , "createAuthorIfNotExistsFor": ["authorMapper" , "name"] + , "listPadsOfAuthor" : ["authorID"] + , "createSession" : ["groupID", "authorID", "validUntil"] + , "deleteSession" : ["sessionID"] + , "getSessionInfo" : ["sessionID"] + , "listSessionsOfGroup" : ["groupID"] + , "listSessionsOfAuthor" : ["authorID"] + , "getText" : ["padID", "rev"] + , "setText" : ["padID", "text"] + , "getHTML" : ["padID", "rev"] + , "setHTML" : ["padID", "html"] + , "getAttributePool" : ["padID"] + , "getRevisionsCount" : ["padID"] + , "getRevisionChangeset" : ["padID", "rev"] + , "getLastEdited" : ["padID"] + , "deletePad" : ["padID"] + , "copyPad" : ["sourceID", "destinationID", "force"] + , "movePad" : ["sourceID", "destinationID", "force"] + , "getReadOnlyID" : ["padID"] + , "getPadID" : ["roID"] + , "setPublicStatus" : ["padID", "publicStatus"] + , "getPublicStatus" : ["padID"] + , "setPassword" : ["padID", "password"] + , "isPasswordProtected" : ["padID"] + , "listAuthorsOfPad" : ["padID"] + , "padUsersCount" : ["padID"] + , "getAuthorName" : ["authorID"] + , "padUsers" : ["padID"] + , "sendClientsMessage" : ["padID", "msg"] + , "listAllGroups" : [] + , "checkToken" : [] + , "getChatHistory" : ["padID"] + , "getChatHistory" : ["padID", "start", "end"] + , "getChatHead" : ["padID"] + , "restoreRevision" : ["padID", "rev"] + } }; // set the latest available API version here -exports.latestApiVersion = '1.2.10'; +exports.latestApiVersion = '1.2.11'; // exports the versions so it can be used by the new Swagger endpoint exports.version = version; From 60b698f69b830b6e9e82a0d3de47763bf0c890a4 Mon Sep 17 00:00:00 2001 From: Prateek Saxena Date: Sun, 9 Nov 2014 09:18:50 +0530 Subject: [PATCH 51/58] Add keyboard shortcut for "Clear Authorshop Colors" in en locale Translate wiki should pick this up and the translations will start coming in a while. #2292 --- src/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/en.json b/src/locales/en.json index d9b98389..9a25b18c 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -12,7 +12,7 @@ "pad.toolbar.unindent.title": "Outdent (Shift+TAB)", "pad.toolbar.undo.title": "Undo (Ctrl+Z)", "pad.toolbar.redo.title": "Redo (Ctrl+Y)", - "pad.toolbar.clearAuthorship.title": "Clear Authorship Colors", + "pad.toolbar.clearAuthorship.title": "Clear Authorship Colors (Ctrl+Shift+C)", "pad.toolbar.import_export.title": "Import/Export from/to different file formats", "pad.toolbar.timeslider.title": "Timeslider", "pad.toolbar.savedRevision.title": "Save Revision", From 9d39c9591adab5b6638e16ee54e7f87a9147e015 Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:46:50 +0100 Subject: [PATCH 52/58] update pad clients --- src/node/db/API.js | 170 +++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 82 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 8ad6e2eb..b3d46ea1 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -583,102 +583,108 @@ exports.deletePad = function(padID, callback) {code:0, message:"ok", data:null} {code: 1, message:"padID does not exist", data: null} */ -exports.restoreRevision = function(padID, rev, callback) +exports.restoreRevision = function (padID, rev, callback) { - var Changeset = require("ep_etherpad-lite/static/js/Changeset"); - - //check if rev is a number - if(rev !== undefined && typeof rev != "number") - { - //try to parse the number - if(!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else - { - callback(new customError("rev is not a number", "apierror")); - return; - } - } + var Changeset = require("ep_etherpad-lite/static/js/Changeset"); + var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); - //ensure this is not a negativ number - if(rev !== undefined && rev < 0) - { - callback(new customError("rev is a negativ number","apierror")); - return; - } + //check if rev is a number + if (rev !== undefined && typeof rev != "number") + { + //try to parse the number + if (!isNaN(parseInt(rev))) + { + rev = parseInt(rev); + } + else + { + callback(new customError("rev is not a number", "apierror")); + return; + } + } - //ensure this is not a float value - if(rev !== undefined && !is_int(rev)) - { - callback(new customError("rev is a float value","apierror")); - return; - } + //ensure this is not a negativ number + if (rev !== undefined && rev < 0) + { + callback(new customError("rev is a negativ number", "apierror")); + return; + } - //get the pad - getPadSafe(padID, true, function(err, pad) - { - if(ERR(err, callback)) return; + //ensure this is not a float value + if (rev !== undefined && !is_int(rev)) + { + callback(new customError("rev is a float value", "apierror")); + return; + } + + //get the pad + getPadSafe(padID, true, function (err, pad) + { + if (ERR(err, callback)) return; - //check if this is a valid revision - if(rev > pad.getHeadRevisionNumber()) - { - callback(new customError("rev is higher than the head revision of the pad","apierror")); - return; - } + //check if this is a valid revision + if (rev > pad.getHeadRevisionNumber()) + { + callback(new customError("rev is higher than the head revision of the pad", "apierror")); + return; + } - pad.getInternalRevisionAText(rev, function(err, atext) - { - if(ERR(err, callback)) return; + pad.getInternalRevisionAText(rev, function (err, atext) + { + if (ERR(err, callback)) return; - var oldText = pad.text(); - atext.text += "\n"; - function eachAttribRun(attribs, func) - { - var attribsIter = Changeset.opIterator(attribs); - var textIndex = 0; - var newTextStart = 0; - var newTextEnd = atext.text.length; - while (attribsIter.hasNext()) - { - var op = attribsIter.next(); - var nextIndex = textIndex + op.chars; - if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) - { - func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); - } - textIndex = nextIndex; - } - } + var oldText = pad.text(); + atext.text += "\n"; + function eachAttribRun(attribs, func) + { + var attribsIter = Changeset.opIterator(attribs); + var textIndex = 0; + var newTextStart = 0; + var newTextEnd = atext.text.length; + while (attribsIter.hasNext()) + { + var op = attribsIter.next(); + var nextIndex = textIndex + op.chars; + if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) + { + func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); + } + textIndex = nextIndex; + } + } - // create a new changeset with a helper builder object - var builder = Changeset.builder(oldText.length); + // create a new changeset with a helper builder object + var builder = Changeset.builder(oldText.length); - // assemble each line into the builder - eachAttribRun(atext.attribs, function(start, end, attribs) - { - builder.insert(atext.text.substring(start, end), attribs); - }); + // assemble each line into the builder + eachAttribRun(atext.attribs, function (start, end, attribs) + { + builder.insert(atext.text.substring(start, end), attribs); + }); - var lastNewlinePos = oldText.lastIndexOf('\n'); - if (lastNewlinePos < 0) { - builder.remove(oldText.length-1,0); - } else { - builder.remove(lastNewlinePos, oldText.match(/\n/g).length-1); - builder.remove(oldText.length - lastNewlinePos-1,0); - } + var lastNewlinePos = oldText.lastIndexOf('\n'); + if (lastNewlinePos < 0) + { + builder.remove(oldText.length - 1, 0); + } else + { + builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1); + builder.remove(oldText.length - lastNewlinePos - 1, 0); + } - var changeset = builder.toString(); + var changeset = builder.toString(); - //append the changeset - pad.appendRevision(changeset); - // - callback(null, null); - }); + //append the changeset + pad.appendRevision(changeset); + // + padMessage.updatePadClients(pad, function () + { + }); + callback(null, null); + }); - }); + }); }; /** From 24ac082cae6ad8842d3028a14ec9ecb8bbd47b9a Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:49:08 +0100 Subject: [PATCH 53/58] Update API.js --- src/node/db/API.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index b3d46ea1..d933f99e 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -587,7 +587,6 @@ exports.restoreRevision = function (padID, rev, callback) { var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); - //check if rev is a number if (rev !== undefined && typeof rev != "number") { From f59238fe58ac1d1a28896642a86f8483a0d524a3 Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:50:43 +0100 Subject: [PATCH 54/58] Update API.js --- src/node/db/API.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index d933f99e..2ba99f6a 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -587,6 +587,7 @@ exports.restoreRevision = function (padID, rev, callback) { var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); + //check if rev is a number if (rev !== undefined && typeof rev != "number") { @@ -682,7 +683,6 @@ exports.restoreRevision = function (padID, rev, callback) }); callback(null, null); }); - }); }; From f7dd756642623ade815f417de7b7b2eb880e488c Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:53:56 +0100 Subject: [PATCH 55/58] Update API.js --- src/node/db/API.js | 173 +++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 2ba99f6a..07d3703c 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -585,105 +585,106 @@ exports.deletePad = function(padID, callback) */ exports.restoreRevision = function (padID, rev, callback) { - var Changeset = require("ep_etherpad-lite/static/js/Changeset"); - var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); + var Changeset = require("ep_etherpad-lite/static/js/Changeset"); + var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); - //check if rev is a number - if (rev !== undefined && typeof rev != "number") - { - //try to parse the number - if (!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else - { - callback(new customError("rev is not a number", "apierror")); - return; - } - } + //check if rev is a number + if (rev !== undefined && typeof rev != "number") + { + //try to parse the number + if (!isNaN(parseInt(rev))) + { + rev = parseInt(rev); + } + else + { + callback(new customError("rev is not a number", "apierror")); + return; + } + } - //ensure this is not a negativ number - if (rev !== undefined && rev < 0) - { - callback(new customError("rev is a negativ number", "apierror")); - return; - } + //ensure this is not a negativ number + if (rev !== undefined && rev < 0) + { + callback(new customError("rev is a negativ number", "apierror")); + return; + } - //ensure this is not a float value - if (rev !== undefined && !is_int(rev)) - { - callback(new customError("rev is a float value", "apierror")); - return; - } + //ensure this is not a float value + if (rev !== undefined && !is_int(rev)) + { + callback(new customError("rev is a float value", "apierror")); + return; + } - //get the pad - getPadSafe(padID, true, function (err, pad) - { - if (ERR(err, callback)) return; + //get the pad + getPadSafe(padID, true, function (err, pad) + { + if (ERR(err, callback)) return; - //check if this is a valid revision - if (rev > pad.getHeadRevisionNumber()) - { - callback(new customError("rev is higher than the head revision of the pad", "apierror")); - return; - } + //check if this is a valid revision + if (rev > pad.getHeadRevisionNumber()) + { + callback(new customError("rev is higher than the head revision of the pad", "apierror")); + return; + } - pad.getInternalRevisionAText(rev, function (err, atext) - { - if (ERR(err, callback)) return; + pad.getInternalRevisionAText(rev, function (err, atext) + { + if (ERR(err, callback)) return; - var oldText = pad.text(); - atext.text += "\n"; - function eachAttribRun(attribs, func) - { - var attribsIter = Changeset.opIterator(attribs); - var textIndex = 0; - var newTextStart = 0; - var newTextEnd = atext.text.length; - while (attribsIter.hasNext()) - { - var op = attribsIter.next(); - var nextIndex = textIndex + op.chars; - if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) - { - func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); - } - textIndex = nextIndex; - } - } + var oldText = pad.text(); + atext.text += "\n"; + function eachAttribRun(attribs, func) + { + var attribsIter = Changeset.opIterator(attribs); + var textIndex = 0; + var newTextStart = 0; + var newTextEnd = atext.text.length; + while (attribsIter.hasNext()) + { + var op = attribsIter.next(); + var nextIndex = textIndex + op.chars; + if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) + { + func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); + } + textIndex = nextIndex; + } + } - // create a new changeset with a helper builder object - var builder = Changeset.builder(oldText.length); + // create a new changeset with a helper builder object + var builder = Changeset.builder(oldText.length); - // assemble each line into the builder - eachAttribRun(atext.attribs, function (start, end, attribs) - { - builder.insert(atext.text.substring(start, end), attribs); - }); + // assemble each line into the builder + eachAttribRun(atext.attribs, function (start, end, attribs) + { + builder.insert(atext.text.substring(start, end), attribs); + }); - var lastNewlinePos = oldText.lastIndexOf('\n'); - if (lastNewlinePos < 0) - { - builder.remove(oldText.length - 1, 0); - } else - { - builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1); - builder.remove(oldText.length - lastNewlinePos - 1, 0); - } + var lastNewlinePos = oldText.lastIndexOf('\n'); + if (lastNewlinePos < 0) + { + builder.remove(oldText.length - 1, 0); + } else + { + builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1); + builder.remove(oldText.length - lastNewlinePos - 1, 0); + } - var changeset = builder.toString(); + var changeset = builder.toString(); - //append the changeset - pad.appendRevision(changeset); - // - padMessage.updatePadClients(pad, function () - { - }); - callback(null, null); - }); - }); + //append the changeset + pad.appendRevision(changeset); + // + padMessage.updatePadClients(pad, function () + { + }); + callback(null, null); + }); + + }); }; /** From 0253156dbb2e26a1a894a414c61ff8e521b3fece Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:55:37 +0100 Subject: [PATCH 56/58] Update APIHandler.js --- src/node/handler/APIHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 76af4aa1..9adc2418 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -345,7 +345,7 @@ var version = , "getChatHistory" : ["padID", "start", "end"] , "getChatHead" : ["padID"] } - , "1.2.11": +, "1.2.11": { "createGroup" : [] , "createGroupIfNotExistsFor" : ["groupMapper"] , "deleteGroup" : ["groupID"] From e5d77c3763d28baa26b07d9cc7a1bdc59384f7f0 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 12 Nov 2014 21:39:03 +0000 Subject: [PATCH 57/58] indentation --- src/static/js/pluginfw/installer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/static/js/pluginfw/installer.js b/src/static/js/pluginfw/installer.js index c1a9adad..bf779d7a 100644 --- a/src/static/js/pluginfw/installer.js +++ b/src/static/js/pluginfw/installer.js @@ -67,9 +67,9 @@ exports.getAvailablePlugins = function(maxCacheAge, cb) { return cb && cb(null, exports.availablePlugins) } plugins = JSON.parse(plugins); - exports.availablePlugins = plugins; - cacheTimestamp = Math.round(+new Date/1000); - cb && cb(null, plugins) + exports.availablePlugins = plugins; + cacheTimestamp = Math.round(+new Date/1000); + cb && cb(null, plugins) }); }; From e8fda27ead8bb550b027b9578199e2b034e388d1 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Fri, 14 Nov 2014 13:42:39 +0100 Subject: [PATCH 58/58] Localisation updates from https://translatewiki.net. --- src/locales/de.json | 6 +++--- src/locales/it.json | 9 +++++---- src/locales/lb.json | 4 ++-- src/locales/mk.json | 6 +++--- src/locales/sv.json | 14 +++++++------- src/locales/vi.json | 9 +++++---- src/locales/zh-hant.json | 8 ++++---- 7 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/locales/de.json b/src/locales/de.json index 05a9af79..25594da1 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -12,9 +12,9 @@ "pad.toolbar.bold.title": "Fett (Strg-B)", "pad.toolbar.italic.title": "Kursiv (Strg-I)", "pad.toolbar.underline.title": "Unterstrichen (Strg-U)", - "pad.toolbar.strikethrough.title": "Durchgestrichen", - "pad.toolbar.ol.title": "Nummerierte Liste", - "pad.toolbar.ul.title": "Ungeordnete Liste", + "pad.toolbar.strikethrough.title": "Durchgestrichen (Strg+5)", + "pad.toolbar.ol.title": "Nummerierte Liste (Strg+Shift+N)", + "pad.toolbar.ul.title": "Ungeordnete Liste (Strg+Shift+L)", "pad.toolbar.indent.title": "Einrücken (TAB)", "pad.toolbar.unindent.title": "Ausrücken (Shift+TAB)", "pad.toolbar.undo.title": "Rückgängig (Strg-Z)", diff --git a/src/locales/it.json b/src/locales/it.json index 8292c4f2..501733f8 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -4,7 +4,8 @@ "Beta16", "Gianfranco", "Muxator", - "Vituzzu" + "Vituzzu", + "Macofe" ] }, "index.newPad": "Nuovo Pad", @@ -12,9 +13,9 @@ "pad.toolbar.bold.title": "Grassetto (Ctrl-B)", "pad.toolbar.italic.title": "Corsivo (Ctrl-I)", "pad.toolbar.underline.title": "Sottolineato (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Barrato", - "pad.toolbar.ol.title": "Elenco numerato", - "pad.toolbar.ul.title": "Elenco puntato", + "pad.toolbar.strikethrough.title": "Barrato (Ctrl+5)", + "pad.toolbar.ol.title": "Elenco numerato (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Elenco puntato (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Rientro (TAB)", "pad.toolbar.unindent.title": "Riduci rientro (Shift+TAB)", "pad.toolbar.undo.title": "Annulla (Ctrl-Z)", diff --git a/src/locales/lb.json b/src/locales/lb.json index 7f936906..841add75 100644 --- a/src/locales/lb.json +++ b/src/locales/lb.json @@ -6,8 +6,8 @@ ] }, "index.newPad": "Neie Pad", - "pad.toolbar.ol.title": "Numeréiert Lëscht", - "pad.toolbar.ul.title": "Net-numeréiert Lëscht", + "pad.toolbar.ol.title": "Numeréiert Lëscht (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Net-numeréiert Lëscht (Ctrl+Shift+L)", "pad.toolbar.undo.title": "Réckgängeg (Ctrl-Z)", "pad.toolbar.redo.title": "Widderhuelen (Ctrl-Y)", "pad.toolbar.savedRevision.title": "Versioun späicheren", diff --git a/src/locales/mk.json b/src/locales/mk.json index 8aaf9917..aec40b27 100644 --- a/src/locales/mk.json +++ b/src/locales/mk.json @@ -10,9 +10,9 @@ "pad.toolbar.bold.title": "Задебелено (Ctrl-B)", "pad.toolbar.italic.title": "Косо (Ctrl-I)", "pad.toolbar.underline.title": "Подвлечено (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Прецртано", - "pad.toolbar.ol.title": "Подреден список", - "pad.toolbar.ul.title": "Неподреден список", + "pad.toolbar.strikethrough.title": "Прецртано (Ctrl+5)", + "pad.toolbar.ol.title": "Подреден список (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Неподреден список (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Вовлекување (TAB)", "pad.toolbar.unindent.title": "Отстап (Shift+TAB)", "pad.toolbar.undo.title": "Врати (Ctrl-Z)", diff --git a/src/locales/sv.json b/src/locales/sv.json index 623def9a..ab6f3820 100644 --- a/src/locales/sv.json +++ b/src/locales/sv.json @@ -11,9 +11,9 @@ "pad.toolbar.bold.title": "Fet (Ctrl-B)", "pad.toolbar.italic.title": "Kursiv (Ctrl-I)", "pad.toolbar.underline.title": "Understruken (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Genomstruken", - "pad.toolbar.ol.title": "Numrerad lista", - "pad.toolbar.ul.title": "Osorterad lista", + "pad.toolbar.strikethrough.title": "Genomstruken (Ctrl+5)", + "pad.toolbar.ol.title": "Numrerad lista (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Onumrerad lista (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Öka indrag (TABB)", "pad.toolbar.unindent.title": "Minska indrag (Shift+TABB)", "pad.toolbar.undo.title": "Ångra (Ctrl-Z)", @@ -52,7 +52,7 @@ "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (Open Document Format)", "pad.importExport.exportdokuwiki": "DokuWiki", - "pad.importExport.abiword.innerHTML": "Du kan endast importera från oformaterad text eller html-format. För mer avancerade importeringsfunktioner, var god installera abiword.", + "pad.importExport.abiword.innerHTML": "Du kan endast importera från oformaterad text eller HTML-format. För mer avancerade importeringsfunktioner, var god installera abiword.", "pad.modals.connected": "Ansluten.", "pad.modals.reconnecting": "Återansluter till ditt block...", "pad.modals.forcereconnect": "Tvinga återanslutning", @@ -60,7 +60,7 @@ "pad.modals.userdup.explanation": "Detta block verkar vara öppet i mer än ett fönster på denna dator.", "pad.modals.userdup.advice": "Återanslut för att använda detta fönster istället.", "pad.modals.unauth": "Inte godkänd", - "pad.modals.unauth.explanation": "Din behörighet ändrades medan du visar denna sida. Försök att återansluta.", + "pad.modals.unauth.explanation": "Din behörighet ändrades medan du visade denna sida. Försök att återansluta.", "pad.modals.looping.explanation": "Kommunikationsproblem med synkroniseringsservern har uppstått.", "pad.modals.looping.cause": "Kanske du är ansluten via en inkompatibel brandvägg eller proxy.", "pad.modals.initsocketfail": "Servern kan inte nås.", @@ -69,7 +69,7 @@ "pad.modals.slowcommit.explanation": "Servern svarar inte.", "pad.modals.slowcommit.cause": "Detta kan bero på problem med nätverksanslutningen.", "pad.modals.badChangeset.explanation": "En redigering som du gjort klassificerades som otillåten av synkroniseringsservern.", - "pad.modals.badChangeset.cause": "Detta kan bero på en felaktig konfiguration av servern eller något annat oväntad beteende. Var god kontakta tjänstadministratören om du anser att detta är ett fel. Försök ansluta igen för att fortsätta redigera.", + "pad.modals.badChangeset.cause": "Detta kan bero på en felaktig konfiguration av servern eller något annat oväntad beteende. Var god kontakta tjänsteadministratören om du upplever att detta är ett fel. Försök att ansluta igen för att fortsätta redigera.", "pad.modals.corruptPad.explanation": "Blocket du försöker komma åt är skadat.", "pad.modals.corruptPad.cause": "Detta kan bero på en felaktig konfiguration av servern eller något annat oväntad beteende. Var god kontakta tjänstadministratören.", "pad.modals.deleted": "Raderad.", @@ -84,7 +84,7 @@ "pad.chat": "Chatt", "pad.chat.title": "Öppna chatten för detta block.", "pad.chat.loadmessages": "Läs in fler meddelanden", - "timeslider.pageTitle": "Tidsreglage för {{appTitle}}", + "timeslider.pageTitle": "{{appTitle}} tidsreglage", "timeslider.toolbar.returnbutton": "Återvänd till blocket", "timeslider.toolbar.authors": "Författare:", "timeslider.toolbar.authorsList": "Inga författare", diff --git a/src/locales/vi.json b/src/locales/vi.json index 608e9645..3d5cb66d 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -3,7 +3,8 @@ "authors": [ "Baonguyen21022003", "Minh Nguyen", - "Tuankiet65" + "Tuankiet65", + "Max20091" ] }, "index.newPad": "Tạo một Pad mới", @@ -11,9 +12,9 @@ "pad.toolbar.bold.title": "In đậm (Ctrl-B)", "pad.toolbar.italic.title": "In nghiêng (Ctrl-I)", "pad.toolbar.underline.title": "Gạch chân (Ctrl-U)", - "pad.toolbar.strikethrough.title": "Gạch ngang", - "pad.toolbar.ol.title": "Danh sách Có Đánh số", - "pad.toolbar.ul.title": "Danh sách Không Đánh số", + "pad.toolbar.strikethrough.title": "Gạch ngang (Ctrl+5)", + "pad.toolbar.ol.title": "Danh sách Có Đánh số (Ctrl+Shift+N)", + "pad.toolbar.ul.title": "Danh sách Không Đánh số (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Tăng lề (TAB)", "pad.toolbar.unindent.title": "Giảm lề (Shift+TAB)", "pad.toolbar.undo.title": "Hoàn tác (Ctrl-Z)", diff --git a/src/locales/zh-hant.json b/src/locales/zh-hant.json index 0707648a..3b084e3d 100644 --- a/src/locales/zh-hant.json +++ b/src/locales/zh-hant.json @@ -14,9 +14,9 @@ "pad.toolbar.bold.title": "粗體(Ctrl-B)", "pad.toolbar.italic.title": "斜體(Ctrl-I)", "pad.toolbar.underline.title": "底線(Ctrl-U)", - "pad.toolbar.strikethrough.title": "刪除線", - "pad.toolbar.ol.title": "有序清單", - "pad.toolbar.ul.title": "無序清單", + "pad.toolbar.strikethrough.title": "刪除線(Ctrl+5)", + "pad.toolbar.ol.title": "有序清單(Ctrl+Shift+N)", + "pad.toolbar.ul.title": "無序清單(Ctrl+Shift+L)", "pad.toolbar.indent.title": "縮排(TAB)", "pad.toolbar.unindent.title": "凸排(Shift+TAB)", "pad.toolbar.undo.title": "撤銷(Ctrl-Z)", @@ -94,7 +94,7 @@ "timeslider.toolbar.exportlink.title": "匯出", "timeslider.exportCurrent": "匯出當前版本為:", "timeslider.version": "版本{{version}}", - "timeslider.saved": "{{year}}年{{month}}月{{day}}日儲存", + "timeslider.saved": "{{year}}年{{month}}{{day}}日儲存", "timeslider.dateformat": "{{year}}年{{month}}月{{day}}日 {{hours}}:{{minutes}}:{{seconds}}", "timeslider.month.january": "1月", "timeslider.month.february": "2月",