Browse Source

Merge pull request #272 from slr/tasty-markdown

tasty ~markdown revisited
master
miguelfreitas 9 years ago
parent
commit
cd8674c1dd
  1. 2
      following.html
  2. 2
      home.html
  3. 5
      js/interface_common.js
  4. 36
      js/interface_localization.js
  5. 2
      js/twister_following.js
  6. 356
      js/twister_formatpost.js
  7. 8
      options.html

2
following.html

@ -276,7 +276,7 @@
<div class="modal-header"> <div class="modal-header">
<h3></h3> <h3></h3>
<span id="closeModal" class="modal-close cancel">&times;</span> <span id="closeModal" class="modal-close cancel">&times;</span>
<span class="modal-back" onClick="history.back();">&lt;</span> <span class="modal-back">&lt;</span>
<span class="mark-all-as-read"></span> <span class="mark-all-as-read"></span>
</div> </div>
<div class="modal-content"></div> <div class="modal-content"></div>

2
home.html

@ -370,7 +370,7 @@
<div class="modal-header"> <div class="modal-header">
<h3></h3> <h3></h3>
<span id="closeModal" class="modal-close cancel">&times;</span> <span id="closeModal" class="modal-close cancel">&times;</span>
<span class="modal-back" onClick="history.back();">&lt;</span> <span class="modal-back">&lt;</span>
<span class="mark-all-as-read"></span> <span class="mark-all-as-read"></span>
</div> </div>
<div class="modal-content"></div> <div class="modal-content"></div>

5
js/interface_common.js

