diff --git a/doc/api/http_api.md b/doc/api/http_api.md index 19d2e7f48..1ae2ea1c8 100644 --- a/doc/api/http_api.md +++ b/doc/api/http_api.md @@ -294,15 +294,14 @@ returns the text of a pad formatted as HTML * `{code: 0, message:"ok", data: {html:"Welcome Text
More Text"}}` * `{code: 1, message:"padID does not exist", data: null}` -#### setHTML(padID, text) +#### setHTML(padID, html) * API >= 1 -sets the html of a pad +sets the text of a pad based on HTML, HTML must be well formed. Malformed HTML will send a warning to the API log. *Example returns:* * `{code: 0, message:"ok", data: null}` * `{code: 1, message:"padID does not exist", data: null}` - * `{code: 1, message:"text too long", data: null}` #### getAttributePool(padID) * API >= 1.2.8 diff --git a/src/locales/ast.json b/src/locales/ast.json index c02790d9b..28fa2d0a9 100644 --- a/src/locales/ast.json +++ b/src/locales/ast.json @@ -1,8 +1,8 @@ { "@metadata": { - "authors": { - "1": "Xuacu" - } + "authors": [ + "Xuacu" + ] }, "index.newPad": "Nuevu bloc", "index.createOpenPad": "o crear/abrir un bloc col nome:", diff --git a/src/locales/da.json b/src/locales/da.json index e508e540c..fdcb4d7db 100644 --- a/src/locales/da.json +++ b/src/locales/da.json @@ -1,10 +1,10 @@ { "@metadata": { - "authors": { - "0": "Christian List", - "1": "Peter Alberti", - "3": "Steenth" - } + "authors": [ + "Christian List", + "Peter Alberti", + "Steenth" + ] }, "index.newPad": "Ny Pad", "index.createOpenPad": "eller opret/åbn en Pad med navnet:", diff --git a/src/locales/de.json b/src/locales/de.json index c2bc1b8ce..8a4acd1c8 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1,11 +1,11 @@ { "@metadata": { - "authors": { - "0": "Metalhead64", - "1": "Mklehr", - "2": "Nipsky", - "4": "Wikinaut" - } + "authors": [ + "Metalhead64", + "Mklehr", + "Nipsky", + "Wikinaut" + ] }, "index.newPad": "Neues Pad", "index.createOpenPad": "Pad mit folgendem Namen öffnen:", diff --git a/src/locales/es.json b/src/locales/es.json index 4b0200cb1..eade2c9b3 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1,16 +1,16 @@ { "@metadata": { - "authors": { - "0": "Armando-Martin", - "1": "Jacobo", - "2": "Joker", - "3": "Larjona", - "4": "Mklehr", - "5": "Rubenwap", - "7": "VegaDark", - "8": "Vivaelcelta", - "9": "Xuacu" - } + "authors": [ + "Armando-Martin", + "Jacobo", + "Joker", + "Larjona", + "Mklehr", + "Rubenwap", + "VegaDark", + "Vivaelcelta", + "Xuacu" + ] }, "index.newPad": "Nuevo Pad", "index.createOpenPad": "o crea/abre un Pad con el nombre:", diff --git a/src/locales/fa.json b/src/locales/fa.json index 08456048d..2cc29f013 100644 --- a/src/locales/fa.json +++ b/src/locales/fa.json @@ -1,13 +1,13 @@ { "@metadata": { - "authors": { - "0": "BMRG14", - "1": "Dalba", - "2": "Ebraminio", - "3": "Reza1615", - "5": "ZxxZxxZ", - "6": "الناز" - } + "authors": [ + "BMRG14", + "Dalba", + "Ebraminio", + "Reza1615", + "ZxxZxxZ", + "الناز" + ] }, "index.newPad": "دفترچه یادداشت تازه", "index.createOpenPad": "یا ایجاد/بازکردن یک دفترچه یادداشت با نام:", diff --git a/src/locales/fi.json b/src/locales/fi.json index b69833d25..991407cb2 100644 --- a/src/locales/fi.json +++ b/src/locales/fi.json @@ -1,15 +1,16 @@ { "@metadata": { - "authors": { - "0": "Artnay", - "1": "Jl", - "2": "Lliehu", - "3": "Nedergard", - "4": "Nike", - "6": "Stryn", - "7": "Veikk0.ma", - "8": "VezonThunder" - } + "authors": [ + "Artnay", + "Jl", + "Lliehu", + "Nedergard", + "Nike", + "Stryn", + "Tomi Toivio", + "Veikk0.ma", + "VezonThunder" + ] }, "index.newPad": "Uusi muistio", "index.createOpenPad": "tai luo tai avaa muistio nimellä:", @@ -19,8 +20,8 @@ "pad.toolbar.strikethrough.title": "Yliviivaus", "pad.toolbar.ol.title": "Numeroitu lista", "pad.toolbar.ul.title": "Numeroimaton lista", - "pad.toolbar.indent.title": "Sisennä", - "pad.toolbar.unindent.title": "Ulonna", + "pad.toolbar.indent.title": "Sisennä (TAB)", + "pad.toolbar.unindent.title": "Ulonna (Shift+TAB)", "pad.toolbar.undo.title": "Kumoa (Ctrl-Z)", "pad.toolbar.redo.title": "Tee uudelleen (Ctrl-Y)", "pad.toolbar.clearAuthorship.title": "Poista kirjoittajavärit", diff --git a/src/locales/fr.json b/src/locales/fr.json index a61d90b07..20900640e 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1,22 +1,22 @@ { "@metadata": { - "authors": { - "0": "Cquoi", - "1": "Crochet.david", - "2": "Gomoko", - "3": "Goofy", - "4": "Goofy-bz", - "5": "Jean-Frédéric", - "6": "Leviathan", - "7": "McDutchie", - "8": "Metroitendo", - "9": "Od1n", - "10": "Peter17", - "11": "Quenenni", - "12": "Rastus Vernon", - "14": "Stephane Cottin", - "15": "Tux-tn" - } + "authors": [ + "Cquoi", + "Crochet.david", + "Gomoko", + "Goofy", + "Goofy-bz", + "Jean-Frédéric", + "Leviathan", + "McDutchie", + "Metroitendo", + "Od1n", + "Peter17", + "Quenenni", + "Rastus Vernon", + "Stephane Cottin", + "Tux-tn" + ] }, "index.newPad": "Nouveau pad", "index.createOpenPad": "ou créer/ouvrir un pad intitulé :", diff --git a/src/locales/gl.json b/src/locales/gl.json index f728ec0b7..3a216e864 100644 --- a/src/locales/gl.json +++ b/src/locales/gl.json @@ -1,8 +1,8 @@ { "@metadata": { - "authors": { - "1": "Toliño" - } + "authors": [ + "Toliño" + ] }, "index.newPad": "Novo documento", "index.createOpenPad": "ou cree/abra un documento co nome:", diff --git a/src/locales/he.json b/src/locales/he.json index 908a27918..41915aac0 100644 --- a/src/locales/he.json +++ b/src/locales/he.json @@ -1,11 +1,11 @@ { "@metadata": { - "authors": { - "0": "Amire80", - "1": "Ofrahod", - "3": "YaronSh", - "4": "תומר ט" - } + "authors": [ + "Amire80", + "Ofrahod", + "YaronSh", + "תומר ט" + ] }, "index.newPad": "פנקס חדש", "index.createOpenPad": "ליצור או לפתוח פנקס בשם:", diff --git a/src/locales/hu.json b/src/locales/hu.json index 8c01edf0a..c3f594ce8 100644 --- a/src/locales/hu.json +++ b/src/locales/hu.json @@ -1,11 +1,11 @@ { "@metadata": { - "authors": { - "0": "Dj", - "1": "Misibacsi", - "2": "R-Joe", - "4": "Tgr" - } + "authors": [ + "Dj", + "Misibacsi", + "R-Joe", + "Tgr" + ] }, "index.newPad": "Új notesz", "index.createOpenPad": "vagy notesz létrehozása ezen a néven:", diff --git a/src/locales/it.json b/src/locales/it.json index 8e98a6846..087cc0c9d 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -1,11 +1,11 @@ { "@metadata": { - "authors": { - "0": "Beta16", - "1": "Gianfranco", - "2": "Muxator", - "4": "Vituzzu" - } + "authors": [ + "Beta16", + "Gianfranco", + "Muxator", + "Vituzzu" + ] }, "index.newPad": "Nuovo Pad", "index.createOpenPad": "o creare o aprire un Pad con il nome:", diff --git a/src/locales/ko.json b/src/locales/ko.json index 5e7d4308c..459ba376b 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1,9 +1,9 @@ { "@metadata": { - "authors": { - "0": "Hym411", - "2": "아라" - } + "authors": [ + "Hym411", + "아라" + ] }, "index.newPad": "새 패드", "index.createOpenPad": "또는 다음 이름으로 패드 만들기/열기:", diff --git a/src/locales/ksh.json b/src/locales/ksh.json index 6bb49dff4..49dcb673c 100644 --- a/src/locales/ksh.json +++ b/src/locales/ksh.json @@ -1,8 +1,8 @@ { "@metadata": { - "authors": { - "1": "Purodha" - } + "authors": [ + "Purodha" + ] }, "index.newPad": "Neu Padd", "index.createOpenPad": "udder maach e Padd op med däm Naame:", diff --git a/src/locales/lb.json b/src/locales/lb.json index 641e61a05..414fa8c1b 100644 --- a/src/locales/lb.json +++ b/src/locales/lb.json @@ -1,9 +1,9 @@ { "@metadata": { - "authors": { - "0": "Robby", - "2": "Soued031" - } + "authors": [ + "Robby", + "Soued031" + ] }, "index.newPad": "Neie Pad", "pad.toolbar.ol.title": "Numeréiert Lëscht", diff --git a/src/locales/ms.json b/src/locales/ms.json index 2d8e94105..1204e47ab 100644 --- a/src/locales/ms.json +++ b/src/locales/ms.json @@ -12,8 +12,8 @@ "pad.toolbar.strikethrough.title": "Garis lorek", "pad.toolbar.ol.title": "Senarai tertib", "pad.toolbar.ul.title": "Senarai tak tertib", - "pad.toolbar.indent.title": "Engsot ke dalam", - "pad.toolbar.unindent.title": "Engsot ke luar", + "pad.toolbar.indent.title": "Engsot ke dalam (TAB)", + "pad.toolbar.unindent.title": "Engsot ke luar (Shift + TAB)", "pad.toolbar.undo.title": "Buat asal (Ctrl-Z)", "pad.toolbar.redo.title": "Buat semula (Ctrl-Y)", "pad.toolbar.clearAuthorship.title": "Padamkan Warna Pengarang", @@ -66,11 +66,15 @@ "pad.modals.initsocketfail.cause": "Ini mungkin disebabkan oleh masalah dengan pelayar atau sambungan internet anda.", "pad.modals.slowcommit.explanation": "Pelayan tidak membalas.", "pad.modals.slowcommit.cause": "Ini mungkin disebabkan oleh masalah dengan kesambungan rangkaian anda.", + "pad.modals.badChangeset.explanation": "Suntingan yang telah anda lakukan telah dikira sebagai terlarang oleh pelayan penyegerakan.", + "pad.modals.badChangeset.cause": "Ini mungkin disebabkan oleh konfigurasi pelayan salah atau sesuatu kelakuan yang tidak dijangka. Sila hubungi penyelia servis anda jika anda merasakan ini adalah satu kesilapan. Cuba sambungkan semula talian untuk terus menyuntung.", + "pad.modals.corruptPad.explanation": "Pad yang anda cuba akses itu telah tercemar.", + "pad.modals.corruptPad.cause": "Ini mungkin disebabkan oleh konfigurasi pelayan salah atau sesuatu kelakuan yang tidak dijangka. Sila hubungi penyelia servis anda.", "pad.modals.deleted": "Dihapuskan.", "pad.modals.deleted.explanation": "Pad ini telah dibuang.", "pad.modals.disconnected": "Sambungan anda telah diputuskan.", "pad.modals.disconnected.explanation": "Sambungan ke pelayan terputus", - "pad.modals.disconnected.cause": "Pelayan mungkin tidak dapat dicapai. Sila beritahu kami jika masalah ini berterusan.", + "pad.modals.disconnected.cause": "Pelayan mungkin tidak dapat dicapai. Sila beritahu penyelia servis jika masalah ini berterusan.", "pad.share": "Kongsikan pad ini", "pad.share.readonly": "Baca sahaja", "pad.share.link": "Pautan", diff --git a/src/locales/ne.json b/src/locales/ne.json new file mode 100644 index 000000000..4ffd69b5c --- /dev/null +++ b/src/locales/ne.json @@ -0,0 +1,86 @@ +{ + "@metadata": { + "authors": [ + "सरोज कुमार ढकाल" + ] + }, + "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.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": "मोनोस्पेस", + "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": "माइक्रोसफ्ट वर्ड", + "pad.importExport.exportpdf": "पिडिएफ", + "pad.importExport.exportopen": "ओडिएफ(खुल्ला कागजात ढाँचा)", + "pad.importExport.exportdokuwiki": "डकुविकि", + "pad.modals.connected": "जोडीएको।", + "pad.modals.reconnecting": "तपाईँको प्याडमा पुन: जडान गर्दै", + "pad.modals.deleted": "मेटिएको ।", + "pad.modals.deleted.explanation": "यो प्याड हटाइसकेको छ ।", + "pad.modals.disconnected": "तपाईँको जडान अवरुद्ध भयो ।", + "pad.modals.disconnected.explanation": "तपाईँको सर्भरसँगको जडान अवरुद्ध भयो", + "pad.share": "यस प्यडलाई बाड्ने", + "pad.share.readonly": "पढ्ने मात्र", + "pad.share.link": "लिङ्क", + "pad.chat": "कुराकानी", + "pad.chat.title": "यस प्याडको लागि कुराकानी खोल्ने", + "pad.chat.loadmessages": "थप सन्देशहरू खोल्ने", + "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}} unnamed {[plural(num) one: author, other: authors ]}", + "pad.savedrevs.marked": "यस संस्करणलाई संग्रहितको रुपमा चिनो लगाइएको छैन", + "pad.userlist.entername": "तपाईँको नाम लेख्नुहोस्", + "pad.userlist.unnamed": "नाम नखुलाइएको", + "pad.userlist.guest": "पाहुना", + "pad.userlist.deny": "अस्वीकार गर्ने", + "pad.userlist.approve": "स्वीकृत गर्ने" +} \ No newline at end of file diff --git a/src/locales/nn.json b/src/locales/nn.json index 5a98353ea..11c24018d 100644 --- a/src/locales/nn.json +++ b/src/locales/nn.json @@ -1,8 +1,8 @@ { "@metadata": { - "authors": { - "1": "Unhammer" - } + "authors": [ + "Unhammer" + ] }, "index.newPad": "Ny blokk", "index.createOpenPad": "eller opprett/opna ei blokk med namnet:", diff --git a/src/locales/pl.json b/src/locales/pl.json index 4f4d7a92a..6ea8ca421 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -1,11 +1,11 @@ { "@metadata": { - "authors": { - "0": "Rezonansowy", - "2": "Ty221", - "3": "WTM", - "4": "Woytecr" - } + "authors": [ + "Rezonansowy", + "Ty221", + "WTM", + "Woytecr" + ] }, "index.newPad": "Nowy dokument", "index.createOpenPad": "lub stwórz/otwórz dokument o nazwie:", @@ -15,8 +15,8 @@ "pad.toolbar.strikethrough.title": "Przekreślenie", "pad.toolbar.ol.title": "Lista uporządkowana", "pad.toolbar.ul.title": "Lista nieuporządkowana", - "pad.toolbar.indent.title": "Wcięcie", - "pad.toolbar.unindent.title": "Zmniejsz wcięcie", + "pad.toolbar.indent.title": "Wcięcie (TAB)", + "pad.toolbar.unindent.title": "Wcięcie (Shift + TAB)", "pad.toolbar.undo.title": "Cofnij (Ctrl-Z)", "pad.toolbar.redo.title": "Ponów (Ctrl-Y)", "pad.toolbar.clearAuthorship.title": "Usuń kolory autorów", diff --git a/src/locales/pt.json b/src/locales/pt.json index cf32223bd..e91ef8245 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -1,11 +1,11 @@ { "@metadata": { - "authors": { - "0": "Hamilton Abreu", - "1": "Luckas", - "3": "Tuliouel", - "4": "Waldir" - } + "authors": [ + "Hamilton Abreu", + "Luckas", + "Tuliouel", + "Waldir" + ] }, "index.newPad": "Nova Nota", "index.createOpenPad": "ou crie/abra uma Nota com o nome:", diff --git a/src/locales/sv.json b/src/locales/sv.json index e0b9e69ae..c4455ff4d 100644 --- a/src/locales/sv.json +++ b/src/locales/sv.json @@ -1,9 +1,9 @@ { "@metadata": { - "authors": { - "0": "Lokal Profil", - "2": "WikiPhoenix" - } + "authors": [ + "Lokal Profil", + "WikiPhoenix" + ] }, "index.newPad": "Nytt block", "index.createOpenPad": "eller skapa/öppna ett block med namnet:", diff --git a/src/locales/te.json b/src/locales/te.json index 2f4372bc6..d116afb59 100644 --- a/src/locales/te.json +++ b/src/locales/te.json @@ -1,10 +1,10 @@ { "@metadata": { - "authors": { - "0": "JVRKPRASAD", - "1": "Malkum", - "3": "Veeven" - } + "authors": [ + "JVRKPRASAD", + "Malkum", + "Veeven" + ] }, "index.newPad": "కొత్త పలక", "index.createOpenPad": "ఒక పేరుతో పలకని సృష్టించండి లేదా అదే పేరుతో ఉన్న పలకని తెరవండి", diff --git a/src/locales/tr.json b/src/locales/tr.json index 27f308d61..56c4ad9b7 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -3,6 +3,7 @@ "authors": [ "Emperyan", "Erdemaslancan", + "Joseph", "Meelo" ] }, @@ -14,8 +15,8 @@ "pad.toolbar.strikethrough.title": "Üstü Çizili", "pad.toolbar.ol.title": "Sıralı liste", "pad.toolbar.ul.title": "Sırasız Liste", - "pad.toolbar.indent.title": "Girintiyi arttır", - "pad.toolbar.unindent.title": "Girintiyi azalt", + "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.clearAuthorship.title": "Yazarlık Renklerini Temizle", diff --git a/src/locales/uk.json b/src/locales/uk.json index cddba5713..d1cf0b32d 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -1,12 +1,12 @@ { "@metadata": { - "authors": { - "0": "Andriykopanytsia", - "1": "Base", - "2": "Olvin", - "4": "Steve.rusyn", - "5": "SteveR" - } + "authors": [ + "Andriykopanytsia", + "Base", + "Olvin", + "Steve.rusyn", + "SteveR" + ] }, "index.newPad": "Створити", "index.createOpenPad": "або створити/відкрити документ з назвою:", diff --git a/src/locales/zh-hans.json b/src/locales/zh-hans.json index a463ad9ac..642f3be43 100644 --- a/src/locales/zh-hans.json +++ b/src/locales/zh-hans.json @@ -21,8 +21,8 @@ "pad.toolbar.strikethrough.title": "删除线", "pad.toolbar.ol.title": "有序列表", "pad.toolbar.ul.title": "无序列表", - "pad.toolbar.indent.title": "增加缩进", - "pad.toolbar.unindent.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": "清除作者颜色", diff --git a/src/locales/zh-hant.json b/src/locales/zh-hant.json index 75431c24f..6950226d7 100644 --- a/src/locales/zh-hant.json +++ b/src/locales/zh-hant.json @@ -1,12 +1,12 @@ { "@metadata": { - "authors": { - "0": "Justincheng12345", - "1": "Liuxinyu970226", - "2": "Shangkuanlc", - "3": "Shirayuki", - "5": "Simon Shek" - } + "authors": [ + "Justincheng12345", + "Liuxinyu970226", + "Shangkuanlc", + "Shirayuki", + "Simon Shek" + ] }, "index.newPad": "新Pad", "index.createOpenPad": "或創建/開啟以下名稱的pad:", diff --git a/src/node/db/API.js b/src/node/db/API.js index 349953cb2..98bc8029d 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -361,6 +361,8 @@ exports.getHTML = function(padID, rev, callback) exportHtml.getPadHTML(pad, rev, function(err, html) { if(ERR(err, callback)) return; + html = "" +html; // adds HTML head + html += ""; data = {html: html}; callback(null, data); }); @@ -371,6 +373,8 @@ exports.getHTML = function(padID, rev, callback) exportHtml.getPadHTML(pad, undefined, function (err, html) { if(ERR(err, callback)) return; + html = "" +html; // adds HTML head + html += ""; data = {html: html}; callback(null, data); }); @@ -378,15 +382,30 @@ exports.getHTML = function(padID, rev, callback) }); } +/** +setHTML(padID, html) sets the text of a pad based on HTML + +Example returns: + +{code: 0, message:"ok", data: null} +{code: 1, message:"padID does not exist", data: null} +*/ exports.setHTML = function(padID, html, callback) { + //html is required + if(typeof html != "string") + { + callback(new customError("html is no string","apierror")); + return; + } + //get the pad getPadSafe(padID, true, function(err, pad) { if(ERR(err, callback)) return; // add a new changeset with the new html to the pad - importHtml.setPadHTML(pad, cleanText(html)); + importHtml.setPadHTML(pad, cleanText(html), callback); //update the clients on the pad padMessageHandler.updatePadClients(pad, callback); diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 180517d1f..4f0f268b7 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -203,7 +203,11 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe { curRev++; var cs = changesets[curRev]; - atext = Changeset.applyToAText(cs, atext, apool); + try{ + atext = Changeset.applyToAText(cs, atext, apool); + }catch(e) { + return callback(e) + } } callback(null); diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 748b8382a..774ebf081 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1,6 +1,6 @@ /** - * The MessageHandler handles all Messages that comes from Socket.IO and controls the sessions - */ + * The MessageHandler handles all Messages that comes from Socket.IO and controls the sessions + */ /* * Copyright 2009 Google Inc., 2011 Peter 'Pita' Martischka (Primary Technology Ltd) @@ -106,12 +106,12 @@ exports.kickSessionsFromPad = function(padID) * @param client the client that leaves */ exports.handleDisconnect = function(client) -{ +{ stats.meter('disconnects').mark(); - + //save the padname of this session var session = sessioninfos[client.id]; - + //if this connection was already etablished with a handshake, send a disconnect message to the others if(session && session.author) { @@ -128,7 +128,7 @@ exports.handleDisconnect = function(client) authorManager.getAuthorColorId(session.author, function(err, color) { ERR(err); - + //prepare the notification for the other users on the pad, that this user left var messageToTheOtherUsers = { "type": "COLLABROOM", @@ -142,14 +142,14 @@ exports.handleDisconnect = function(client) } } }; - + //Go trough all user that are still on the pad, and send them the USER_LEAVE message client.broadcast.to(session.padId).json.send(messageToTheOtherUsers); - }); + }); } - + //Delete the sessioninfos entrys of this session - delete sessioninfos[client.id]; + delete sessioninfos[client.id]; } /** @@ -158,7 +158,7 @@ exports.handleDisconnect = function(client) * @param message the message from the client */ exports.handleMessage = function(client, message) -{ +{ if(message == null) { return; @@ -174,7 +174,7 @@ exports.handleMessage = function(client, message) var handleMessageHook = function(callback){ var dropMessage = false; - // Call handleMessage hook. If a plugin returns null, the message will be dropped. Note that for all messages + // Call handleMessage hook. If a plugin returns null, the message will be dropped. Note that for all messages // handleMessage will be called, even if the client is not authorized hooks.aCallAll("handleMessage", { client: client, message: message }, function ( err, messages ) { if(ERR(err, callback)) return; @@ -183,7 +183,7 @@ exports.handleMessage = function(client, message) dropMessage = true; } }); - + // If no plugins explicitly told us to drop the message, its ok to proceed if(!dropMessage){ callback() }; }); @@ -259,7 +259,7 @@ exports.handleMessage = function(client, message) var checkAccessCallback = function(err, statusObject) { if(ERR(err, callback)) return; - + //access was granted if(statusObject.accessStatus == "grant") { @@ -297,17 +297,17 @@ exports.handleMessage = function(client, message) function handleSaveRevisionMessage(client, message){ var padId = sessioninfos[client.id].padId; var userId = sessioninfos[client.id].author; - + padManager.getPad(padId, function(err, pad) { if(ERR(err)) return; - + pad.addSavedRevision(pad.head, userId); }); } /** - * Handles a custom message, different to the function below as it handles objects not strings and you can + * Handles a custom message, different to the function below as it handles objects not strings and you can * direct the message to specific sessionID * * @param msg {Object} the message we're sending @@ -356,10 +356,10 @@ function handleChatMessage(client, message) var userId = sessioninfos[client.id].author; var text = message.data.text; var padId = sessioninfos[client.id].padId; - + var pad; var userName; - + async.series([ //get the pad function(callback) @@ -385,7 +385,7 @@ function handleChatMessage(client, message) { //save the chat message pad.appendChatMessage(text, userId, time); - + var msg = { type: "COLLABROOM", data: { @@ -396,10 +396,10 @@ function handleChatMessage(client, message) text: text } }; - + //broadcast the chat message to everyone on the pad socketio.sockets.in(padId).json.send(msg); - + callback(); } ], function(err) @@ -425,20 +425,20 @@ function handleGetChatMessages(client, message) messageLogger.warn("Dropped message, GetChatMessages Message has no start!"); return; } - + var start = message.data.start; var end = message.data.end; var count = start - count; - + if(count < 0 && count > 100) { messageLogger.warn("Dropped message, GetChatMessages Message, client requested invalid amout of messages!"); return; } - + var padId = sessioninfos[client.id].padId; var pad; - + async.series([ //get the pad function(callback) @@ -488,10 +488,10 @@ function handleSuggestUserName(client, message) messageLogger.warn("Dropped message, suggestUserName Message has no unnamedId!"); return; } - + var padId = sessioninfos[client.id].padId, clients = socketio.sockets.clients(padId); - + //search the author and send him this message for(var i = 0; i < clients.length; i++) { var session = sessioninfos[clients[i].id]; @@ -520,14 +520,14 @@ function handleUserInfoUpdate(client, message) messageLogger.warn("Dropped message, USERINFO_UPDATE Message has no colorId!"); return; } - + //Find out the author name of this session var author = sessioninfos[client.id].author; - + //Tell the authorManager about the new attributes authorManager.setAuthorColorId(author, message.data.userInfo.colorId); authorManager.setAuthorName(author, message.data.userInfo.name); - + var padId = sessioninfos[client.id].padId; var infoMsg = { @@ -545,7 +545,7 @@ function handleUserInfoUpdate(client, message) } } }; - + //Send the other clients on the pad the update message client.broadcast.to(padId).json.send(infoMsg); } @@ -588,7 +588,7 @@ function handleUserChanges(data, cb) messageLogger.warn("Dropped message, USER_CHANGES Message has no changeset!"); return cb(); } - + //get all Vars we need var baseRev = message.data.baseRev; var wireApool = (new AttributePool()).fromJsonable(message.data.apool); @@ -596,12 +596,12 @@ function handleUserChanges(data, cb) // The client might disconnect between our callbacks. We should still // finish processing the changeset, so keep a reference to the session. var thisSession = sessioninfos[client.id]; - + var r, apool, pad; // Measure time to process edit var stopWatch = stats.timer('edits').start(); - + async.series([ //get the pad function(callback) @@ -617,7 +617,7 @@ function handleUserChanges(data, cb) function(callback) { //ex. _checkChangesetAndPool - + try { // Verify that the changeset has valid syntax and is in canonical form @@ -644,9 +644,9 @@ function handleUserChanges(data, cb) if('author' == attr[0] && attr[1] != thisSession.author) throw new Error("Trying to submit changes as another author in changeset "+changeset); }) } - + //ex. adoptChangesetAttribs - + //Afaik, it copies the new attributes from the changeset, to the global Attribute Pool changeset = Changeset.moveOpsToNewPool(changeset, wireApool, pad.pool); } @@ -657,7 +657,7 @@ function handleUserChanges(data, cb) stats.meter('failedChangesets').mark(); return callback(new Error("Can't apply USER_CHANGES, because "+e.message)); } - + //ex. applyUserChanges apool = pad.pool; r = baseRev; @@ -671,7 +671,7 @@ function handleUserChanges(data, cb) function(callback) { r++; - + pad.getRevisionChangeset(r, function(err, c) { if(ERR(err, callback)) return; @@ -704,16 +704,16 @@ function handleUserChanges(data, cb) function (callback) { var prevText = pad.text(); - - if (Changeset.oldLen(changeset) != prevText.length) + + if (Changeset.oldLen(changeset) != prevText.length) { client.json.send({disconnect:"badChangeset"}); stats.meter('failedChangesets').mark(); return callback(new Error("Can't apply USER_CHANGES "+changeset+" with oldLen " + Changeset.oldLen(changeset) + " to document of length " + prevText.length)); } - + pad.appendRevision(changeset, thisSession.author); - + var correctionChangeset = _correctMarkersInPad(pad.atext, pad.pool); if (correctionChangeset) { pad.appendRevision(correctionChangeset); @@ -724,7 +724,7 @@ function handleUserChanges(data, cb) var nlChangeset = Changeset.makeSplice(pad.text(), pad.text().length-1, 0, "\n"); pad.appendRevision(nlChangeset); } - + exports.updatePadClients(pad, function(er) { ERR(er) }); @@ -739,16 +739,16 @@ 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) return callback(); - + // since all clients usually get the same set of changesets, store them in local cache // to remove unnecessary roundtrip to the datalayer // TODO: in REAL world, if we're working without datalayer cache, all requests to revisions will be fired - // BEFORE first result will be landed to our cache object. The solution is to replace parallel processing + // BEFORE first result will be landed to our cache object. The solution is to replace parallel processing // via async.forEach with sequential for() loop. There is no real benefits of running this in parallel, // but benefit of reusing cached revision object is HUGE var revCache = {}; @@ -763,7 +763,7 @@ exports.updatePadClients = function(pad, callback) async.whilst( function (){ return sessioninfos[sid] && sessioninfos[sid].rev < pad.getHeadRevisionNumber()}, function(callback) - { + { var r = sessioninfos[sid].rev + 1; async.waterfall([ @@ -772,7 +772,7 @@ exports.updatePadClients = function(pad, callback) callback(null, revCache[r]); else pad.getRevision(r, callback); - }, + }, function(revision, callback) { revCache[r] = revision; @@ -800,8 +800,8 @@ exports.updatePadClients = function(pad, callback) author: author, currentTime: currentTime, timeDelta: currentTime - sessioninfos[sid].time - }}; - + }}; + client.json.send(wireMsg); } @@ -814,7 +814,7 @@ exports.updatePadClients = function(pad, callback) }, callback ); - },callback); + },callback); } /** @@ -830,11 +830,11 @@ function _correctMarkersInPad(atext, apool) { var offset = 0; while (iter.hasNext()) { var op = iter.next(); - + var hasMarker = _.find(AttributeManager.lineAttributes, function(attribute){ return Changeset.opAttributeValue(op, attribute, apool); }) !== undefined; - + if (hasMarker) { for(var i=0;i 0 && text.charAt(offset-1) != '\n') { @@ -864,7 +864,7 @@ function _correctMarkersInPad(atext, apool) { } /** - * Handles a CLIENT_READY. A CLIENT_READY is the first message from the client to the server. The Client sends his token + * Handles a CLIENT_READY. A CLIENT_READY is the first message from the client to the server. The Client sends his token * and the pad it wants to enter. The Server answers with the inital values (clientVars) of the pad * @param client the client that send this message * @param message the message from the client @@ -922,7 +922,7 @@ function handleClientReady(client, message) securityManager.checkAccess (padIds.padId, message.sessionID, message.token, message.password, function(err, statusObject) { if(ERR(err, callback)) return; - + //access was granted if(statusObject.accessStatus == "grant") { @@ -935,7 +935,7 @@ function handleClientReady(client, message) client.json.send({accessStatus: statusObject.accessStatus}) } }); - }, + }, //get all authordata of this new user, and load the pad-object from the database function(callback) { @@ -967,7 +967,7 @@ function handleClientReady(client, message) function(callback) { var authors = pad.getAllAuthors(); - + async.parallel([ //get timestamp of latest revission needed for timeslider function(callback) @@ -993,7 +993,7 @@ function handleClientReady(client, message) }, callback); } ], callback); - + }, //glue the clientVars together, send them and tell the other clients that a new one is there function(callback) @@ -1013,12 +1013,12 @@ 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; sessioninfos[client.id].readOnlyPadId = padIds.readOnlyPadId; 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 @@ -1056,7 +1056,7 @@ function handleClientReady(client, message) client.json.send({disconnect:"corruptPad"});// pull the breaks return callback(); } - + // Warning: never ever send padIds.padId to the client. If the // client is read only you would open a security hole 1 swedish // mile wide... @@ -1085,7 +1085,7 @@ function handleClientReady(client, message) "padId": message.padId, "initialTitle": "Pad: " + message.padId, "opts": {}, - // tell the client the number of the latest chat-message, which will be + // 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, @@ -1093,7 +1093,7 @@ function handleClientReady(client, message) "readonly": padIds.readonly, "serverTimestamp": new Date().getTime(), "userId": author, - "abiwordAvailable": settings.abiwordAvailable(), + "abiwordAvailable": settings.abiwordAvailable(), "plugins": { "plugins": plugins.plugins, "parts": plugins.parts, @@ -1106,18 +1106,18 @@ function handleClientReady(client, message) { clientVars.userName = authorName; } - + //call the clientVars-hook so plugins can modify them before they get sent to the client hooks.aCallAll("clientVars", { clientVars: clientVars, pad: pad }, function ( err, messages ) { if(ERR(err, callback)) return; - + _.each(messages, function(newVars) { //combine our old object with the new attributes from the hook for(var attr in newVars) { clientVars[attr] = newVars[attr]; } }); - + //Join the pad and start receiving updates client.join(padIds.padId); //Send the clientVars to the Client @@ -1126,9 +1126,9 @@ function handleClientReady(client, message) sessioninfos[client.id].rev = pad.getHeadRevisionNumber(); }); } - + sessioninfos[client.id].author = author; - + //prepare the notification for the other users on the pad, that this user joined var messageToTheOtherUsers = { "type": "COLLABROOM", @@ -1142,7 +1142,7 @@ function handleClientReady(client, message) } } }; - + //Add the authorname of this new User, if avaiable if(authorName != null) { @@ -1151,7 +1151,7 @@ function handleClientReady(client, message) // notify all existing users about new user 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) { @@ -1160,9 +1160,9 @@ function handleClientReady(client, message) //Jump over, if this session is the connection session if(roomClient.id == client.id) return callback(); - - - //Since sessioninfos might change while being enumerated, check if the + + + //Since sessioninfos might change while being enumerated, check if the //sessionID is still assigned to a valid session if(sessioninfos[roomClient.id] !== undefined) author = sessioninfos[roomClient.id].author; @@ -1178,7 +1178,7 @@ function handleClientReady(client, message) callback(null, historicalAuthorData[author]); else authorManager.getAuthor(author, callback); - }, + }, function (authorInfo, callback) { //Send the new User a Notification about this other user @@ -1207,7 +1207,7 @@ function handleClientReady(client, message) } /** - * Handles a request for a rough changeset, the timeslider client needs it + * Handles a request for a rough changeset, the timeslider client needs it */ function handleChangesetRequest(client, message) { @@ -1237,7 +1237,7 @@ function handleChangesetRequest(client, message) messageLogger.warn("Dropped message, changeset request has no requestID!"); return; } - + var granularity = message.data.granularity; var start = message.data.start; var end = start + (100 * granularity); @@ -1255,7 +1255,7 @@ function handleChangesetRequest(client, message) //build the requested rough changesets and send them back getChangesetInfo(padIds.padId, start, end, granularity, function(err, changesetInfo) { - ERR(err); + if(err) return console.error('Error while handling a changeset request for '+padIds.padId, err, message.data); var data = changesetInfo; data.requestID = message.data.requestID; @@ -1281,47 +1281,49 @@ function getChangesetInfo(padId, startNum, endNum, granularity, callback) var composedChangesets = {}; var revisionDate = []; var lines; - + var head_revision = 0; + async.series([ //get the pad from the database function(callback) { padManager.getPad(padId, function(err, _pad) - { + { if(ERR(err, callback)) return; pad = _pad; + head_revision = pad.getHeadRevisionNumber(); callback(); }); }, function(callback) - { + { //calculate the last full endnum var lastRev = pad.getHeadRevisionNumber(); if (endNum > lastRev+1) { endNum = lastRev+1; } endNum = Math.floor(endNum / granularity)*granularity; - + var compositesChangesetNeeded = []; var revTimesNeeded = []; - + //figure out which composite Changeset and revTimes we need, to load them in bulk var compositeStart = startNum; - while (compositeStart < endNum) + while (compositeStart < endNum) { var compositeEnd = compositeStart + granularity; - + //add the composite Changeset we needed compositesChangesetNeeded.push({start: compositeStart, end: compositeEnd}); - + //add the t1 time we need revTimesNeeded.push(compositeStart == 0 ? 0 : compositeStart - 1); //add the t2 time we need revTimesNeeded.push(compositeEnd - 1); - + compositeStart += granularity; } - + //get all needed db values parallel async.parallel([ function(callback) @@ -1358,58 +1360,57 @@ function getChangesetInfo(padId, startNum, endNum, granularity, callback) if(ERR(err, callback)) return; lines = _lines; callback(); - }); + }); } ], callback); }, //doesn't know what happens here excatly :/ function(callback) - { + { var compositeStart = startNum; - - while (compositeStart < endNum) + + while (compositeStart < endNum) { - if (compositeStart + granularity > endNum) + var compositeEnd = compositeStart + granularity; + if (compositeEnd > endNum || compositeEnd > head_revision) { break; } - - var compositeEnd = compositeStart + granularity; - + var forwards = composedChangesets[compositeStart + "/" + compositeEnd]; var backwards = Changeset.inverse(forwards, lines.textlines, lines.alines, pad.apool()); - + Changeset.mutateAttributionLines(forwards, lines.alines, pad.apool()); Changeset.mutateTextLines(forwards, lines.textlines); - + var forwards2 = Changeset.moveOpsToNewPool(forwards, pad.apool(), apool); var backwards2 = Changeset.moveOpsToNewPool(backwards, pad.apool(), apool); - + var t1, t2; - if (compositeStart == 0) + if (compositeStart == 0) { t1 = revisionDate[0]; } - else + else { t1 = revisionDate[compositeStart - 1]; } - + t2 = revisionDate[compositeEnd - 1]; - + timeDeltas.push(t2 - t1); forwardsChangesets.push(forwards2); backwardsChangesets.push(backwards2); - + compositeStart += granularity; } - + callback(); } ], function(err) { if(ERR(err, callback)) return; - + callback(null, {forwardsChangesets: forwardsChangesets, backwardsChangesets: backwardsChangesets, apool: apool.toJsonable(), @@ -1424,7 +1425,7 @@ function getChangesetInfo(padId, startNum, endNum, granularity, callback) * Tries to rebuild the getPadLines function of the original Etherpad * https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L263 */ -function getPadLines(padId, revNum, callback) +function getPadLines(padId, revNum, callback) { var atext; var result = {}; @@ -1435,7 +1436,7 @@ function getPadLines(padId, revNum, callback) function(callback) { padManager.getPad(padId, function(err, _pad) - { + { if(ERR(err, callback)) return; pad = _pad; callback(); @@ -1479,7 +1480,7 @@ function getPadLines(padId, revNum, callback) function composePadChangesets(padId, startNum, endNum, callback) { var pad; - var changesets = []; + var changesets = {}; var changeset; async.series([ @@ -1497,14 +1498,19 @@ function composePadChangesets(padId, startNum, endNum, callback) function(callback) { var changesetsNeeded=[]; - - //create a array for all changesets, we will + + var headNum = pad.getHeadRevisionNumber(); + if (endNum > headNum) + endNum = headNum; + if (startNum < 0) + startNum = 0; + //create a array for all changesets, we will //replace the values with the changeset later for(var r=startNum;r\n+<')); @@ -44,8 +39,15 @@ function setPadHTML(pad, html, callback) // Convert a dom tree into a list of lines and attribute liens // using the content collector object var cc = contentcollector.makeContentCollector(true, null, pad.pool); - cc.collectContent(doc.childNodes[0]); + try{ // we use a try here because if the HTML is bad it will blow up + cc.collectContent(doc.childNodes[0]); + }catch(e){ + apiLogger.warn("HTML was not properly formed", e); + return; // We don't process the HTML because it was bad.. + } + var result = cc.finish(); + apiLogger.debug('Lines:'); var i; for (i = 0; i < result.lines.length; i += 1) @@ -90,6 +92,7 @@ function setPadHTML(pad, html, callback) // the changeset is ready! var theChangeset = builder.toString(); apiLogger.debug('The changeset: ' + theChangeset); + pad.setText(""); pad.appendRevision(theChangeset); }