halcyonTemplates.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. function mediaattachments_template(status) {
  2. let media_views = "";
  3. var border = "";
  4. var mvfullheight = "";
  5. var media_embeds = new Array();
  6. var audio_embeds = new Array();
  7. var dsplength = status.media_attachments.length;
  8. for(var i=0;i<dsplength;i++) {
  9. var blurbackground = "";
  10. if(status.media_attachments[i].remote_url != null) status.media_attachments[i].url = status.media_attachments[i].remote_url;
  11. if(status.media_attachments[i].description == null) status.media_attachments[i].description = "";
  12. if(status.media_attachments[i].blurhash) blurbackground = ' style="background-image:url('+getBlurImage(status.media_attachments[i].blurhash)+')"';
  13. if((status.media_attachments[i].type === "video" && localStorage.setting_play_video == "false") || (status.media_attachments[i].type === "gifv" && localStorage.setting_play_gif == "false")) {
  14. if(status.media_attachments[i].preview_url != status.media_attachments[i].url) media_embeds.push(`
  15. <div class="media_attachment" mediacount="${i}">
  16. <img src="${status.media_attachments[i].preview_url}" title="${status.media_attachments[i].description}">
  17. <div class='sensitive_alert'${blurbackground}>
  18. <span class="text1">${__('Sensitive content')}</span>
  19. <span class="text2">${status.media_attachments[i].description}</span>
  20. </div>
  21. </div>`);
  22. }
  23. else if(status.media_attachments[i].type === "video") {
  24. var vidprev = "";
  25. if(status.media_attachments[i].preview_url != status.media_attachments[i].url) vidprev = "&preview="+encodeURIComponent(status.media_attachments[i].preview_url);
  26. media_embeds.push(`
  27. <div class="media_attachment" otype="video/gifv" mediacount="${i}">
  28. <iframe src="/media/video.php?url=${encodeURIComponent(status.media_attachments[i].url)}&title=${encodeURIComponent(status.media_attachments[i].description)+vidprev}" title="${status.media_attachments[i].description}" frameborder="0" allowfullscreen></iframe>
  29. <div class='sensitive_alert'${blurbackground}>
  30. <span class="text1">${__('Sensitive content')}</span>
  31. <span class="text2">${status.media_attachments[i].description}</span>
  32. </div>
  33. </div>`);
  34. }
  35. else if(status.media_attachments[i].type === "gifv") {
  36. var vidprev = "";
  37. if(status.media_attachments[i].preview_url != status.media_attachments[i].url) vidprev = "<img src='"+status.media_attachments[i].preview_url+"'>";
  38. media_embeds.push(`
  39. <div class="media_attachment with_overlay" otype="video" sid="${status.id}" oid="${status.media_attachments[i].id}" url="${status.media_attachments[i].url}" mediacount="${i}">
  40. <video frameborder="0" title="${status.media_attachments[i].description}" autoplay loop muted>
  41. <source src="${status.media_attachments[i].url}">
  42. ${vidprev}
  43. </video>
  44. <div class='sensitive_alert'${blurbackground}>
  45. <span class="text1">${__('Sensitive content')}</span>
  46. <span class="text2">${status.media_attachments[i].description}</span>
  47. </div>
  48. </div>`);
  49. }
  50. else if(status.media_attachments[i].type === "audio" || (status.media_attachments[i].type === "unknown" && status.media_attachments[i].url.substring(status.media_attachments[i].url.length-4) == ".mp3")) {
  51. if(localStorage.setting_play_audio != "false") {
  52. var audio_embed = $("<div>").attr("title",status.media_attachments[i].description).addClass("player");
  53. audio_embed.player(status.media_attachments[i].url);
  54. audio_embeds.push(audio_embed);
  55. }
  56. }
  57. else if(status.media_attachments[i].type === "image") {
  58. media_embeds.push(`
  59. <div class="media_attachment with_overlay" otype="image" sid="${status.id}" oid="${status.media_attachments[i].id}" url="${status.media_attachments[i].url}" mediacount="${i}">
  60. <img src="${status.media_attachments[i].url}" title="${status.media_attachments[i].description}" window_view="enable"/>
  61. <div class='sensitive_alert'${blurbackground}>
  62. <span class="text1">${__('Sensitive content')}</span>
  63. <span class="text2">${status.media_attachments[i].description}</span>
  64. </div>
  65. </div>`);
  66. }
  67. }
  68. if(status.media_attachments[0].type === "video" && localStorage.setting_play_video != "false" && dsplength == 1) border = ' style="border:0;border-radius:0"';
  69. if(localStorage.setting_full_height == "true" && status.media_attachments.length == 1 && (status.media_attachments[0].type == "image" || (status.media_attachments[0].type === "video" && localStorage.setting_play_video == "false") || status.media_attachments[0].type === "gifv"))
  70. mvfullheight = " media_full_height";
  71. if(media_embeds.length > 0) {
  72. media_views = `<div class='media_views${mvfullheight}' sid="${status.id}" media_length='${dsplength}'${border}>`;
  73. if(media_embeds.length < 3) {
  74. for(let i in media_embeds) {
  75. media_views += media_embeds[i];
  76. }
  77. }
  78. else {
  79. for(let i in media_embeds) {
  80. if(Number(i) === 1) {
  81. media_views += (`<div class="media_attachments_right">`);
  82. media_views += media_embeds[i];
  83. }
  84. else media_views += media_embeds[i];
  85. }
  86. media_views += "</div>";
  87. }
  88. media_views += "</div>";
  89. }
  90. else media_views = "";
  91. var media_view = $("<div>");
  92. media_view.append(media_views);
  93. if(status.sensitive && localStorage.setting_show_nsfw == "false") media_view.find(".media_attachment").addClass("sensitive");
  94. for(let i in audio_embeds) {
  95. media_view.append(audio_embeds[i]);
  96. }
  97. return media_view;
  98. }
  99. function link_preview_template(card) {
  100. if(localStorage.setting_link_previews == "true") {
  101. var randattr = "";
  102. if(server_setting_unshorten && checkURLshortener(card.url)) {
  103. var linkrand = Math.round(Math.random()*1000000);
  104. randattr = ' data-random="'+linkrand+'"';
  105. $(this).attr("data-random",linkrand);
  106. $.ajax("/unshorten.php?url="+encodeURIComponent(card.url)).done(function(data) {
  107. $(".media_views.link_preview").filter("[data-random="+linkrand+"]").data("url",data);
  108. $(".media_views.link_preview").filter("[data-random="+linkrand+"]").find(".card_link").text(data);
  109. });
  110. }
  111. let preview_html = (`<div class="media_views link_preview" media_length="1" style="height:unset" data-url="${card.url}"${randattr}>
  112. <img src="${card.image}" style="width:${card.width};max-width:200px;float:left;margin-right:5px">
  113. <strong>${card.title}</strong><br/>
  114. <span>${card.description}</span><br/>
  115. <span style="color:#777777" class="card_link">${card.url}</span>`);
  116. return preview_html;
  117. }
  118. else return "";
  119. }
  120. function poll_template(poll) {
  121. let poll_html = "";
  122. var expires_at = new Date(new Date(poll.expires_at).getTime()-Date.now());
  123. var expires_string;
  124. if(expires_at.getUTCMonth() == 1) expires_string = "1 "+__("month");
  125. else if(expires_at.getUTCMonth() > 1) expires_string = (expires_at.getUTCMonth())+" "+__("months");
  126. else if(expires_at.getUTCDate() == 2) expires_string = "1 "+__("day");
  127. else if(expires_at.getUTCDate() > 2) expires_string = (expires_at.getUTCDate()-1)+" "+__("days");
  128. else if(expires_at.getUTCHours() == 1) expires_string = "1 "+__("hour");
  129. else if(expires_at.getUTCHours() > 1) expires_string = expires_at.getUTCHours()+" "+__("hours");
  130. else if(expires_at.getUTCMinutes() == 1) expires_string = "1 "+__("minute");
  131. else if(expires_at.getUTCMinutes() > 1) expires_string = expires_at.getUTCMinutes()+" "+__("minutes");
  132. else if(expires_at.getUTCSeconds() == 1) expires_string = "1 "+__("second");
  133. else expires_string = expires_at.getUTCSeconds()+" "+__("seconds");
  134. if(poll.voted || poll.expired) {
  135. poll_html = (`<div class="poll_box">`);
  136. optionsort = [...poll.options];
  137. optionsort.sort(function(a,b) {return a.votes_count - b.votes_count});
  138. optionsort.reverse();
  139. if(optionsort[0].votes_count != optionsort[1].votes_count) poll.options[poll.options.indexOf(optionsort[0])].winner = true;
  140. for(var i=0;i<poll.options.length;i++) {
  141. var winner = "";
  142. if(poll.options[i].winner) winner = " poll_winner";
  143. poll_html += (`<div class="poll_result_option"><span class="poll_bar${winner}" style="width:${poll.options[i].votes_count/poll.votes_count*100}%"></div>
  144. <label class="poll_result_label"><strong>${Math.round(poll.options[i].votes_count/poll.votes_count*100) || 0}%</strong> <span class="emoji_poss">${poll.options[i].title}</span></label>`);
  145. }
  146. if(poll.expired) poll_html += (`<br/><span class="poll_footer">${poll.votes_count} ${__("votes")} &bull; ${__("Final results")}</span>`);
  147. else poll_html += (`<br/><span class="poll_footer">${poll.votes_count} ${__("votes")} &bull; ${expires_string} ${__("left")}</span>`);
  148. }
  149. else {
  150. const poll_random = Math.round(Math.random()*1000);
  151. poll_html = (`<div class="poll_box poll_box_form poll_${poll.id}" data-poll="${poll.id}" data-random="${poll_random}" id="poll_${poll.id}_${poll_random}">`);
  152. for(var i=0;i<poll.options.length;i++) {
  153. if(poll.multiple) {
  154. poll_html += (`<input type="checkbox" id="poll_${poll.id}_${poll_random}_${i}" name="poll_${poll.id}" class="poll_vote_option checkbox">
  155. <label for="poll_${poll.id}_${poll_random}_${i}" class="poll_vote_label poll_checkbox_label emoji_poss">${poll.options[i].title}</label><br/>`);
  156. }
  157. else {
  158. poll_html += (`<div class="radiobox"><input type="radio" id="poll_${poll.id}_${poll_random}_${i}" name="poll_${poll.id}" class="poll_vote_option">
  159. <label for="poll_${poll.id}_${poll_random}_${i}" class="poll_vote_label radiotext emoji_poss">${poll.options[i].title}</label></div>`);
  160. }
  161. }
  162. poll_html += (`<button class="halcyon_button poll_vote"><span>${__("Vote")}</span></button>
  163. ${poll.votes_count} ${__("votes")} &bull; ${expires_string} ${__("left")}`);
  164. }
  165. poll_html += (`</div>`);
  166. return poll_html;
  167. }
  168. function timeline_template(status,is_pinned=false) {
  169. var header_note = "";
  170. if(is_pinned) {
  171. header_note = (`<div class="pinned_notice_box">
  172. <i class="fa fa-fw fa-thumb-tack"></i>${__('Pinned Toot')}</span>
  173. </div>`);
  174. }
  175. if(status.reblog !== null) {
  176. restatus = prepareStatus(status);
  177. status = restatus.reblog;
  178. header_note = (`<div class="boost_author_box">
  179. <a href="${restatus.halcyon.account_link}">
  180. <span class="emoji_poss"><i class="fa fa-fw fa-retweet"></i>${restatus.account.display_name} ${__('Boosted')}</span>
  181. </a>
  182. </div>`);
  183. }
  184. else status = prepareStatus(status);
  185. const html=$(`
  186. <li sid="${status.id}" class="toot_entry">
  187. ${header_note}
  188. <div class="toot_entry_body">
  189. <a href="${status.halcyon.account_link}">
  190. <div class="icon_box">
  191. <img src="${status.account.avatar}">
  192. </div>
  193. </a>
  194. <section class="toot_content">
  195. <header class="toot_header">
  196. <div class="text_ellipsis">
  197. <a href="${status.halcyon.account_link}">
  198. <span class="displayname emoji_poss">
  199. ${status.account.display_name}
  200. </span>
  201. <span class="username">
  202. @${status.account.acct}${status.halcyon.account_state_icons}
  203. </span>
  204. <time datetime="${status.halcyon.attr_datetime}">${status.halcyon.datetime}</time>
  205. </a>
  206. </div>
  207. <div class="expand_button_wrap">
  208. <button class="expand_button">
  209. <i class="fa fa-fw fa-chevron-down"></i>
  210. </button>
  211. <div class="expand_menu invisible disallow_select">
  212. <ul>
  213. <li><a class="copylink_button" url="${status.url}">${__('Copy link to Toot')}</a></li>
  214. ${status.halcyon.own_toot_buttons}
  215. </ul>
  216. <ul>
  217. <li><a href="${status.url}" target="_blank">${__('View original')}</a></li>
  218. </ul>
  219. </div>
  220. </div>
  221. </header>
  222. <article class="toot_article ${status.halcyon.article_option}">
  223. ${status.halcyon.alert_text}
  224. <span class="status_content emoji_poss">
  225. ${status.content}
  226. </span>
  227. ${status.halcyon.preview_object}
  228. </article>
  229. ${status.halcyon.reactions}
  230. <footer class="toot_footer"${status.halcyon.footer_width}>
  231. <div class="toot_reaction">
  232. <button class="reply_button" tid="${status.id}" mentions='${JSON.stringify(status.mentions)}' display_name="${status.account.display_name}" privacy="${status.visibility}" content_warning="${htmlEscape(status.spoiler_text)}">
  233. <i class="fa fa-fw fa-reply"></i>
  234. <span class="reaction_count reply_count">${status.replies_count}</span>
  235. </button>
  236. </div>
  237. ${status.halcyon.reblog_button}
  238. <div class="toot_reaction">
  239. <button class="fav_button" tid="${status.id}" favourited="${status.favourited}">
  240. <i class="fa fa-fw fa-star"></i>
  241. <span class="reaction_count fav_count">${status.favourites_count}</span>
  242. </button>
  243. </div>
  244. <div class="toot_reaction">
  245. <button class="bookmark_button" tid="${status.id}" bookmarked="${status.bookmarked}">
  246. <i class="fa fa-fw fa-bookmark"></i>
  247. </button>
  248. </div>
  249. <div class="toot_reaction">
  250. <button>
  251. <i class="fa fa-fw fa-${status.halcyon.privacy_icon}" title="${status.halcyon.privacy_mode}"></i>
  252. </button>
  253. </div>
  254. </footer>
  255. </section>
  256. </div>
  257. </li>`);
  258. html.find(".toot_article").append(status.halcyon.media_views);
  259. html.find(".toot_article").append(status.halcyon.poll_object);
  260. return html;
  261. }
  262. function notifications_template(NotificationObj) {
  263. var notice_author_link;
  264. if(NotificationObj.account.acct.indexOf("@") == -1) notice_author_link = "/@"+NotificationObj.account.acct+"@"+current_instance+"?mid="+NotificationObj.account.id;
  265. else notice_author_link = "/@"+NotificationObj.account.acct+"?mid="+NotificationObj.account.id;
  266. if(NotificationObj.account.display_name.length == 0) {
  267. NotificationObj.account.display_name = NotificationObj.account.username;
  268. }
  269. NotificationObj.account.display_name = htmlEscape(NotificationObj.account.display_name);
  270. for(i=0;i<NotificationObj.account.emojis.length;i++) {
  271. NotificationObj.account.display_name = NotificationObj.account.display_name.replace(new RegExp(":"+NotificationObj.account.emojis[i].shortcode+":","g"),"<img src='"+NotificationObj.account.emojis[i].url+"' class='emoji'>");
  272. }
  273. if(NotificationObj.type === 'favourite') {
  274. NotificationObj.status = prepareStatus(NotificationObj.status);
  275. const html = (`
  276. <li sid="${NotificationObj.status.id}" class="notice_entry fav favourite toot_entry">
  277. <div class="notice_author_box">
  278. <a href="${notice_author_link}">
  279. <div class="icon_box">
  280. <img src="${NotificationObj.account.avatar}">
  281. </div>
  282. </a>
  283. <i class="fa fa-fw fa-star font-icon favourite"></i>
  284. <a class="notice_author" href="${notice_author_link}">
  285. <span class="emoji_poss">${NotificationObj.account.display_name}</span> ${__('favourited Your Toot')}
  286. </a>
  287. </div>
  288. <div class="notice_entry_body">
  289. <section class="toot_content">
  290. <header class="toot_header">
  291. <div class="text_ellipsis">
  292. <a href="${NotificationObj.status.halcyon.author_link}">
  293. <span class="displayname emoji_poss">
  294. ${NotificationObj.status.account.display_name}
  295. </span>
  296. <span class="username">
  297. @${NotificationObj.status.account.acct}${NotificationObj.status.halcyon.account_state_icons}
  298. </span>
  299. </a>
  300. </div>
  301. </header>
  302. <article class="toot_article emoji_poss">
  303. <p>${NotificationObj.status.content}</p>
  304. </article>
  305. <footer class="toot_footer"></footer>
  306. </section>
  307. </div>
  308. </li>`);
  309. return $(html);
  310. }
  311. else if(NotificationObj.type === 'reblog') {
  312. NotificationObj.status = prepareStatus(NotificationObj.status);
  313. html = (`
  314. <li sid="${NotificationObj.status.id}" class="notice_entry bos boost toot_entry">
  315. <div class="notice_author_box">
  316. <a href="${notice_author_link}">
  317. <div class="icon_box">
  318. <img src="${NotificationObj.account.avatar}">
  319. </div>
  320. </a>
  321. <i class="fa fa-fw fa-retweet font-icon boost"></i>
  322. <a class="notice_author" href="${notice_author_link}">
  323. <span class="emoji_poss" >${NotificationObj.account.display_name}</span> ${__('boosted Your Toot')}
  324. </a>
  325. </div>
  326. <blockquote class="notice_entry_body">
  327. <section class="toot_content">
  328. <header class="toot_header">
  329. <div class="text_ellipsis">
  330. <a href="${NotificationObj.status.halcyon.author_link}">
  331. <span class="displayname emoji_poss">
  332. ${NotificationObj.status.account.display_name}
  333. </span>
  334. <span class="username">
  335. @${NotificationObj.status.account.acct}${NotificationObj.status.halcyon.account_state_icons}
  336. </span>
  337. </a>
  338. </div>
  339. </header>
  340. <article class="toot_article emoji_poss">
  341. <p>${NotificationObj.status.content}</p>
  342. </article>
  343. <footer class="toot_footer"></footer>
  344. </section>
  345. </blockquote>
  346. </li>`);
  347. return $(html);
  348. }
  349. else if(NotificationObj.type === 'pleroma:emoji_reaction') {
  350. NotificationObj.status = prepareStatus(NotificationObj.status);
  351. const html = (`
  352. <li sid="${NotificationObj.status.id}" class="notice_entry emoji_reaction toot_entry">
  353. <div class="notice_author_box">
  354. <a href="${notice_author_link}">
  355. <div class="icon_box">
  356. <img src="${NotificationObj.account.avatar}">
  357. </div>
  358. </a>
  359. <i class="fa fa-fw fa-smile-o font-icon reaction"></i>
  360. <a class="notice_author" href="${notice_author_link}">
  361. <span class="emoji_poss">${NotificationObj.account.display_name}</span> ${__('reacted to Your Toot')}
  362. </a>
  363. </div>
  364. <div class="notice_entry_body">
  365. <span class="notice_emoji emoji_poss">${NotificationObj.emoji}</span>
  366. <section class="toot_content">
  367. <header class="toot_header">
  368. <div class="text_ellipsis">
  369. <a href="${NotificationObj.status.halcyon.author_link}">
  370. <span class="displayname emoji_poss">
  371. ${NotificationObj.status.account.display_name}
  372. </span>
  373. <span class="username">
  374. @${NotificationObj.status.account.acct}${NotificationObj.status.halcyon.account_state_icons}
  375. </span>
  376. </a>
  377. </div>
  378. </header>
  379. <article class="toot_article emoji_poss">
  380. <p>${NotificationObj.status.content}</p>
  381. </article>
  382. <footer class="toot_footer"></footer>
  383. </section>
  384. </div>
  385. </li>`);
  386. return $(html);
  387. }
  388. else if(NotificationObj.type === 'mention' || NotificationObj.type === 'poll') {
  389. NotificationObj.status = prepareStatus(NotificationObj.status);
  390. var poll_notify = "";
  391. if(NotificationObj.type === 'poll') {
  392. poll_notify = (`<div class="notice_author_box poll_notify_header">
  393. <i class="fa fa-fw fa-pie-chart font-icon poll"></i>
  394. <a class="notice_author" href="javascript:void(0)">
  395. ${__('A poll you participated in has ended')}
  396. </a>
  397. </div>`);
  398. }
  399. const html=$(`
  400. <li sid="${NotificationObj.status.id}" class="toot_entry">
  401. ${poll_notify}
  402. <div class="toot_entry_body">
  403. <a href="${notice_author_link}">
  404. <div class="icon_box">
  405. <img src="${NotificationObj.status.account.avatar}">
  406. </div>
  407. </a>
  408. <section class="toot_content">
  409. <header class="toot_header">
  410. <div class="text_ellipsis">
  411. <a href="${notice_author_link}">
  412. <span class="displayname emoji_poss">
  413. ${NotificationObj.status.account.display_name}
  414. </span>
  415. <span class="username">
  416. @${NotificationObj.status.account.acct}${NotificationObj.status.halcyon.account_state_icons}
  417. </span>
  418. <time datetime="${NotificationObj.status.halcyon.attr_datetime}">${NotificationObj.status.halcyon.datetime}</time>
  419. </a>
  420. </div>
  421. <div class="expand_button_wrap">
  422. <button class="expand_button">
  423. <i class="fa fa-fw fa-chevron-down"></i>
  424. </button>
  425. <div class="expand_menu invisible disallow_select">
  426. <ul>
  427. <li><a class="copylink_button" url="${NotificationObj.status.url}" >${__('Copy link to Toot')}</a></li>
  428. ${NotificationObj.status.halcyon.own_toot_buttons}
  429. </ul>
  430. <ul>
  431. <li><a href="${NotificationObj.status.url}" target="_blank">${__('View original')}</a></li>
  432. </ul>
  433. </div>
  434. </div>
  435. </header>
  436. <article class="toot_article ${NotificationObj.status.halcyon.article_option}">
  437. ${NotificationObj.status.halcyon.alert_text}
  438. <span class="status_content emoji_poss">
  439. ${NotificationObj.status.content}
  440. </span>
  441. ${NotificationObj.status.halcyon.preview_object}
  442. </article>
  443. ${NotificationObj.status.halcyon.reactions}
  444. <footer class="toot_footer"${NotificationObj.status.halcyon.footer_width}>
  445. <div class="toot_reaction">
  446. <button class="reply_button" tid="${NotificationObj.status.id}" mentions='${JSON.stringify(NotificationObj.status.mentions)}' display_name="${NotificationObj.account.display_name}" privacy="${NotificationObj.status.visibility}" content_warning="${htmlEscape(NotificationObj.status.spoiler_text)}">
  447. <i class="fa fa-fw fa-reply"></i>
  448. <span class="reaction_count reply_count">${NotificationObj.status.replies_count}</span>
  449. </button>
  450. </div>
  451. ${NotificationObj.status.halcyon.reblog_button}
  452. <div class="toot_reaction">
  453. <button class="fav_button" tid="${NotificationObj.status.id}" favourited="${NotificationObj.status.favourited}">
  454. <i class="fa fa-fw fa-star"></i>
  455. <span class="reaction_count fav_count">${NotificationObj.status.favourites_count}</span>
  456. </button>
  457. </div>
  458. <div class="toot_reaction">
  459. <button class="bookmark_button" tid="${NotificationObj.status.id}" bookmarked="${NotificationObj.status.bookmarked}">
  460. <i class="fa fa-fw fa-bookmark"></i>
  461. </button>
  462. </div>
  463. <div class="toot_reaction">
  464. <button>
  465. <i class="fa fa-fw fa-${NotificationObj.status.halcyon.privacy_icon}" title="${NotificationObj.status.halcyon.privacy_mode}"></i>
  466. </button>
  467. </div>
  468. </footer>
  469. </section>
  470. </div>
  471. </li>`);
  472. html.find(".toot_article").append(NotificationObj.status.halcyon.media_views);
  473. html.find(".toot_article").append(NotificationObj.status.halcyon.poll_object);
  474. return html;
  475. } else if(NotificationObj.type === 'follow') {
  476. const html=(`
  477. <li sid="${NotificationObj.id}" class="notice_entry fol toot_entry">
  478. <div class="notice_author_box">
  479. <a href="${notice_author_link}">
  480. <div class="icon_box">
  481. <img src="${NotificationObj.account.avatar}">
  482. </div>
  483. </a>
  484. <i class="fa fa-fw fa-user font-icon follow"></i>
  485. <a class="notice_author" href="${notice_author_link}">
  486. <span class="emoji_poss">${NotificationObj.account.display_name}</span> ${__('followed you')}
  487. </a>
  488. </div>
  489. </li>`);
  490. return $(html);
  491. }
  492. }
  493. function follows_template(AccountObj) {
  494. var profile_link;
  495. if(AccountObj.acct.indexOf("@") == -1) profile_link = "/@"+AccountObj.acct+"@"+current_instance+"?mid="+AccountObj.id;
  496. else profile_link = "/@"+AccountObj.acct+"?mid="+AccountObj.id;
  497. if(AccountObj.display_name.length == 0) {
  498. AccountObj.display_name = AccountObj.username;
  499. }
  500. AccountObj.display_name = htmlEscape(AccountObj.display_name);
  501. for(i=0;i<AccountObj.emojis.length;i++) {
  502. AccountObj.display_name = AccountObj.display_name.replace(new RegExp(":"+AccountObj.emojis[i].shortcode+":","g"),"<img src='"+AccountObj.emojis[i].url+"' class='emoji'>");
  503. }
  504. var account_state_icons = "";
  505. if(AccountObj.locked == true) account_state_icons += " <i class='fa fa-lock'></i>";
  506. if(AccountObj.bot == true) account_state_icons += " <img src='/assets/images/robot.svg' class='emoji'>";
  507. var html = (`
  508. <div class="follows_profile_box" mid="${AccountObj.id}">
  509. <div class="follows_profile_header">
  510. <img class="js_follows_header_image" src="${AccountObj.header}"/>
  511. </div>
  512. <div class="follows_profile">
  513. <div class="follows_profile_icon">
  514. <img class="js_follows_profile_image" src="${AccountObj.avatar}"/>
  515. </div>
  516. <button class="halcyon_button follow_button action_button" mid="${AccountObj.id}">
  517. <i class="fa fa-fw fa-user-plus"></i>
  518. <span>${__('Follow')}</span>
  519. </button>
  520. <div class="follows_profile_name_box">
  521. <a class="js_follows_profile_link emoji_poss" href="${profile_link}">
  522. <h2 class="js_follows_profile_displayname">
  523. ${AccountObj.display_name}
  524. </h2>
  525. <span class="js_follows_profile_username">
  526. @${AccountObj.acct}${account_state_icons}
  527. </span>
  528. </a>
  529. </div>
  530. <div class="follows_profile_bio emoji_poss">
  531. <p>${AccountObj.note}</p>
  532. </div>
  533. </div>
  534. </div>`);
  535. html = html.replace(new RegExp('class="emojione"',"g"),'class=emoji');
  536. return $(html);
  537. }
  538. function status_template(status, class_options) {
  539. if(status.reblog !== null) status = status.reblog;
  540. status = prepareStatus(status);
  541. const html=$(`
  542. <div sid="${status.id}" class="toot_detail ${class_options}">
  543. <div class="toot_detail_body">
  544. <header class="toot_header">
  545. <div class="icon_box">
  546. <img src="${status.account.avatar}">
  547. </div>
  548. <a href="${status.halcyon.account_link}">
  549. <span class="displayname emoji_poss">
  550. ${status.account.display_name}
  551. </span>
  552. <span class="username">
  553. @${status.account.acct}${status.halcyon.account_state_icons}
  554. </span>
  555. </a>
  556. <div class="expand_button_wrap">
  557. <button class="expand_button">
  558. <i class="fa fa-fw fa-chevron-down"></i>
  559. </button>
  560. <div class="expand_menu invisible disallow_select">
  561. <ul>
  562. <li><a class="copylink_button" url="${status.url}" >${__('Copy link to Toot')}</a></li>
  563. ${status.halcyon.own_toot_buttons}
  564. </ul>
  565. <ul>
  566. <li><a href="${status.url}" target="_blank">${__('View original')}</a></li>
  567. </ul>
  568. </div>
  569. </div>
  570. </header>
  571. <section class="toot_content">
  572. <article class="toot_article ${status.halcyon.article_option} emoji_poss">
  573. ${status.halcyon.alert_text}
  574. <span class="status_content emoji_poss">
  575. ${status.content}
  576. </span>
  577. ${status.halcyon.preview_object}
  578. </article>
  579. <time datetime="${status.halcyon.attr_datetime}">${status.halcyon.attr_datetime}</time>
  580. ${status.halcyon.reactions}
  581. </section>
  582. <footer class="toot_footer"${status.halcyon.footer_width}>
  583. <div class="toot_reaction">
  584. <button class="reply_button" tid="${status.id}" mentions='${JSON.stringify(status.mentions)}' display_name="${status.account.display_name}" privacy="${status.visibility}" content_warning="${htmlEscape(status.spoiler_text)}">
  585. <i class="fa fa-fw fa-reply"></i>
  586. <span class="reaction_count reply_count">${status.replies_count}</span>
  587. </button>
  588. </div>
  589. ${status.halcyon.reblog_button}
  590. <div class="toot_reaction">
  591. <button class="fav_button" tid="${status.id}" favourited="${status.favourited}">
  592. <i class="fa fa-fw fa-star"></i>
  593. <span class="reaction_count fav_count">${status.favourites_count}</span>
  594. </button>
  595. </div>
  596. <div class="toot_reaction">
  597. <button class="bookmark_button" tid="${status.id}" bookmarked="${status.bookmarked}">
  598. <i class="fa fa-fw fa-bookmark"></i>
  599. </button>
  600. </div>
  601. <div class="toot_reaction">
  602. <button>
  603. <i class="fa fa-fw fa-${status.halcyon.privacy_icon}" title="${status.halcyon.privacy_mode}"></i>
  604. </button>
  605. </div>
  606. </footer>
  607. </div>
  608. </div>
  609. <form id="reply_status_form" name="reply_status_form" class="status_form" sid="${status.id}" mentions='${JSON.stringify(status.mentions)}'>
  610. <div class="status_left icon_box">
  611. <img class="js_current_profile_image" src="${current_avatar}">
  612. </div>
  613. <div class="status_top">
  614. <input class="status_spoiler invisible" name="status_spoiler" placeholder="${__('Content warning')}" value="${htmlEscape(status.spoiler_text)}" data-random="${Math.round(Math.random()*1000)}" type="text"/>
  615. </div>
  616. <div class="status_main">
  617. <!-- text area -->
  618. <div class="status_textarea">
  619. <textarea class="emoji_poss" name="status_textarea" placeholder="${__('Toot your reply')}" data-random="${Math.round(Math.random()*1000)}"></textarea>
  620. <div class="media_attachments_preview_area invisible"></div>
  621. <div class="status_poll_editor invisible">
  622. <i class="fa fa-circle-o"></i> <input name="options[]" type="text" class="disallow_enter textfield poll_field"><br/>
  623. <i class="fa fa-circle-o"></i> <input name="options[]" type="text" class="disallow_enter textfield poll_field"><br/>
  624. <i class="fa fa-circle-o"></i> <input name="options[]" type="text" class="disallow_enter textfield poll_field"><br/>
  625. <i class="fa fa-circle-o"></i> <input name="options[]" type="text" class="disallow_enter textfield poll_field"><br/>
  626. <div style="height:32px;display:inline-block;padding-top:10px">${__("Expires in")} </div>
  627. <div style="float:right;margin-right:5px"><div class="poll_time"><input type="number" min="0" class="poll_days">${__('Days')}</div>
  628. <div class="poll_time"><input type="number" min="0" max="24" placeholder="0-24" class="poll_hours">${__('Hours')}</div>
  629. <div class="poll_time"><input type="number" min="0" max="60" placeholder="0-60" class="poll_mins">${__('Minutes')}</div></div><br/>
  630. <div class="poll_time_warning invisible"></div>
  631. <div class="switch poll_mc_switch">
  632. <input type="checkbox" class="poll_multiple_choice">
  633. <div class="switch-btn">
  634. <span></span>
  635. </div>
  636. </div>
  637. ${__("Multiple choice")}
  638. </div>
  639. </div>
  640. </div>
  641. <div class="status_bottom invisible">
  642. <!-- Media Attachment -->
  643. <label for="reply_status_media_atta" class="status_media_attachment status_option_button">
  644. <i class="fa fa-camera" aria-hidden="true"></i>
  645. </label>
  646. <!-- Content warning -->
  647. <label for="reply_status_cw" class="status_CW status_option_button">
  648. <span class="disallow_select">CW</span>
  649. </label>
  650. <!-- Not safe for work -->
  651. <label for="reply_status_nsfw" class="status_NSFW status_option_button">
  652. <span class="disallow_select">NSFW</span>
  653. </label>
  654. <!-- Privacy options -->
  655. <div class="status_privacy status_option_button expand_privacy_menu_button">
  656. <!-- Expand menu -->
  657. <i class="fa fa-${status.halcyon.privacy_icon}" aria-hidden="true"></i>
  658. <!-- Privacy options -->
  659. <div class="expand_privacy_menu invisible">
  660. <label for="reply_status_public" class="status_privacy select_privacy disallow_select" privacyicon="fa fa-globe">
  661. <i class="fa fa-globe" aria-hidden="true"></i>${__('Public')}
  662. </label>
  663. <label for="reply_status_unlisted" class="status_privacy select_privacy disallow_select" privacyicon="fa fa-unlock-alt">
  664. <i class="fa fa-unlock-alt" aria-hidden="true"></i>${__('Unlisted')}
  665. </label>
  666. <label for="reply_status_fonly" class="status_privacy select_privacy disallow_select" privacyicon="fa fa-lock">
  667. <i class="fa fa-lock" aria-hidden="true"></i>${__('Followers-only')}
  668. </label>
  669. <label for="reply_status_direct" class="status_privacy select_privacy disallow_select" privacyicon="fa fa-envelope">
  670. <i class="fa fa-envelope" aria-hidden="true"></i>${__('Direct')}
  671. </label>
  672. </div>
  673. </div>
  674. <label for="reply_status_poll" class="status_poll status_option_button">
  675. <i class="fa fa-pie-chart" aria-hidden="true"></i>
  676. </label>
  677. <label for="reply_status_emoji" class="status_emoji status_option_button">
  678. <i class="fa fa-smile-o" aria-hidden="true"></i>
  679. </label>
  680. <input id="reply_status_media_atta" name="files" type="file" multiple class="invisible"/>
  681. <input id="reply_status_cw" name="status_cw" type="checkbox" class="invisible" />
  682. <input id="reply_status_nsfw" name="status_nsfw" type="checkbox" class="invisible" />
  683. <input id="reply_status_public" name='privacy_option' value="public" class="invisible" type="radio"${status.halcyon.checked_public}>
  684. <input id="reply_status_unlisted" name='privacy_option' value="unlisted" class="invisible" type="radio"${status.halcyon.checked_unlisted}>
  685. <input id="reply_status_fonly" name='privacy_option' value="private" class="invisible" type="radio"${status.halcyon.checked_private}>
  686. <input id="reply_status_direct" name='privacy_option' value="direct" class="invisible" type="radio"${status.halcyon.checked_direct}>
  687. <div id="reply_status_emoji" name="status_emoji" type="button"></div>
  688. <div class="submit_status_label_wrap">
  689. <span class="character_count">
  690. ${current_instance_charlimit}
  691. </span>
  692. <label for="header_status_addfield" class="status_addfield status_option_button">
  693. <i class="fa fa-plus-circle" aria-hidden="true"></i>
  694. </label>
  695. <label for="reply_status_form_submit" class="submit_status_label">
  696. <div class="toot_button_label disallow_select">
  697. <i class="fa fa-reply" aria-hidden="true"></i>
  698. <span>${__('Reply')}</span>
  699. </div>
  700. </label>
  701. </div>
  702. <input id="reply_status_form_submit" class="submit_status" type="button" class="invisible"/>
  703. </div>
  704. </form>`);
  705. history.pushState(null, null, status.halcyon.account_link.replace("?mid=",'/status/'+status.id+"?mid="));
  706. html.find(".toot_article").append(status.halcyon.media_views);
  707. html.find(".toot_article").append(status.halcyon.poll_object);
  708. return html;
  709. }
  710. function media_template(status,media) {
  711. if(!status) {
  712. const html = (`
  713. <div class="media_detail">
  714. <div class="media_box">
  715. <img src="${media}">
  716. </div>
  717. </div>`);
  718. return $(html)
  719. }
  720. else {
  721. var pictures = new Array;
  722. var hidebackward = "";
  723. var hideforward ="";
  724. for(var i=0;i<status.media_attachments.length;i++) {
  725. if(status.media_attachments[i].remote_url != null) status.media_attachments[i].url = status.media_attachments[i].remote_url;
  726. if(status.media_attachments[i].description == null) status.media_attachments[i].description = "";
  727. if(status.media_attachments[i].type == "image" || status.media_attachments[i].type == "gifv") pictures.push(status.media_attachments[i].url);
  728. }
  729. console.log(media);
  730. console.log(parseInt(media));
  731. var mediacnt = pictures.indexOf(pictures.find(function(data) {if(data==this) return true},status.media_attachments[parseInt(media)].url));
  732. console.log(mediacnt);
  733. if(mediacnt == 0) hidebackward = " style='display:none'";
  734. if(mediacnt == pictures.length-1) hideforward = " style='display:none'";
  735. if(status.media_attachments[media].type == "image") var player = `<img src="${status.media_attachments[media].url}" title="${status.media_attachments[media].description}">`;
  736. else if(status.media_attachments[media].type == "gifv") {
  737. var vidprev = "";
  738. if(status.media_attachments[media].preview_url != status.media_attachments[media].url) vidprev = "<img src='"+status.media_attachments[media].preview_url+"'>";
  739. var player = (`<video frameborder="0" title="${status.media_attachments[media].description}" autoplay loop muted style="width:100%">
  740. <source src="${status.media_attachments[media].url}">
  741. ${vidprev}
  742. </video>`);
  743. }
  744. const status_template = timeline_template(status).html(),
  745. html = (`<div class="media_detail" pictures='${JSON.stringify(pictures)}' cid="${mediacnt}">
  746. <div class="media_box">
  747. <span class="media_backward"${hidebackward}><i class="fa fa-2x fa-chevron-left"></i></span>
  748. ${player}
  749. <span class="media_forward"${hideforward}><i class="fa fa-2x fa-chevron-right"></i></span>
  750. </div>
  751. <div class="toot_entry" sid="${status.id}">
  752. ${status_template}
  753. </div>
  754. </div>`);
  755. return $(html)
  756. }
  757. }
  758. function context_template(status,class_options) {
  759. var reblog_note = "";
  760. if(status.reblog !== null) {
  761. restatus = prepareStatus(status);
  762. status = restatus.reblog;
  763. reblog_note = (`<div class="boost_author_box">
  764. <a href="${restatus.halcyon.account_link}">
  765. <span class="emoji_poss"><i class="fa fa-fw fa-retweet"></i>${restatus.account.display_name} ${__('Boosted')}</span>
  766. </a>
  767. </div>`);
  768. }
  769. else status = prepareStatus(status);
  770. const html=$(`
  771. <div sid="${status.id}" class="toot_entry ${class_options}">
  772. ${reblog_note}
  773. <div class="toot_entry_body">
  774. <div class="icon_box">
  775. <img src="${status.account.avatar}">
  776. </div>
  777. <section class="toot_content">
  778. <header class="toot_header">
  779. <a href="${status.halcyon.account_link}">
  780. <span class="displayname emoji_poss">
  781. ${status.account.display_name}
  782. </span>
  783. <span class="username">
  784. @${status.account.acct}${status.halcyon.account_state_icons}
  785. </span>
  786. <time datetime="${status.halcyon.attr_datetime}">${status.halcyon.datetime}</time>
  787. </a>
  788. <div class="expand_button_wrap">
  789. <button class="expand_button">
  790. <i class="fa fa-fw fa-chevron-down"></i>
  791. </button>
  792. <div class="expand_menu invisible disallow_select">
  793. <ul>
  794. <li><a class="copylink_button" url="${status.url}" >${__('Copy link to Toot')}</a></li>
  795. ${status.halcyon.own_toot_buttons}
  796. </ul>
  797. <ul>
  798. <li><a href="${status.url}" target="_blank">${__('View original')}</a></li>
  799. </ul>
  800. </div>
  801. </div>
  802. </header>
  803. <article class="toot_article ${status.halcyon.article_option}">
  804. ${status.halcyon.alert_text}
  805. <span class="status_content emoji_poss">
  806. ${status.content}
  807. </span>
  808. </article>
  809. ${status.halcyon.reactions}
  810. <footer class="toot_footer"${status.halcyon.footer_width}>
  811. <div class="toot_reaction">
  812. <button class="reply_button" tid="${status.id}" mentions='${JSON.stringify(status.mentions)}' display_name="${status.account.display_name}" privacy="${status.visibility}" content_warning="${htmlEscape(status.spoiler_text)}">
  813. <i class="fa fa-fw fa-reply"></i>
  814. <span class="reaction_count reply_count">${status.replies_count}</span>
  815. </button>
  816. </div>
  817. ${status.halcyon.reblog_button}
  818. <div class="toot_reaction">
  819. <button class="fav_button" tid="${status.id}" favourited="${status.favourited}">
  820. <i class="fa fa-fw fa-star"></i>
  821. <span class="reaction_count fav_count">${status.favourites_count}</span>
  822. </button>
  823. </div>
  824. <div class="toot_reaction">
  825. <button class="bookmark_button" tid="${status.id}" bookmarked="${status.bookmarked}">
  826. <i class="fa fa-fw fa-bookmark"></i>
  827. </button>
  828. </div>
  829. <div class="toot_reaction">
  830. <button>
  831. <i class="fa fa-fw fa-${status.halcyon.privacy_icon}" title="${status.halcyon.privacy_mode}"></i>
  832. </button>
  833. </div>
  834. </footer>
  835. </section>
  836. </div>
  837. </div>`);
  838. html.find(".toot_article").append(status.halcyon.media_views);
  839. html.find(".toot_article").append(status.halcyon.poll_object);
  840. return html;
  841. }
  842. function announcement_template(announcement) {
  843. var reactions;
  844. var datetime = "";
  845. reactions = parse_reactions(announcement.reactions);
  846. if(announcement.starts_at && announcement.ends_at) {
  847. var start = new Date(announcement.starts_at);
  848. var end = new Date(announcement.ends_at);
  849. datetime = (`<i class="fa fa-calendar"></i> ${start.getFullYear()}-${addZero(start.getMonth()+1)}-${addZero(start.getDate())}`);
  850. if(!announcement.all_day) datetime += (` <i class="fa fa-clock-o"></i> ${addZero(start.getHours())}:${addZero(start.getMinutes())}`);
  851. datetime += (` - <i class="fa fa-calendar"></i> ${end.getFullYear()}-${addZero(end.getMonth()+1)}-${addZero(end.getDate())}`);
  852. if(!announcement.all_day) datetime += (` <i class="fa fa-clock-o"></i> ${addZero(end.getHours())}:${addZero(end.getMinutes())}`);
  853. }
  854. announcement = prepareAnnouncement(announcement);
  855. const html=(`<div class="announcement" aid="${announcement.id}">
  856. <div class="announcement_icon"><i class="fa fa-3x fa-exclamation-triangle"></i></div>
  857. <div class="announcement_content">
  858. <div class="announcement_text emoji_poss">${announcement.content}</div>
  859. <div class="announcement_reactions">${reactions}</div>
  860. <div class="announcement_date">${datetime}</div>
  861. </div></div>`);
  862. return html;
  863. }