@ -1343,6 +1343,8 @@ function initInterfaceCommon() {
closeModal(); closeModal();
}); });
$('.modal-back').on('click', function() {history.back();});
$('.prompt-close').on('click', function(e) { $('.prompt-close').on('click', function(e) {
e.stopPropagation(); e.stopPropagation();
closeModalHandler('.prompt-wrapper'); closeModalHandler('.prompt-wrapper');
@ -1460,6 +1462,9 @@ $(document).ready(function()
initInterfaceLogin(); initInterfaceLogin();
} else if (page.indexOf("network.html") === 0) { } else if (page.indexOf("network.html") === 0) {
initInterfaceNetwork(); initInterfaceNetwork();
} else if (page.indexOf('options.html') === 0) {
initInterfaceCommon();
$.Options.initControls();
} else if (page.indexOf("profile-edit.html") === 0) { } else if (page.indexOf("profile-edit.html") === 0) {
initProfileEdit(); initProfileEdit();
} }

36
js/interface_localization.js

@ -40,6 +40,8 @@ if(preferredLanguage == "en"){
"Block chain information": "Block chain information", "Block chain information": "Block chain information",
"Block chain is up-to-date, twister is ready to use!": "Block chain is up-to-date, twister is ready to use!", "Block chain is up-to-date, twister is ready to use!": "Block chain is up-to-date, twister is ready to use!",
"Block generation": "Block generation ", "Block generation": "Block generation ",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Cancel", "Cancel": "Cancel",
"Change user": "Change user", "Change user": "Change user",
"Checking...": "Checking...", // checking if username is available "Checking...": "Checking...", // checking if username is available
@ -329,6 +331,8 @@ if(preferredLanguage == "es"){
"Block chain information": "Información de la cadena de bloques", "Block chain information": "Información de la cadena de bloques",
"Block chain is up-to-date, twister is ready to use!": "La cadena de bloques está puesta al día, twister está listo para usar!", "Block chain is up-to-date, twister is ready to use!": "La cadena de bloques está puesta al día, twister está listo para usar!",
"Block generation": "Generación de bloques ", "Block generation": "Generación de bloques ",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Cancelar", "Cancel": "Cancelar",
"Change user": "Cambiar de usuario", "Change user": "Cambiar de usuario",
"Checking...": "Comprobando ...", // checking if username is available "Checking...": "Comprobando ...", // checking if username is available
@ -602,6 +606,8 @@ if(preferredLanguage == "uk"){
"Block chain information": "Інформація про ланцюжок блоків", "Block chain information": "Інформація про ланцюжок блоків",
"Block chain is up-to-date, twister is ready to use!": "Ланцюг блоків оновлено, twister готовий до використання!", "Block chain is up-to-date, twister is ready to use!": "Ланцюг блоків оновлено, twister готовий до використання!",
"Block generation": "Генерація блоку ", "Block generation": "Генерація блоку ",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Відміна", "Cancel": "Відміна",
"Change user": "Змінити користувача", "Change user": "Змінити користувача",
"Checking...": "Перевірка...", // checking if username is available "Checking...": "Перевірка...", // checking if username is available
@ -874,6 +880,8 @@ if(preferredLanguage == "zh-CN"){
"Block chain information": "区块链信息", "Block chain information": "区块链信息",
"Block chain is up-to-date, twister is ready to use!": "区块链已经更新,Twister 已经可以使用!", "Block chain is up-to-date, twister is ready to use!": "区块链已经更新,Twister 已经可以使用!",
"Block generation": "区块生成器", "Block generation": "区块生成器",
"busted_oh": "噢,阻挡!",
"busted_avowal": "系统检测到此用户试图在这里注入恶意代码",
"Cancel": "取消", "Cancel": "取消",
"Change user": "切换用户", "Change user": "切换用户",
"Checking...": "检查中...", // checking if username is available "Checking...": "检查中...", // checking if username is available
@ -1108,11 +1116,11 @@ if(preferredLanguage == "zh-CN"){
"Messages": "消息", "Messages": "消息",
"Edit profile": "编辑个人简介", "Edit profile": "编辑个人简介",
"Top Trends": "热门趋势", "Top Trends": "热门趋势",
"Twistday Reminder": "Twistday Reminder", "Twistday Reminder": "Twistday周年纪念日提醒",
"Show upcoming in near future": "Show upcoming in near future", "Show upcoming in near future": "显示Twistday周年纪念日预告",
"Who's celebrating Twistday": "Who's celebrating Twistday", "Who's celebrating Twistday": "谁在庆祝自己的Twistday周年纪念日",
"Today's luckies:": "Today's luckies:", "Today's luckies:": "今天的幸运用户:",
"Upcoming ones:": "Upcoming ones:", "Upcoming ones:": "即将到来的幸运用户:",
"twisted again by": "转推由", "twisted again by": "转推由",
"undo": "撤销", "undo": "撤销",
"Are you sure you want to exit the daemon?\nThe Twister client will stop working.": "你确定要退出后台进程?\nTwister 客户端将停止工作。", "Are you sure you want to exit the daemon?\nThe Twister client will stop working.": "你确定要退出后台进程?\nTwister 客户端将停止工作。",
@ -1163,6 +1171,8 @@ if(preferredLanguage == "nl"){
"Block chain information": "Block chain informatie", "Block chain information": "Block chain informatie",
"Block chain is up-to-date, twister is ready to use!": "Block chain is up-to-date, twister is klaar voor gebruik!", "Block chain is up-to-date, twister is ready to use!": "Block chain is up-to-date, twister is klaar voor gebruik!",
"Block generation": "Block productie", "Block generation": "Block productie",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Annuleren", "Cancel": "Annuleren",
"Change user": "Gebruiker wijzigen", "Change user": "Gebruiker wijzigen",
"Checking...": "Controleren...", // checking if username is available "Checking...": "Controleren...", // checking if username is available
@ -1436,6 +1446,8 @@ if(preferredLanguage == "it"){
"Block chain information": "Informazioni sulla catena di blocchi", "Block chain information": "Informazioni sulla catena di blocchi",
"Block chain is up-to-date, twister is ready to use!": "Catena di blocchi aggiornata, Twister è pronto per l'uso!", "Block chain is up-to-date, twister is ready to use!": "Catena di blocchi aggiornata, Twister è pronto per l'uso!",
"Block generation": "Generatore di blocchi:", "Block generation": "Generatore di blocchi:",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Cancella", "Cancel": "Cancella",
"Change user": "Cambia utente", "Change user": "Cambia utente",
"Checking...": "Controllo in corso...", // checking if username is available "Checking...": "Controllo in corso...", // checking if username is available
@ -1706,6 +1718,8 @@ if(preferredLanguage == "fr"){
"Block chain information": "Informations à propos de la chaîne de blocs", "Block chain information": "Informations à propos de la chaîne de blocs",
"Block chain is up-to-date, twister is ready to use!": "La chaîne de blocs est à jour, Twister est maintenant fonctionnel!", "Block chain is up-to-date, twister is ready to use!": "La chaîne de blocs est à jour, Twister est maintenant fonctionnel!",
"Block generation": "Production de blocs", "Block generation": "Production de blocs",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Annuler", "Cancel": "Annuler",
"Change user": "Changer d'utilisateur", "Change user": "Changer d'utilisateur",
"Checking...": "Vérification...", // checking if username is available "Checking...": "Vérification...", // checking if username is available
@ -1981,6 +1995,8 @@ if(preferredLanguage == "ru"){
"Block chain information": "Информация цепочки блоков", "Block chain information": "Информация цепочки блоков",
"Block chain is up-to-date, twister is ready to use!": "Цепочка блоков обновлена, twister готов к использованию!", "Block chain is up-to-date, twister is ready to use!": "Цепочка блоков обновлена, twister готов к использованию!",
"Block generation": "Майнинг блоков ", "Block generation": "Майнинг блоков ",
"busted_oh": "о нет!",
"busted_avowal": "я пойман на попытке вставить этот подозрительный код здесь",
"Cancel": "Отмена", "Cancel": "Отмена",
"Change user": "Сменить пользователя", "Change user": "Сменить пользователя",
"Checking...": "Проверка...", "Checking...": "Проверка...",
@ -2259,6 +2275,8 @@ if(preferredLanguage == "de"){
"Block chain information": "Block-Chain Informationen", "Block chain information": "Block-Chain Informationen",
"Block chain is up-to-date, twister is ready to use!": "Block-Chain ist aktuell, twister ist benutzbar!", "Block chain is up-to-date, twister is ready to use!": "Block-Chain ist aktuell, twister ist benutzbar!",
"Block generation": "Block-Generierung ", "Block generation": "Block-Generierung ",
"busted_oh": "Oh nein!",
"busted_avowal": "Ich bin ertappt, habe versucht, hier Schadcode einzugeben!",
"Cancel": "Abbrechen", "Cancel": "Abbrechen",
"Change user": "Benutzer wechseln", "Change user": "Benutzer wechseln",
"Checking...": "Überprüfe...", // checking if username is available "Checking...": "Überprüfe...", // checking if username is available
@ -2533,6 +2551,8 @@ if(preferredLanguage == "ja"){
"Block chain information": "ブロックチェイン", "Block chain information": "ブロックチェイン",
"Block chain is up-to-date, twister is ready to use!": "ブロックチェインは最新の状態です。", "Block chain is up-to-date, twister is ready to use!": "ブロックチェインは最新の状態です。",
"Block generation": "ブロック生成", "Block generation": "ブロック生成",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "キャンセル", "Cancel": "キャンセル",
"Change user": "ユーザーを変更", "Change user": "ユーザーを変更",
"Checking...": "チェック...", // checking if username is available "Checking...": "チェック...", // checking if username is available
@ -2804,6 +2824,8 @@ if(preferredLanguage == "pt-BR"){
"Block chain information": "Informações da Cadeia de Blocos", "Block chain information": "Informações da Cadeia de Blocos",
"Block chain is up-to-date, twister is ready to use!": "A Cadeida de Blocos está sincronizada, Twister está pronto para uso!", "Block chain is up-to-date, twister is ready to use!": "A Cadeida de Blocos está sincronizada, Twister está pronto para uso!",
"Block generation": "Geração de blocos ", "Block generation": "Geração de blocos ",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Cancelar", "Cancel": "Cancelar",
"Change user": "Trocar usuário", "Change user": "Trocar usuário",
"Checking...": "Verificando...", // checking if username is available "Checking...": "Verificando...", // checking if username is available
@ -3079,6 +3101,8 @@ if(preferredLanguage == "tr"){
"Block chain information": "Blok zincir bilgisi", "Block chain information": "Blok zincir bilgisi",
"Block chain is up-to-date, twister is ready to use!": "Blok zinciri güncel, twister kullanıma hazır!", "Block chain is up-to-date, twister is ready to use!": "Blok zinciri güncel, twister kullanıma hazır!",
"Block generation": "Blok üretimi ", "Block generation": "Blok üretimi ",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "İptal", "Cancel": "İptal",
"Change user": "Kullanıcı değiştir", "Change user": "Kullanıcı değiştir",
"Checking...": "Denetleniyor...", // checking if username is available "Checking...": "Denetleniyor...", // checking if username is available
@ -3351,6 +3375,8 @@ if(preferredLanguage == "cs"){
"Block chain information": "Informace o blockchainu", "Block chain information": "Informace o blockchainu",
"Block chain is up-to-date, twister is ready to use!": "Blockchain je aktuální, twister je připraven k použití!", "Block chain is up-to-date, twister is ready to use!": "Blockchain je aktuální, twister je připraven k použití!",
"Block generation": "Generování bloků ", "Block generation": "Generování bloků ",
"busted_oh": "oh noes!",
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"Cancel": "Zrušit", "Cancel": "Zrušit",
"Change user": "Změnit uživatele", "Change user": "Změnit uživatele",
"Checking...": "Ověřuji...", // checking if username is available "Checking...": "Ověřuji...", // checking if username is available

2
js/twister_following.js

@ -777,7 +777,7 @@ function processSwarmProgressFinal(lastHaves, numPieces)
} }
} }
} }
window.setTimeout("requestSwarmProgress();",2000); window.setTimeout(requestSwarmProgress, 2000);
} }
function followingChangedUser() { function followingChangedUser() {

356
js/twister_formatpost.js

@ -3,6 +3,28 @@
// //
// Format JSON posts and DMs to HTML. // Format JSON posts and DMs to HTML.
var _htmlFormatMsgLinkTemplateExternal;
var _htmlFormatMsgLinkTemplateUser;
var _htmlFormatMsgLinkTemplateHashtag;
$(document).ready(function() {
// we're setting it here for perfomance improvement purpose // to not search and prepare it for for every post every time
_htmlFormatMsgLinkTemplateExternal = $('#external-page-link-template')
if (_htmlFormatMsgLinkTemplateExternal.length) {
_htmlFormatMsgLinkTemplateExternal = _htmlFormatMsgLinkTemplateExternal[0].cloneNode();
_htmlFormatMsgLinkTemplateExternal.removeAttribute('id');
}
_htmlFormatMsgLinkTemplateUser = $('#msg-user-link-template')
if (_htmlFormatMsgLinkTemplateUser.length) {
_htmlFormatMsgLinkTemplateUser = _htmlFormatMsgLinkTemplateUser[0].cloneNode();
_htmlFormatMsgLinkTemplateUser.removeAttribute('id');
}
_htmlFormatMsgLinkTemplateHashtag = $('#hashtag-link-template')
if (_htmlFormatMsgLinkTemplateHashtag.length) {
_htmlFormatMsgLinkTemplateHashtag = _htmlFormatMsgLinkTemplateHashtag[0].cloneNode();
_htmlFormatMsgLinkTemplateHashtag.removeAttribute('id');
}
});
// format "userpost" to html element // format "userpost" to html element
// kind = "original"/"ancestor"/"descendant" // kind = "original"/"ancestor"/"descendant"
@ -172,7 +194,7 @@ function dmDataToSnippetItem(dmData, remoteUser) {
getGroupChatName( remoteUser, dmItem.find("a.post-info-name") ); getGroupChatName( remoteUser, dmItem.find("a.post-info-name") );
else else
getFullname( remoteUser, dmItem.find("a.post-info-name") ); getFullname( remoteUser, dmItem.find("a.post-info-name") );
dmItem.find(".post-text").html(escapeHtmlEntities(dmData.text)); dmItem.find(".post-text").html(htmlFormatMsg(dmData.text));
dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)).attr("title",timeSincePost(dmData.time)); dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)).attr("title",timeSincePost(dmData.time));
return dmItem; return dmItem;
@ -198,7 +220,10 @@ function dmDataToConversationItem(dmData, localUser, remoteUser) {
// convert message text to html, featuring @users and links formating. // convert message text to html, featuring @users and links formating.
function htmlFormatMsg(msg, mentions) { function htmlFormatMsg(msg, mentions) {
function getStrStart(str, startPoint, stopChars, isStopCharMustExist, stopCharsTrailing) { // TODO: add options for emotions; msg = $.emotions(msg);
// TODO make markup optionally mutable ?
function getSubStrStart(str, startPoint, stopChars, isStopCharMustExist, stopCharsTrailing) {
for (var i = startPoint; i > -1; i--) { for (var i = startPoint; i > -1; i--) {
if (stopChars.indexOf(str[i]) > -1) if (stopChars.indexOf(str[i]) > -1)
break; break;
@ -215,7 +240,7 @@ function htmlFormatMsg(msg, mentions) {
return i; return i;
} }
function getStrEnd(str, startPoint, stopChars, isStopCharMustExist, stopCharsTrailing) { function getSubStrEnd(str, startPoint, stopChars, isStopCharMustExist, stopCharsTrailing) {
for (var i = startPoint; i < str.length; i++) { for (var i = startPoint; i < str.length; i++) {
if (stopChars.indexOf(str[i]) > -1) if (stopChars.indexOf(str[i]) > -1)
break; break;
@ -232,8 +257,8 @@ function htmlFormatMsg(msg, mentions) {
return i; return i;
} }
function markdown(str, chr, tag) { function markout(msg, chr, tag) {
function whiteSpace(i, j) { function isWhiteSpacesBetween(i, j) {
j++; j++;
for (i += 1; i < j; i++) { for (i += 1; i < j; i++) {
if (p[i].w) if (p[i].w)
@ -243,50 +268,50 @@ function htmlFormatMsg(msg, mentions) {
return false; return false;
} }
var i, j, t, l, r, strEncoded; var i, j, t, l, r, htmlEntityEncoded;
var w = false; var w = false;
var p = []; var p = [];
// collecting chars position data // collecting chars position data
for (i = 0; i < str.length; i++) { for (i = 0; i < msg.str.length; i++) {
if (str[i] === chr) { if (msg.str[i] === chr) {
for (j = i + 1; j < str.length; j++) { for (j = i + 1; j < msg.str.length; j++) {
if (str[j] !== chr) if (msg.str[j] !== chr)
break; break;
} }
if (i === 0) { if (i === 0) {
p.push({i: i, k: j - i, t: -1, w: w, a: -1, p: -1}); p.push({i: i, k: j - i, t: -1, w: w, a: -1, p: -1});
w = false; w = false;
} else if (j === str.length) { } else if (j === msg.str.length) {
p.push({i: i, k: j - i, t: 1, w: w, a: -1, p: -1}); p.push({i: i, k: j - i, t: 1, w: w, a: -1, p: -1});
w = false; w = false;
} else { } else {
if (stopCharsMarkDown.indexOf(str[i - 1]) > -1) { if (stopCharsMarkout.indexOf(msg.str[i - 1]) > -1) {
l = 1; l = 1;
for (t = i - 2; t > -1; t--) { for (t = i - 2; t > -1; t--) {
if (str[t] === chr) { if (msg.str[t] === chr) {
l = -1; l = -1;
break; break;
} else if (stopCharsMarkDown.indexOf(str[t]) === -1) { } else if (stopCharsMarkout.indexOf(msg.str[t]) === -1) {
l = whiteSpaces.indexOf(str[t]); l = whiteSpaces.indexOf(msg.str[t]);
break; break;
} }
} }
} else } else
l = whiteSpaces.indexOf(str[i - 1]); l = whiteSpaces.indexOf(msg.str[i - 1]);
if (stopCharsMarkDown.indexOf(str[j]) > -1) { if (stopCharsMarkout.indexOf(msg.str[j]) > -1) {
r = 1; r = 1;
for (t = j + 1; t < str.length; t++) { for (t = j + 1; t < msg.str.length; t++) {
if (str[t] === chr) { if (msg.str[t] === chr) {
r = -1; r = -1;
break; break;
} else if (stopCharsMarkDown.indexOf(str[t]) === -1) { } else if (stopCharsMarkout.indexOf(msg.str[t]) === -1) {
r = whiteSpaces.indexOf(str[t]); r = whiteSpaces.indexOf(msg.str[t]);
break; break;
} }
} }
} else } else
r = whiteSpaces.indexOf(str[j]); r = whiteSpaces.indexOf(msg.str[j]);
if (l > -1) { if (l > -1) {
if (r > -1) { if (r > -1) {
if (j - i > 2) { if (j - i > 2) {
@ -307,7 +332,7 @@ function htmlFormatMsg(msg, mentions) {
w = false; w = false;
} }
i = j - 1; i = j - 1;
} else if (!w && whiteSpaces.indexOf(str[i]) > -1) { } else if (!w && whiteSpaces.indexOf(msg.str[i]) > -1) {
w = true; w = true;
} }
} }
@ -317,7 +342,7 @@ function htmlFormatMsg(msg, mentions) {
if (p[i].t < 1 && p[i].a === -1) { if (p[i].t < 1 && p[i].a === -1) {
t = i; t = i;
for (j = i + 1; j < p.length; j++) { for (j = i + 1; j < p.length; j++) {
if (p[i].t === 0 && whiteSpace(i, j)) { if (p[i].t === 0 && isWhiteSpacesBetween(i, j)) {
i = j - 1; i = j - 1;
break; break;
} else if (p[j].t < 1 && p[j].a === -1) { } else if (p[j].t < 1 && p[j].a === -1) {
@ -335,11 +360,11 @@ function htmlFormatMsg(msg, mentions) {
for (i = 0; i < p.length; i++) { for (i = 0; i < p.length; i++) {
if (p[i].t === -1 && p[i].a === -1) { if (p[i].t === -1 && p[i].a === -1) {
for (j = p[i].p; j > -1; j = p[j].p) { for (j = p[i].p; j > -1; j = p[j].p) {
if (whiteSpace(i, j)) { if (isWhiteSpacesBetween(i, j)) {
i = j - 1; i = j - 1;
break; break;
} else if (p[j].t === 0 } else if (p[j].t === 0
&& !(p[j].p > -1 && p[p[j].p].t === 0 && !whiteSpace(j, p[j].p))) { && !(p[j].p > -1 && p[p[j].p].t === 0 && !isWhiteSpacesBetween(j, p[j].p))) {
p[j].a = i; p[j].a = i;
p[i].a = j; p[i].a = j;
i = j; i = j;
@ -359,15 +384,15 @@ function htmlFormatMsg(msg, mentions) {
else else
t = '<' + tag + '>'; t = '<' + tag + '>';
j = p[i].a; j = p[i].a;
t = t + str.slice(p[i].i + p[i].k, p[j].i); t = t + msg.str.slice(p[i].i + p[i].k, p[j].i);
if (p[j].k > 1) if (p[j].k > 1)
t = t + Array(p[i].k).join(chr) + '</' + tag + '>'; t = t + Array(p[i].k).join(chr) + '</' + tag + '>';
else else
t = t + '</' + tag + '>'; t = t + '</' + tag + '>';
html.push(t.replace(/&(?!lt;|gt;)/g, '&amp;')); msg.htmlEntities.push(t.replace(/&(?!lt;|gt;)/g, '&amp;'));
strEncoded = '>' + (html.length - 1).toString() + '<'; htmlEntityEncoded = '>' + (msg.htmlEntities.length - 1).toString() + '<';
str = str.slice(0, p[i].i) + strEncoded + str.slice(p[j].i + p[j].k); msg.str = msg.str.slice(0, p[i].i) + htmlEntityEncoded + msg.str.slice(p[j].i + p[j].k);
l = strEncoded.length - p[j].i - p[j].k + p[i].i; l = htmlEntityEncoded.length - p[j].i - p[j].k + p[i].i;
i = j; i = j;
for (j += 1; j < p.length; j++) for (j += 1; j < p.length; j++)
p[j].i += l; p[j].i += l;
@ -379,196 +404,228 @@ function htmlFormatMsg(msg, mentions) {
if (p[i].a > -1) { if (p[i].a > -1) {
if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) { if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) {
if (p[i].k > 1) if (p[i].k > 1)
html.push('<' + tag + '>' + Array(p[i].k).join(chr)); msg.htmlEntities.push('<' + tag + '>' + Array(p[i].k).join(chr));
else else
html.push('<' + tag + '>'); msg.htmlEntities.push('<' + tag + '>');
} else if (p[i].t === 1 || (p[i].t === 0 && p[i].a < i)) { } else if (p[i].t === 1 || (p[i].t === 0 && p[i].a < i)) {
if (p[i].k > 1) if (p[i].k > 1)
html.push(Array(p[i].k).join(chr) + '</' + tag + '>'); msg.htmlEntities.push(Array(p[i].k).join(chr) + '</' + tag + '>');
else else
html.push('</' + tag + '>'); msg.htmlEntities.push('</' + tag + '>');
} }
strEncoded = '>' + (html.length - 1).toString() + '<'; htmlEntityEncoded = '>' + (msg.htmlEntities.length - 1).toString() + '<';
str = str.slice(0, p[i].i) + strEncoded + str.slice(p[i].i + p[i].k); msg.str = msg.str.slice(0, p[i].i) + htmlEntityEncoded + msg.str.slice(p[i].i + p[i].k);
l = strEncoded.length - p[i].k; l = htmlEntityEncoded.length - p[i].k;
for (j = i + 1; j < p.length; j++) for (j = i + 1; j < p.length; j++)
p[j].i += l; p[j].i += l;
} }
} }
} }
return str; return msg;
}
function newHtmlEntityLink(template, urlTarget, urlName) {
template.href = urlTarget;
template.innerHTML = urlName; // .innerHTML instead .text to allow markup inside [] of [url name](target)
return template.outerHTML;
} }
function htmlSplitCounter(str) { function msgAddHtmlEntity(msg, strSliceLeft, strSliceRigth, htmlEntity) {
html.push('<span class="splited-post-counter">' + str + '</span>'); msg.htmlEntities.push(htmlEntity);
var htmlEntityEncoded = '>' + (msg.htmlEntities.length - 1).toString() + '<';
msg.str = msg.str.slice(0, strSliceLeft) + htmlEntityEncoded + msg.str.slice(strSliceRigth);
msg.i = strSliceLeft + htmlEntityEncoded.length - 1;
return '>' + (html.length - 1).toString() + '<'; return msg;
} }
function unpackHtml(str) { function applyHtml(msg) {
var t; var t;
for (var i = 0; i < str.length - 2; i++) { for (var i = 0; i < msg.str.length - 2; i++) {
if (str[i] === '>') { if (msg.str[i] === '>') {
for (var j = i + 2; j < str.length; j++) { for (var j = i + 2; j < msg.str.length; j++) {
if (str[j] === '<') if (msg.str[j] === '<')
break; break;
} }
t = html[parseInt(str.slice(i + 1, j))]; t = msg.htmlEntities[parseInt(msg.str.slice(i + 1, j))];
str = str.slice(0, i) + t + str.slice(j + 1); msg.str = msg.str.slice(0, i) + t + msg.str.slice(j + 1);
i = i + t.length - 1; i = i + t.length - 1;
} }
} }
return str; return msg.str;
} }
var mentionsChars = 'abcdefghijklmnopqrstuvwxyz_0123456789'; var mentionsChars = 'abcdefghijklmnopqrstuvwxyz_0123456789';
var stopCharsTrailing = '/\\*~_-`.,:;?!%\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011'; var stopCharsTrailing = '/\\*~_-`.,:;?!%\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011\u2047\u2048\u2049';
var stopCharsTrailingUrl = stopCharsTrailing.slice(1); var stopCharsTrailingUrl = stopCharsTrailing.slice(1);
var whiteSpaces = ' \f\n\r\t\v\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000'; var whiteSpaces = ' \f\n\r\t\v\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000';
var whiteSpacesUrl = '\'\"' + whiteSpaces;
var stopCharsLeft = '<' + whiteSpaces; var stopCharsLeft = '<' + whiteSpaces;
var stopCharsRight = '>' + whiteSpaces; var stopCharsRight = '>' + whiteSpaces;
var stopCharsRightHashtags = '>/\\.,:;?!%\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011' // same as stopCharsTrailing but without '*~_-`' plus '>' var stopCharsRightHashtags = '>/\\.,:;?!%\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011\u2047\u2048\u2049' // same as stopCharsTrailing but without '*~_-`' plus '>'
+ whiteSpaces; + whiteSpaces;
var stopCharsMarkDown = '/\\*~_-`.,:;?!%+=&\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011'; var stopCharsMarkout = '/\\*~_-`.,:;?!%+=&\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011\u2047\u2048\u2049';
var i, j, k, str, strEncoded; var i, j, k, str;
var html = [];
msg = {str: escapeHtmlEntities(msg), htmlEntities: []};
msg = markdown(escapeHtmlEntities(msg),
'`', 'samp'); // kind of monospace, sequence of chars inside will be escaped from markup msg = markout(msg, '`', 'samp'); // <samp> tag is kind of monospace, here sequence of chars inside it will be escaped from markup
for (i = 0; i < msg.length - 7; i++) {
var htmlPiece = undefined; // handling links
var msgSliceIdx; for (i = 0; i < msg.str.length - 7; i++) {
if (msg.slice(i, i + 2) === '](') { if (msg.str.slice(i, i + 2) === '](') {
// FIXME there can be text with [] inside [] or links with () wee need to handle it too // FIXME there can be text with [] inside [] or links with () we need to handle it too
j = getStrStart(msg, i - 1, '[', true, ''); j = getSubStrStart(msg.str, i - 2, '[', true, '');
if (j < i) { if (j < i - 1) {
k = getStrEnd(msg, i + 2, ')', true, ''); k = getSubStrEnd(msg.str, i + 3, ')', true, whiteSpaces);
if (k > i + 1) { if (k > i + 2) {
var a = $('#external-page-link-template')[0].cloneNode(); var linkName = msg.str.slice(j, i); // name of possiible link
a.href = proxyURL(msg.slice(i + 2, k + 1)); for (i += 2; i < k; i++) {
a.text = msg.slice(j, i); if (whiteSpacesUrl.indexOf(msg.str[i]) === -1) // drop whitespaces and ' and " // apostrophes and quotes to prevent injection of js events
htmlPiece = a.outerHTML; break;
msgSliceIdx = [j - 1, k + 2]; }
} if (i < k) {
} var x = getSubStrEnd(msg.str, i, ':', false, '') + 1;
} else if (msg.slice(i, i + 4).toLowerCase() === 'http') { // following check is NOT for real protection (we have blocking CSP rule instead), it's just to aware people
if (msg.slice(i + 4, i + 7) === '://' && stopCharsRight.indexOf(msg[i + 7]) === -1) { if (msg.str[i] === '#' || (x > i && x < k && (msg.str.slice(x - 6, x).toLowerCase() === 'script' // other things would be added when W3C and all the people invent it
j = getStrEnd(msg, i + 7, stopCharsRight, false, stopCharsTrailingUrl); || msg.str.slice(x - 4, x).toLowerCase() === 'data'))) {
msg = msgAddHtmlEntity(msg, j - 1, getSubStrEnd(msg.str, k + 1, ')', true, '') + 2,
'…<br><b><i>' + polyglot.t('busted_oh') + '</i> '
+ polyglot.t('busted_avowal') + ':</b><br><samp>'
+ msg.str.slice(i, k + 1)
.replace(/&(?!lt;|gt;)/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
+ '</samp><br>'
);
} else {
if (getSubStrEnd(msg.str, i + 1, whiteSpacesUrl, false, '') < k) // use only first word as href target, others drop silently
k = getSubStrEnd(msg.str, i + 1, whiteSpacesUrl, false, '');
msg = msgAddHtmlEntity(msg, j - 1, getSubStrEnd(msg.str, k + 1, ')', true, '') + 2,
newHtmlEntityLink(_htmlFormatMsgLinkTemplateExternal,
proxyURL(msg.str.slice(i, k + 1)),
applyHtml( // we're trying markup inside [] of []()
markout(markout(markout(markout(
{str: linkName, htmlEntities: msg.htmlEntities},
'*', 'b'), // bold
'~', 'i'), // italic
'_', 'u'), // underlined
'-', 's') // striketrough
)
.replace(/&(?!lt;|gt;)/g, '&amp;')
)
);
}
i = msg.i + 1;
}
}
}
} else if (msg.str.slice(i, i + 4).toLowerCase() === 'http') {
if (msg.str.slice(i + 4, i + 7) === '://' && stopCharsRight.indexOf(msg.str[i + 7]) === -1) {
j = getSubStrEnd(msg.str, i + 7, stopCharsRight, false, stopCharsTrailingUrl);
if (j > i + 6) { if (j > i + 6) {
str = msg.slice(i, j + 1); str = msg.str.slice(i, j + 1);
// FIXME we're trying to not interact with DOM, coz' we want to run really fast [to hell of RegExps] msg = msgAddHtmlEntity(msg, i, i + str.length,
// FIXME actually we should avoid it by dropping a template idea and construct html right here newHtmlEntityLink(_htmlFormatMsgLinkTemplateExternal,
htmlPiece = $('#external-page-link-template')[0].outerHTML proxyURL(str), str)
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id') );
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href') i = msg.i;
.replace(/<a\s+/ig, '<a href="' + proxyURL(str) + '" ') // $().closest('a').attr('href', proxyURL(url))
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, '$1' + str + '$2') // $().closest('a').text(url)
;
msgSliceIdx = [i, i + str.length];
} }
} else if (msg.slice(i + 4, i + 8).toLowerCase() === 's://' && stopCharsRight.indexOf(msg[i + 8]) === -1) { } else if (msg.str.slice(i + 4, i + 8).toLowerCase() === 's://' && stopCharsRight.indexOf(msg.str[i + 8]) === -1) {
j = getStrEnd(msg, i + 8, stopCharsRight, false, stopCharsTrailingUrl); j = getSubStrEnd(msg.str, i + 8, stopCharsRight, false, stopCharsTrailingUrl);
if (j > i + 7) { if (j > i + 7) {
str = msg.slice(i, j + 1); str = msg.str.slice(i, j + 1);
htmlPiece = $('#external-page-link-template')[0].outerHTML msg = msgAddHtmlEntity(msg, i, i + str.length,
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id') newHtmlEntityLink(_htmlFormatMsgLinkTemplateExternal,
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href') proxyURL(str), str)
.replace(/<a\s+/ig, '<a href="' + proxyURL(str) + '" ') // $().closest('a').attr('href', proxyURL(url)) );
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, '$1' + str + '$2') // $().closest('a').text(url) i = msg.i;
;
msgSliceIdx = [i, i + str.length];
}
} }
} }
if (htmlPiece) {
html.push(htmlPiece)
strEncoded = '>' + (html.length - 1).toString() + '<';
msg = msg.slice(0, msgSliceIdx[0]) + strEncoded + msg.slice(msgSliceIdx[1]);
i = i + strEncoded.length - 1;
} }
} }
for (i = 1; i < msg.length - 1; i++) { // handling mails
if (msg[i] === '@' && stopCharsLeft.indexOf(msg[i - 1]) === -1 for (i = 1; i < msg.str.length - 1; i++) {
&& stopCharsTrailing.indexOf(msg[i - 1]) === -1 && stopCharsRight.indexOf(msg[i + 1]) === -1) { if (msg.str[i] === '@' && stopCharsLeft.indexOf(msg.str[i - 1]) === -1
j = getStrStart(msg, i - 1, stopCharsLeft, false, stopCharsTrailing); && stopCharsTrailing.indexOf(msg.str[i - 1]) === -1 && stopCharsRight.indexOf(msg.str[i + 1]) === -1) {
j = getSubStrStart(msg.str, i - 1, stopCharsLeft, false, stopCharsTrailing);
if (j < i) { if (j < i) {
k = getStrEnd(msg, i + 1, stopCharsRight, false, stopCharsTrailing); k = getSubStrEnd(msg.str, i + 1, stopCharsRight, false, stopCharsTrailing);
if (k > i) { if (k > i) {
str = msg.slice(j, k + 1); str = msg.str.slice(j, k + 1);
html.push($('#external-page-link-template')[0].outerHTML msg = msgAddHtmlEntity(msg, j, j + str.length,
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id') newHtmlEntityLink(_htmlFormatMsgLinkTemplateExternal,
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href') 'mailto:' + str.toLowerCase(), str)
.replace(/<a\s+/ig, '<a href="mailto:' + str.toLowerCase() + '" ') // $().closest('a').attr('href', 'mailto:'+url)
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, '$1' + str + '$2') // $().closest('a').text(url)
); );
strEncoded = '>' + (html.length - 1).toString() + '<'; i = msg.i;
msg = msg.slice(0, j) + strEncoded + msg.slice(j + str.length);
i = j + strEncoded.length - 1;
} }
} }
} }
} }
for (i = 0; i < msg.length - 1; i++) { // handling mentions
if (msg[i] === '@' && mentionsChars.indexOf(msg[i + 1].toLowerCase()) > -1) { for (i = 0; i < msg.str.length - 1; i++) {
for (j = i + 2; j < msg.length; j++) { if (msg.str[i] === '@' && mentionsChars.indexOf(msg.str[i + 1].toLowerCase()) > -1) {
if (mentionsChars.indexOf(msg[j].toLowerCase()) === -1) for (j = i + 2; j < msg.str.length; j++) {
if (mentionsChars.indexOf(msg.str[j].toLowerCase()) === -1)
break; break;
} }
str = msg.slice(i + 1, j).toLowerCase(); str = msg.str.slice(i + 1, j).toLowerCase();
mentions.push(str); // FIXME mentions.push(str); // FIXME
html.push($('#msg-user-link-template')[0].outerHTML msg = msgAddHtmlEntity(msg, i, i + str.length + 1,
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id') newHtmlEntityLink(_htmlFormatMsgLinkTemplateUser,
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href') $.MAL.userUrl(str), '@' + str)
.replace(/<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-profile-modal\b))/ig, '<a href="' + $.MAL.userUrl(str) + '" ') // $().closest('a.open-profile-modal').attr('href', $.MAL.userUrl(username))
.replace(/(<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-profile-modal\b))[^]*?>)[^]*?(<\/a>)/ig, '$1@' + str + '$2') // $().closest('a.open-profile-modal').text('@'+username)
); );
strEncoded = '>' + (html.length - 1).toString() + '<'; i = msg.i;
msg = msg.slice(0, i) + strEncoded + msg.slice(i + str.length + 1);
i = i + strEncoded.length - 1;
} }
} }
for (i = 0; i < msg.length - 1; i++) { // handling hashtags
if (msg[i] === '#' && msg[i + 1] !== '#' && stopCharsRight.indexOf(msg[i + 1]) === -1) { for (i = 0; i < msg.str.length - 1; i++) {
j = getStrEnd(msg, i + 1, stopCharsRightHashtags, false, stopCharsTrailing); if (msg.str[i] === '#' && msg.str[i + 1] !== '#' && stopCharsRight.indexOf(msg.str[i + 1]) === -1) {
j = getSubStrEnd(msg.str, i + 1, stopCharsRightHashtags, false, stopCharsTrailing);
if (j > i) { if (j > i) {
str = msg.slice(i + 1, j + 1); str = msg.str.slice(i + 1, j + 1);
html.push($('#hashtag-link-template')[0].outerHTML msg = msgAddHtmlEntity(msg, i, i + str.length + 1,
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id') newHtmlEntityLink(_htmlFormatMsgLinkTemplateHashtag,
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href') $.MAL.hashtagUrl(encodeURIComponent(str.toLowerCase())), '#' + str.replace(/&amp;/g, '&'))
.replace(/<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-hashtag-modal\b))/ig, '<a href="' + $.MAL.hashtagUrl(encodeURIComponent(str.toLowerCase())) + '" ') // $().closest('a.open-profile-modal').attr('href', $.MAL.hashtagUrl(hashtag))
.replace(/(<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-hashtag-modal\b))[^]*?>)[^]*?(<\/a>)/ig, '$1#' + str.replace(/&amp;/g, '&') + '$2') // $().closest('a.open-profile-modal').text('#'+hashtag)
); );
strEncoded = '>' + (html.length - 1).toString() + '<'; i = msg.i;
msg = msg.slice(0, i) + strEncoded + msg.slice(i + str.length + 1);
i = i + strEncoded.length - 1;
} }
} }
} }
msg = unpackHtml( // handling text style markup
markdown(markdown(markdown(markdown(msg, msg = markout(markout(markout(markout(msg,
'*', 'b'), // bold '*', 'b'), // bold
'~', 'i'), // italic '~', 'i'), // italic
'_', 'u'), // underlined '_', 'u'), // underlined
'-', 's') // striketrough '-', 's') // striketrough
.replace(/\(\d{1,2}\/\d{1,2}\)$/, htmlSplitCounter) ;
// handling splitted posts numbering and escaping ampersands, qoutes and apostrophes
msg.str = msg.str
.replace(/\(\d{1,2}\/\d{1,2}\)$/, function (str) {
msg.htmlEntities.push('<span class="splited-post-counter">' + str + '</span>'); // FIXME
return '>' + (msg.htmlEntities.length - 1).toString() + '<';
})
.replace(/&(?!lt;|gt;)/g, '&amp;') // FIXME in many cases there is no need to escape ampersand in HTML 5 .replace(/&(?!lt;|gt;)/g, '&amp;') // FIXME in many cases there is no need to escape ampersand in HTML 5
.replace(/"/g, '&quot;') .replace(/"/g, '&quot;')
.replace(/'/g, '&apos;') .replace(/'/g, '&apos;')
);
// applying html entities to msg.str and converting msg to string back
msg = applyHtml(msg);
// handling linebreaks
if ($.Options.displayLineFeeds.val === 'enable') if ($.Options.displayLineFeeds.val === 'enable')
msg = msg.replace(/\n/g, '<br />'); msg = msg.replace(/\n/g, '<br />');
// TODO: add options for emotions; msg = $.emotions(msg);
// TODO make markdown optionally mutable ?
return msg; return msg;
} }
@ -604,4 +661,3 @@ function reverseHtmlEntities(str) {
.replace(/&apos;/g, "'") .replace(/&apos;/g, "'")
.replace(/&amp;/g, '&'); .replace(/&amp;/g, '&');
} }

8
options.html

@ -20,14 +20,6 @@
<script src="js/interface_login.js"></script> <script src="js/interface_login.js"></script>
<script src="js/polyglot.min.js"></script> <script src="js/polyglot.min.js"></script>
<script src="js/interface_localization.js"></script> <script src="js/interface_localization.js"></script>
<script>
$(function() {
initInterfaceCommon();
$.Options.initControls();
})
changeStyle();
</script>
</head> </head>
<body> <body>

Loading…
Cancel
Save