WIP: Add: announcement(except: mark as read)
This commit is contained in:
parent
ab265fae62
commit
b642d42229
|
@ -490,6 +490,9 @@ textarea {
|
|||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
#sabakanMark {
|
||||
background-color: var(--emphasized);
|
||||
}
|
||||
|
||||
/*スクロールバー*/
|
||||
::-webkit-scrollbar {
|
||||
|
|
|
@ -559,7 +559,7 @@ p:not(:last-child) {
|
|||
z-index: 500;
|
||||
padding: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: 40px 1fr 1fr 24px;
|
||||
grid-template-columns: 40px 60px 1fr 24px;
|
||||
grid-template-rows: 30px 30px;
|
||||
grid-template-areas: 'notice notice_name notice_name a2' 'notice a1 sta a3' 'notf-box notf-box notf-box notf-box';
|
||||
}
|
||||
|
@ -862,3 +862,31 @@ audio {
|
|||
.box .ui-resizable-se {
|
||||
display: none !important;
|
||||
}
|
||||
.announcement {
|
||||
padding: 5px;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.announReaction {
|
||||
width: 35px;
|
||||
height: 1.7rem;
|
||||
font-size: 1.1rem;
|
||||
margin: 3px;
|
||||
cursor: pointer;
|
||||
border: solid 1px;
|
||||
padding-left: 2px;
|
||||
background-color: var(--notfbox);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.announReaction img {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
.announReaction.reactioned {
|
||||
background-color: var(--emphasized);
|
||||
}
|
||||
.announReaction.add {
|
||||
width: 19px;
|
||||
}
|
||||
.reactionsPack {
|
||||
display: flex;
|
||||
}
|
|
@ -1,84 +1,105 @@
|
|||
var defaultemojiList = ["activity", "flag", "food", "nature", "object", "people", "place", "symbol"];
|
||||
var defaultemojiList = ['activity', 'flag', 'food', 'nature', 'object', 'people', 'place', 'symbol']
|
||||
var defaultemoji = {
|
||||
activity: activity,
|
||||
flag: flag,
|
||||
food: food,
|
||||
nature: nature,
|
||||
object: object,
|
||||
people: people,
|
||||
place: place,
|
||||
symbol: symbol
|
||||
};
|
||||
if (lang == "ja") {
|
||||
var defaultemojiname = {
|
||||
activity: "活動",
|
||||
flag: "国旗",
|
||||
food: "食べ物",
|
||||
nature: "自然",
|
||||
object: "もの",
|
||||
people: "ひと",
|
||||
place: "場所",
|
||||
symbol: "記号"
|
||||
};
|
||||
activity: activity,
|
||||
flag: flag,
|
||||
food: food,
|
||||
nature: nature,
|
||||
object: object,
|
||||
people: people,
|
||||
place: place,
|
||||
symbol: symbol
|
||||
}
|
||||
if (lang == 'ja') {
|
||||
var defaultemojiname = {
|
||||
activity: '活動',
|
||||
flag: '国旗',
|
||||
food: '食べ物',
|
||||
nature: '自然',
|
||||
object: 'もの',
|
||||
people: 'ひと',
|
||||
place: '場所',
|
||||
symbol: '記号'
|
||||
}
|
||||
} else {
|
||||
var defaultemojiname = {
|
||||
activity: "Activities",
|
||||
flag: "Flags",
|
||||
food: "Foods",
|
||||
nature: "Nature",
|
||||
object: "Tools",
|
||||
people: "People",
|
||||
place: "Places",
|
||||
symbol: "Symbols"
|
||||
};
|
||||
var defaultemojiname = {
|
||||
activity: 'Activities',
|
||||
flag: 'Flags',
|
||||
food: 'Foods',
|
||||
nature: 'Nature',
|
||||
object: 'Tools',
|
||||
people: 'People',
|
||||
place: 'Places',
|
||||
symbol: 'Symbols'
|
||||
}
|
||||
}
|
||||
|
||||
function defaultEmoji(target) {
|
||||
var json = defaultemoji[target];
|
||||
var emojis = "";
|
||||
Object.keys(json).forEach(function (key) {
|
||||
var emoji = json[key];
|
||||
emojis = emojis + '<a onclick="defEmoji(\'' + emoji["shortcode"] + '\')" class="pointer"><span style="width: 20px; height: 20px; display: inline-block; background-image: url(\'../../img/sheet.png\'); background-size: 4900%; background-position: ' + emoji["css"] + ';"></span></a>';
|
||||
});
|
||||
$("#emoji-list").html(emojis);
|
||||
$("#now-emoji").text(lang.lang_defaultemojis_text.replace("{{cat}}", defaultemojiname[target]));
|
||||
$(".emoji-control").addClass("hide");
|
||||
var announcement = false
|
||||
if ($('#media').val() == 'announcement') {
|
||||
announcement = true
|
||||
}
|
||||
var json = defaultemoji[target]
|
||||
var emojis = ''
|
||||
Object.keys(json).forEach(function(key) {
|
||||
var emoji = json[key]
|
||||
if (announcement) {
|
||||
var def = `<a onclick="emojiReactionDef('${emoji['shortcode']}')" class="pointer">`
|
||||
} else {
|
||||
var def = `<a onclick="defEmoji('${emoji['shortcode']}')" class="pointer">`
|
||||
}
|
||||
emojis =
|
||||
emojis +
|
||||
`${def}
|
||||
<span style="
|
||||
width: 20px; height: 20px; display: inline-block; background-image: url('../../img/sheet.png'); background-size: 4900%;
|
||||
background-position:${emoji['css']};"></span>
|
||||
</a>`
|
||||
})
|
||||
$('#emoji-list').html(emojis)
|
||||
$('#now-emoji').text(lang.lang_defaultemojis_text.replace('{{cat}}', defaultemojiname[target]))
|
||||
$('.emoji-control').addClass('hide')
|
||||
}
|
||||
function customEmoji() {
|
||||
$("#emoji-suggest").val("");
|
||||
$(".emoji-control").removeClass("hide");
|
||||
emojiList('home')
|
||||
$('#emoji-suggest').val('')
|
||||
$('.emoji-control').removeClass('hide')
|
||||
emojiList('home')
|
||||
}
|
||||
function defEmoji(target) {
|
||||
var selin = $("#textarea").prop('selectionStart');
|
||||
if (!selin) {
|
||||
selin = 0;
|
||||
}
|
||||
var emojiraw = newpack.filter(function (item, index) {
|
||||
if (item.short_name == target) return true;
|
||||
});
|
||||
var hex = emojiraw[0].unified.split("-");
|
||||
if (hex.length === 2) {
|
||||
emoji = twemoji.convert.fromCodePoint(hex[0]) + twemoji.convert.fromCodePoint(hex[1]);
|
||||
} else {
|
||||
emoji = twemoji.convert.fromCodePoint(hex[0]);
|
||||
}
|
||||
var now = $("#textarea").val();
|
||||
var before = now.substr(0, selin);
|
||||
var after = now.substr(selin, now.length);
|
||||
newt = before + emoji + after;
|
||||
$("#textarea").val(newt);
|
||||
$("#textarea").focus();
|
||||
var selin = $('#textarea').prop('selectionStart')
|
||||
if (!selin) {
|
||||
selin = 0
|
||||
}
|
||||
var emojiraw = newpack.filter(function(item, index) {
|
||||
if (item.short_name == target) return true
|
||||
})
|
||||
var hex = emojiraw[0].unified.split('-')
|
||||
if (hex.length === 2) {
|
||||
emoji = twemoji.convert.fromCodePoint(hex[0]) + twemoji.convert.fromCodePoint(hex[1])
|
||||
} else {
|
||||
emoji = twemoji.convert.fromCodePoint(hex[0])
|
||||
}
|
||||
var now = $('#textarea').val()
|
||||
var before = now.substr(0, selin)
|
||||
var after = now.substr(selin, now.length)
|
||||
newt = before + emoji + after
|
||||
$('#textarea').val(newt)
|
||||
$('#textarea').focus()
|
||||
}
|
||||
function faicon() {
|
||||
var json = faicons;
|
||||
var emojis = "";
|
||||
Object.keys(json).forEach(function (key) {
|
||||
var emoji = json[key];
|
||||
var eje = emoji.replace(/fa-/g, "");
|
||||
emojis = emojis + '<a onclick="emojiInsert(\'[faicon]' + eje + '[/faicon]\')" class="pointer white-text" style="font-size:24px"><i class="fa ' + emoji + '"></i></a>';
|
||||
});
|
||||
$("#emoji-list").html(emojis);
|
||||
$("#now-emoji").text("faicon");
|
||||
$(".emoji-control").addClass("hide");
|
||||
var json = faicons
|
||||
var emojis = ''
|
||||
Object.keys(json).forEach(function(key) {
|
||||
var emoji = json[key]
|
||||
var eje = emoji.replace(/fa-/g, '')
|
||||
emojis =
|
||||
emojis +
|
||||
'<a onclick="emojiInsert(\'[faicon]' +
|
||||
eje +
|
||||
'[/faicon]\')" class="pointer white-text" style="font-size:24px"><i class="fa ' +
|
||||
emoji +
|
||||
'"></i></a>'
|
||||
})
|
||||
$('#emoji-list').html(emojis)
|
||||
$('#now-emoji').text('faicon')
|
||||
$('.emoji-control').addClass('hide')
|
||||
}
|
|
@ -193,7 +193,15 @@ function emojiGet(parse, started) {
|
|||
function emojiList(target, reaction) {
|
||||
$('#now-emoji').text(lang.lang_emoji_custom)
|
||||
var acct_id = $('#post-acct-sel').val()
|
||||
if (reaction && localStorage.getItem('emojiReaction_' + acct_id) != 'true') {
|
||||
if(reaction && $('#media').val() == 'misskey') {
|
||||
var misskeyReact = true
|
||||
} else {
|
||||
var misskeyReact = false
|
||||
}
|
||||
if (
|
||||
misskeyReact &&
|
||||
localStorage.getItem('emojiReaction_' + acct_id) != 'true'
|
||||
) {
|
||||
console.error('Disabled')
|
||||
clear()
|
||||
hide()
|
||||
|
@ -263,9 +271,20 @@ function emojiList(target, reaction) {
|
|||
var emoji = obj[i]
|
||||
if (emoji) {
|
||||
if (reaction) {
|
||||
html =
|
||||
html +
|
||||
`<a onclick="emojiReaction(':${emoji.shortcode}:')" class="pointer"><img src="${emoji.url}" width="20" title="${emoji.shortcode}"></a>`
|
||||
if (emoji.divider) {
|
||||
html = html + '<p style="margin-bottom:0">' + emoji.cat + '</p>'
|
||||
} else {
|
||||
if (emoji.listed) {
|
||||
if(misskeyReact) {
|
||||
var shortcode = `:${emoji.shortcode}:`
|
||||
} else {
|
||||
var shortcode = emoji.shortcode
|
||||
}
|
||||
html =
|
||||
html +
|
||||
`<a onclick="emojiReaction('${shortcode}')" class="pointer"><img src="${emoji.url}" width="20" title="${emoji.shortcode}"></a>`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (emoji.divider) {
|
||||
html = html + '<p style="margin-bottom:0">' + emoji.cat + '</p>'
|
||||
|
|
|
@ -116,6 +116,7 @@ function reactiontoggle(id, acct_id, tlid) {
|
|||
//reactioncustom
|
||||
function reactioncustom(acct_id, id) {
|
||||
$('#reply').val(id)
|
||||
$('#media').val('misskey')
|
||||
$('#unreact').hide()
|
||||
$('#addreact').removeClass('hide')
|
||||
$('#post-acct-sel').val(acct_id)
|
||||
|
@ -186,9 +187,14 @@ function reactRefreshCore(json) {
|
|||
}
|
||||
}
|
||||
function emojiReaction(emoji) {
|
||||
var media = $('#media').val()
|
||||
var acct_id = $('#post-acct-sel').val()
|
||||
var id = $('#reply').val()
|
||||
reaction(emoji, id, acct_id, null)
|
||||
if(media == 'announcement') {
|
||||
announReaction(id, acct_id, 0, false, emoji)
|
||||
} else {
|
||||
reaction(emoji, id, acct_id, null)
|
||||
}
|
||||
clear()
|
||||
hide()
|
||||
}
|
||||
|
|
145
app/js/tl/announParse.js
Normal file
145
app/js/tl/announParse.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
function announParse(obj, acct_id, tlid) {
|
||||
var template = ''
|
||||
var datetype = localStorage.getItem('datetype')
|
||||
var gif = localStorage.getItem('gif')
|
||||
//Ticker
|
||||
var tickerck = localStorage.getItem('ticker_ok')
|
||||
if (tickerck == 'yes') {
|
||||
var ticker = true
|
||||
} else if (!ticker || ticker == 'no') {
|
||||
var ticker = false
|
||||
}
|
||||
if (!datetype) {
|
||||
datetype = 'absolute'
|
||||
}
|
||||
if (!gif) {
|
||||
var gif = 'yes'
|
||||
}
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
var toot = obj[key]
|
||||
var content = toot.content
|
||||
if (toot.emojis) {
|
||||
Object.keys(toot.emojis).forEach(function(key1) {
|
||||
var emoji = toot.emojis[key1]
|
||||
var shortcode = emoji.shortcode
|
||||
if (gif == 'yes') {
|
||||
var emoSource = emoji.url
|
||||
} else {
|
||||
var emoSource = emoji.static_url
|
||||
}
|
||||
var emoji_url = `
|
||||
<img draggable="false" src="${emoSource}" class="emoji-img" data-emoji="${shortcode}"
|
||||
alt=" :${shortcode}: " title="${shortcode}" onclick="this.classList.toggle('bigemoji');">
|
||||
`
|
||||
var regExp = new RegExp(':' + shortcode + ':', 'g')
|
||||
content = content.replace(regExp, emoji_url)
|
||||
})
|
||||
}
|
||||
content = twemoji.parse(content)
|
||||
var reactions = ''
|
||||
//既存のリアクション
|
||||
if (toot.reactions) {
|
||||
Object.keys(toot.reactions).forEach(function(key2) {
|
||||
var reaction = toot.reactions[key2]
|
||||
//普通の絵文字 or カスタム絵文字 は文字数判断。ただしスコットランド国旗みたいなやべぇやつに注意
|
||||
var splitter = new GraphemeSplitter()
|
||||
if (splitter.splitGraphemes(reaction.name).length > 1) {
|
||||
//カスタム絵文字
|
||||
var shortcode = reaction.shortcode
|
||||
if (gif == 'yes') {
|
||||
var emoSource = reaction.url
|
||||
} else {
|
||||
var emoSource = reaction.static_url
|
||||
}
|
||||
var emoji_url = `
|
||||
<img draggable="false" src="${emoSource}" class="emoji-img" data-emoji="${shortcode}"
|
||||
alt=" :${shortcode}: " title="${shortcode}">`
|
||||
} else {
|
||||
emoji_url = twemoji.parse(reaction.name)
|
||||
}
|
||||
var addClass = ''
|
||||
if (reaction.me) {
|
||||
addClass = 'reactioned'
|
||||
}
|
||||
reactions =
|
||||
reactions +
|
||||
`<div class="announReaction ${addClass}" onclick="announReaction('${toot.id}', '${acct_id}', '${tlid}', ${reaction.me},'${reaction.name}')">
|
||||
${emoji_url} ${reaction.count}
|
||||
</div>`
|
||||
})
|
||||
}
|
||||
if (toot.ends_at) {
|
||||
var ended = `<div class="announReaction" title="${date(poll.expires_at, 'absolute')}" style="width: auto; cursor: default;">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
${date(toot.ends_at, datetype)}
|
||||
</div>`
|
||||
} else {
|
||||
var ended = ''
|
||||
}
|
||||
|
||||
template =
|
||||
template +
|
||||
`<div class="announcement">
|
||||
${content}
|
||||
<div class="reactionsPack">
|
||||
${reactions}
|
||||
<div class="announReaction add" onclick="announReactionNew('${toot.id}', '${acct_id}', '${tlid}')"><i class="fas fa-plus"></i></div>
|
||||
${ended}
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
return template
|
||||
}
|
||||
function announReaction(id, acct_id, tlid, del, name) {
|
||||
var at = localStorage.getItem('acct_' + acct_id + '_at')
|
||||
var domain = localStorage.getItem('domain_' + acct_id)
|
||||
var start = 'https://' + domain + '/api/v1/announcements/' + id + '/reactions/' + encodeURIComponent(name)
|
||||
var httpreq = new XMLHttpRequest()
|
||||
if(del) {
|
||||
var method = 'DELETE'
|
||||
} else {
|
||||
var method = 'PUT'
|
||||
}
|
||||
httpreq.open(method, start, true)
|
||||
httpreq.setRequestHeader('Content-Type', 'application/json')
|
||||
httpreq.setRequestHeader('Authorization', 'Bearer ' + at)
|
||||
httpreq.responseType = 'json'
|
||||
httpreq.send()
|
||||
httpreq.onreadystatechange = function() {
|
||||
if (httpreq.readyState === 4) {
|
||||
var json = httpreq.response
|
||||
if (this.status !== 200) {
|
||||
setLog(start, this.status, this.response)
|
||||
}
|
||||
announ(acct_id, tlid)
|
||||
}
|
||||
}
|
||||
}
|
||||
function announReactionNew(id, acct_id, tlid) {
|
||||
$('#reply').val(id)
|
||||
$('#media').val('announcement')
|
||||
$('#unreact').hide()
|
||||
$('#addreact').removeClass('hide')
|
||||
$('#post-acct-sel').val(acct_id)
|
||||
$('select').formSelect()
|
||||
localStorage.setItem('nohide', true)
|
||||
show()
|
||||
emojiToggle(true)
|
||||
$('#left-side').hide()
|
||||
}
|
||||
function emojiReactionDef(target) {
|
||||
var emojiraw = newpack.filter(function(item, index) {
|
||||
if (item.short_name == target) return true
|
||||
})
|
||||
var hex = emojiraw[0].unified.split('-')
|
||||
if (hex.length === 2) {
|
||||
emoji = twemoji.convert.fromCodePoint(hex[0]) + twemoji.convert.fromCodePoint(hex[1])
|
||||
} else {
|
||||
emoji = twemoji.convert.fromCodePoint(hex[0])
|
||||
}
|
||||
var acct_id = $('#post-acct-sel').val()
|
||||
var id = $('#reply').val()
|
||||
announReaction(id, acct_id, 0, false, emoji)
|
||||
clear()
|
||||
hide()
|
||||
}
|
|
@ -880,7 +880,7 @@ function misskeyUserparse(obj, auth, acct_id, tlid, popup) {
|
|||
}
|
||||
var ftxt = lang.lang_parse_followed;
|
||||
if (popup > 0 || popup == -1) {
|
||||
var notftext = '<span class="cbadge"title="' + date(toot.createdAt,
|
||||
var notftext = '<span class="cbadge" title="' + date(toot.createdAt,
|
||||
'absolute') + '(' + lang.lang_parse_notftime + ')"><i class="far fa-clock"></i>' + date(toot.createdAt,
|
||||
datetype) +
|
||||
'</span>' + ftxt + '<br>';
|
||||
|
|
|
@ -64,6 +64,9 @@ function tl(type, data, acct_id, tlid, delc, voice, mode) {
|
|||
)
|
||||
$('#notice_icon_' + tlid).text('bookmark')
|
||||
return
|
||||
} else if (type == 'home') {
|
||||
//ホームならお知らせ「も」取りに行く
|
||||
announ(acct_id, tlid);
|
||||
}
|
||||
localStorage.setItem('now', type)
|
||||
todo(cap(type) + ' TL Loading...')
|
||||
|
@ -311,6 +314,8 @@ function reload(type, cc, acct_id, tlid, data, mute, delc, voice, mode) {
|
|||
}
|
||||
} else if (typeA == 'filters_changed') {
|
||||
filterUpdate(acct_id)
|
||||
} else if (~typeA.indexOf('announcement')) {
|
||||
announ(acct_id, tlid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1167,3 +1172,33 @@ function getBookmark(acct_id, tlid, more) {
|
|||
}
|
||||
}
|
||||
}
|
||||
//Announcement
|
||||
function announ(acct_id, tlid) {
|
||||
var at = localStorage.getItem('acct_' + acct_id + '_at')
|
||||
var domain = localStorage.getItem('domain_' + acct_id)
|
||||
var start = 'https://' + domain + '/api/v1/announcements'
|
||||
var httpreq = new XMLHttpRequest()
|
||||
httpreq.open('GET', start, true)
|
||||
httpreq.setRequestHeader('Content-Type', 'application/json')
|
||||
httpreq.setRequestHeader('Authorization', 'Bearer ' + at)
|
||||
httpreq.responseType = 'json'
|
||||
httpreq.send()
|
||||
httpreq.onreadystatechange = function() {
|
||||
if (httpreq.readyState === 4) {
|
||||
var json = httpreq.response
|
||||
if (this.status !== 200) {
|
||||
setLog(start, this.status, this.response)
|
||||
}
|
||||
if (json.length > 0) {
|
||||
$('.notf-announ_' + acct_id).removeClass('hide')
|
||||
$('.notf-announ_' + acct_id + '_ct').text(json.length)
|
||||
} else {
|
||||
$('.notf-announ_' + acct_id).addClass('hide')
|
||||
}
|
||||
var templete = announParse(json, acct_id, tlid)
|
||||
$('#announce_' + tlid).html(templete)
|
||||
jQuery('time.timeago').timeago()
|
||||
todc()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -234,7 +234,7 @@ function parseColumn(target, dontclose) {
|
|||
var unread = `<a id="unread_${key}" onclick="showUnread('${key}','${acct.type}','${acct.domain}')"
|
||||
class="setting nex" title="${lang.lang_layout_unread}">
|
||||
<i class="material-icons waves-effect nex">more</i>
|
||||
</a>`
|
||||
</a>${lang.lang_layout_unread}<br>`
|
||||
var notfDomain = acct.domain
|
||||
var notfKey = key
|
||||
var if_tag = ''
|
||||
|
@ -368,7 +368,10 @@ function parseColumn(target, dontclose) {
|
|||
title="${unique_notf}" ${icnsert}>
|
||||
<i class="material-icons waves-effect nex notf-icon_${acct.domain}">notifications</i>
|
||||
</a>
|
||||
${unread}
|
||||
<span class="cbadge hide notf-announ_${acct.domain}" style="margin-right:0" onclick="notfToggle('${acct.domain}','${key}')">
|
||||
<i class="fas fa-bullhorn"></i>
|
||||
<span class="notf-announ_${acct.domain}_ct">0</span>
|
||||
</span>
|
||||
${if_tag_btn}
|
||||
</div>
|
||||
<div class="area-sta">
|
||||
|
@ -389,10 +392,12 @@ function parseColumn(target, dontclose) {
|
|||
</div>
|
||||
</div>
|
||||
<div class="column-hide notf-indv-box z-depth-4" id="notf-box_${notfKey}">
|
||||
<div id="announce_${notfKey}" style="border: 1px solid"></div>
|
||||
<div id="notifications_${notfKey}" data-notf="${notfDomain}" data-type="notf" class="notf-timeline">
|
||||
</div>
|
||||
</div>
|
||||
<div class="column-hide notf-indv-box" id="util-box_${key}" style="padding:5px;">
|
||||
${unread}
|
||||
${exclude}${left_hold}
|
||||
<a onclick="mediaToggle('${key}')" class="setting nex">
|
||||
<i class="material-icons waves-effect nex" title="${lang.lang_layout_mediafil}">perm_media</i>
|
||||
|
|
|
@ -1226,6 +1226,7 @@
|
|||
<script type="text/javascript" src="../../js/tl/misskeyparse.js"></script>
|
||||
<script type="text/javascript" src="../../js/tl/dm.js"></script>
|
||||
<script type="text/javascript" src="../../js/ui/scroll.js"></script>
|
||||
<script type="text/javascript" src="../../js/tl/announParse.js"></script>
|
||||
<script type="text/javascript" src="../../js/tl/tl.js"></script>
|
||||
<script type="text/javascript" src="../../js/tl/card.js"></script>
|
||||
<script type="text/javascript" src="../../js/tl/parse.js"></script>
|
||||
|
|
Loading…
Reference in New Issue
Block a user