diff --git a/.gitignore b/.gitignore
index 489cc58b..1ab6dd1c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,7 +26,7 @@ app/git
*.code-workspace
releasenote.md
app/yarn-error.log
-app/js/platform/aiscript.js
+app/js/platform/native.js
app/view/es-ES
app/view/fr-FR
app/view/no-NO
diff --git a/app/js/platform/first.js b/app/js/platform/first.js
index 2b14d839..d2d9528c 100644
--- a/app/js/platform/first.js
+++ b/app/js/platform/first.js
@@ -1,312 +1,303 @@
-window.onload = function () {
- console.log('loaded')
- initPostbox()
- connection()
- initPlugin(plugins)
- if (localStorage.getItem('control-center-np')) $('#ccnp').removeClass('hide')
+window.onload = function() {
+ console.log('loaded')
+ initPostbox()
+ connection()
+ initPlugin(plugins)
+ if (localStorage.getItem('control-center-np')) $('#ccnp').removeClass('hide')
}
-$.strip_tags = function (str, allowed) {
- if (!str) {
- return ''
- }
- allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('')
- var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi,
- commentsAndPhpTags = /|<\?(?:php)?[\s\S]*?\?>/gi
- return str.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
- return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''
- })
+$.strip_tags = function(str, allowed) {
+ if (!str) {
+ return ''
+ }
+ allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('')
+ var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi,
+ commentsAndPhpTags = /|<\?(?:php)?[\s\S]*?\?>/gi
+ return str.replace(commentsAndPhpTags, '').replace(tags, function($0, $1) {
+ return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''
+ })
}
+
function escapeHTML(str) {
- if (!str) {
- return ''
- }
- return str
- .replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''')
+ if (!str) {
+ return ''
+ }
+ return str
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
}
//PHPのnl2brと同様
function nl2br(str) {
- if (!str) {
- return ''
- }
- str = str.replace(/\r\n/g, '
')
- str = str.replace(/(\n|\r)/g, '
')
- return str
+ if (!str) {
+ return ''
+ }
+ str = str.replace(/\r\n/g, '
')
+ str = str.replace(/(\n|\r)/g, '
')
+ return str
}
+
function br2nl(str) {
- if (!str) {
- return ''
- }
- str = str.replace(/
/g, '\r\n')
- return str
+ if (!str) {
+ return ''
+ }
+ str = str.replace(/
/g, '\r\n')
+ return str
}
+
function formattime(date) {
- var str = date.getFullYear() + '-'
- if (date.getMonth() + 1 < 10) {
- str = str + '0' + (date.getMonth() + 1) + '-'
- } else {
- str = str + (date.getMonth() + 1) + '-'
- }
- if (date.getDate() < 10) {
- str = str + '0' + date.getDate()
- } else {
- str = str + date.getDate()
- }
- str = str + 'T'
- if (date.getHours() < 10) {
- str = str + '0' + date.getHours() + ':'
- } else {
- str = str + date.getHours() + ':'
- }
- if (date.getMinutes() < 10) {
- str = str + '0' + date.getMinutes()
- } else {
- str = str + date.getMinutes()
- }
- return escapeHTML(str)
+ var str = date.getFullYear() + '-'
+ if (date.getMonth() + 1 < 10) {
+ str = str + '0' + (date.getMonth() + 1) + '-'
+ } else {
+ str = str + (date.getMonth() + 1) + '-'
+ }
+ if (date.getDate() < 10) {
+ str = str + '0' + date.getDate()
+ } else {
+ str = str + date.getDate()
+ }
+ str = str + 'T'
+ if (date.getHours() < 10) {
+ str = str + '0' + date.getHours() + ':'
+ } else {
+ str = str + date.getHours() + ':'
+ }
+ if (date.getMinutes() < 10) {
+ str = str + '0' + date.getMinutes()
+ } else {
+ str = str + date.getMinutes()
+ }
+ return escapeHTML(str)
}
+
function formattimeutc(date) {
- var str = date.getUTCFullYear() + '-'
- if (date.getUTCMonth() + 1 < 10) {
- str = str + '0' + (date.getUTCMonth() + 1) + '-'
- } else {
- str = str + (date.getUTCMonth() + 1) + '-'
- }
- if (date.getUTCDate() < 10) {
- str = str + '0' + date.getUTCDate()
- } else {
- str = str + date.getUTCDate()
- }
- str = str + 'T'
- if (date.getUTCHours() < 10) {
- str = str + '0' + date.getUTCHours() + ':'
- } else {
- str = str + date.getUTCHours() + ':'
- }
- if (date.getUTCMinutes() < 10) {
- str = str + '0' + date.getUTCMinutes()
- } else {
- str = str + date.getUTCMinutes()
- }
- return escapeHTML(str)
+ var str = date.getUTCFullYear() + '-'
+ if (date.getUTCMonth() + 1 < 10) {
+ str = str + '0' + (date.getUTCMonth() + 1) + '-'
+ } else {
+ str = str + (date.getUTCMonth() + 1) + '-'
+ }
+ if (date.getUTCDate() < 10) {
+ str = str + '0' + date.getUTCDate()
+ } else {
+ str = str + date.getUTCDate()
+ }
+ str = str + 'T'
+ if (date.getUTCHours() < 10) {
+ str = str + '0' + date.getUTCHours() + ':'
+ } else {
+ str = str + date.getUTCHours() + ':'
+ }
+ if (date.getUTCMinutes() < 10) {
+ str = str + '0' + date.getUTCMinutes()
+ } else {
+ str = str + date.getUTCMinutes()
+ }
+ return escapeHTML(str)
}
postMessage(['sendSinmpleIpc', 'custom-css-request'], '*')
+
function makeCID() {
- let chars = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".split("")
- for (let i = 0, len = chars.length; i < len; i++) {
- switch (chars[i]) {
- case "x":
- chars[i] = Math.floor(Math.random() * 16).toString(16)
- break
- case "y":
- chars[i] = (Math.floor(Math.random() * 4) + 8).toString(16)
- break
- }
- }
- return chars.join("")
-}
-function randomStr(l) {
- // 生成する文字列に含める文字セット
- var c = 'abcdefghijklmnopqrstuvwxyz0123456789'
- var cl = c.length
- var r = ''
- for (var i = 0; i < l; i++) {
- r += c[Math.floor(Math.random() * cl)]
- }
- return r
+ return uuid()
}
+
function rgbToHex(color) {
- // HEXに変換したものを代入する変数
- var hex = ''
+ // HEXに変換したものを代入する変数
+ var hex = ''
- // 第1引数がHEXのとき変換処理は必要ないのでそのままreturn
- // IE8の場合はjQueryのcss()関数でHEXを返すので除外
- if (color.match(/^#[a-f\d]{3}$|^#[a-f\d]{6}$/i)) {
- return color
- }
+ // 第1引数がHEXのとき変換処理は必要ないのでそのままreturn
+ // IE8の場合はjQueryのcss()関数でHEXを返すので除外
+ if (color.match(/^#[a-f\d]{3}$|^#[a-f\d]{6}$/i)) {
+ return color
+ }
- // 正規表現
- var regex = color.match(/^rgb\(([0-9.]+),\s*([0-9.]+),\s*([0-9.]+)\)$/)
+ // 正規表現
+ var regex = color.match(/^rgb\(([0-9.]+),\s*([0-9.]+),\s*([0-9.]+)\)$/)
- // 正規表現でマッチしたとき
- if (regex) {
- var rgb = [
- // RGBからHEXへ変換
- parseInt(regex[1]).toString(16),
- parseInt(regex[2]).toString(16),
- parseInt(regex[3]).toString(16)
- ]
+ // 正規表現でマッチしたとき
+ if (regex) {
+ var rgb = [
+ // RGBからHEXへ変換
+ parseInt(regex[1]).toString(16),
+ parseInt(regex[2]).toString(16),
+ parseInt(regex[3]).toString(16)
+ ]
- for (var i = 0; i < rgb.length; ++i) {
- // rgb(1,1,1)のようなときHEXに変換すると1桁になる
- // 1桁のときは前に0を足す
- if (rgb[i].length == 1) {
- rgb[i] = '0' + rgb[i]
- }
- hex += rgb[i]
- }
+ for (var i = 0; i < rgb.length; ++i) {
+ // rgb(1,1,1)のようなときHEXに変換すると1桁になる
+ // 1桁のときは前に0を足す
+ if (rgb[i].length == 1) {
+ rgb[i] = '0' + rgb[i]
+ }
+ hex += rgb[i]
+ }
- return hex
- }
+ return hex
+ }
- console.error(color + ':第1引数はRGB形式で入力')
+ console.error(color + ':第1引数はRGB形式で入力')
}
/*マルチバイト用切り出し*/
-$.isSurrogatePear = function (upper, lower) {
- return 0xd800 <= upper && upper <= 0xdbff && 0xdc00 <= lower && lower <= 0xdfff
+$.isSurrogatePear = function(upper, lower) {
+ return 0xd800 <= upper && upper <= 0xdbff && 0xdc00 <= lower && lower <= 0xdfff
}
-$.mb_strlen = function (str) {
- var splitter = new GraphemeSplitter()
- var arr = splitter.splitGraphemes(str)
- return arr.length
+$.mb_strlen = function(str) {
+ var splitter = new GraphemeSplitter()
+ var arr = splitter.splitGraphemes(str)
+ return arr.length
}
-$.mb_substr = function (str, begin, end) {
- //配列にする
- var splitter = new GraphemeSplitter()
- var arr = splitter.splitGraphemes(str)
- var newarr = []
- for (var i = 0; i < arr.length; i++) {
- if (i >= begin && i <= end) {
- newarr.push(arr[i])
- }
- }
- return newarr.join('')
-}
-//ソートするやつ
+$.mb_substr = function(str, begin, end) {
+ //配列にする
+ var splitter = new GraphemeSplitter()
+ var arr = splitter.splitGraphemes(str)
+ var newarr = []
+ for (var i = 0; i < arr.length; i++) {
+ if (i >= begin && i <= end) {
+ newarr.push(arr[i])
+ }
+ }
+ return newarr.join('')
+ }
+ //ソートするやつ
function object_array_sort(data, key, order, fn) {
- var num_a = -1
- var num_b = 1
- if (order === 'asc') {
- num_a = 1
- num_b = -1
- }
- data = data.sort(function (a, b) {
- var x = a[key]
- var y = b[key]
- if (x > y) return num_a
- if (x < y) return num_b
- return 0
- })
- var arrObj = {}
- for (var i = 0; i < data.length; i++) {
- arrObj[data[i]['family']] = data[i]
- }
- data = []
- for (var key in arrObj) {
- data.push(arrObj[key])
- }
- fn(data)
+ var num_a = -1
+ var num_b = 1
+ if (order === 'asc') {
+ num_a = 1
+ num_b = -1
+ }
+ data = data.sort(function(a, b) {
+ var x = a[key]
+ var y = b[key]
+ if (x > y) return num_a
+ if (x < y) return num_b
+ return 0
+ })
+ var arrObj = {}
+ for (var i = 0; i < data.length; i++) {
+ arrObj[data[i]['family']] = data[i]
+ }
+ data = []
+ for (var key in arrObj) {
+ data.push(arrObj[key])
+ }
+ fn(data)
}
+
function setLog(txt1, txt2, txt3) {
- //url,statuscode,responsetext
- var text = new Date().toUTCString()
- text = text + ',' + txt1 + ',' + txt2 + ',' + escapeCsv(txt3)
- console.error(text)
- postMessage(['log', text], '*')
+ //url,statuscode,responsetext
+ var text = new Date().toUTCString()
+ text = text + ',' + txt1 + ',' + txt2 + ',' + escapeCsv(txt3)
+ console.error(text)
+ postMessage(['log', text], '*')
}
+
function escapeCsv(str) {
- if (!str) {
- return str
- }
- var result
- result = str.toString().replace(/\"/g, '""')
- if (result.indexOf(',') >= 0) {
- result = '"' + result + '"'
- }
- return result
+ if (!str) {
+ return str
+ }
+ var result
+ result = str.toString().replace(/\"/g, '""')
+ if (result.indexOf(',') >= 0) {
+ result = '"' + result + '"'
+ }
+ return result
}
+
function evalAttr(json, attr, lenCk) {
- if (json[attr]) {
- if (lenCk) {
- if (json[attr][0]) {
- return true
- } else {
- return false
- }
- } else {
- return true
- }
- } else {
- return false
- }
+ if (json[attr]) {
+ if (lenCk) {
+ if (json[attr][0]) {
+ return true
+ } else {
+ return false
+ }
+ } else {
+ return true
+ }
+ } else {
+ return false
+ }
}
+
function statusModel(now) {
- if (!now) {
- var now = new Date().toString()
- }
- return {
- id: '',
- created_at: now,
- in_reply_to_id: null,
- in_reply_to_account_id: null,
- sensitive: false,
- spoiler_text: '',
- visibility: 'public',
- language: 'en',
- uri: '',
- url: '',
- replies_count: 0,
- reblogs_count: 0,
- favourites_count: 0,
- favourited: false,
- reblogged: false,
- muted: false,
- bookmarked: false,
- pinned: false,
- content: '
No status here
',
- reblog: null,
- application: {
- name: null,
- website: null
- },
- account: {
- id: '',
- username: '',
- acct: '',
- display_name: '',
- locked: false,
- bot: false,
- created_at: now,
- note: '',
- url: '',
- avatar: '',
- avatar_static: '',
- header: '',
- header_static: '',
- followers_count: 0,
- following_count: 0,
- statuses_count: 0,
- last_status_at: now,
- emojis: [],
- fields: []
- },
- media_attachments: [],
- mentions: [],
- tags: [],
- card: null,
- poll: null
- }
+ if (!now) {
+ var now = new Date().toString()
+ }
+ return {
+ id: '',
+ created_at: now,
+ in_reply_to_id: null,
+ in_reply_to_account_id: null,
+ sensitive: false,
+ spoiler_text: '',
+ visibility: 'public',
+ language: 'en',
+ uri: '',
+ url: '',
+ replies_count: 0,
+ reblogs_count: 0,
+ favourites_count: 0,
+ favourited: false,
+ reblogged: false,
+ muted: false,
+ bookmarked: false,
+ pinned: false,
+ content: 'No status here
',
+ reblog: null,
+ application: {
+ name: null,
+ website: null
+ },
+ account: {
+ id: '',
+ username: '',
+ acct: '',
+ display_name: '',
+ locked: false,
+ bot: false,
+ created_at: now,
+ note: '',
+ url: '',
+ avatar: '',
+ avatar_static: '',
+ header: '',
+ header_static: '',
+ followers_count: 0,
+ following_count: 0,
+ statuses_count: 0,
+ last_status_at: now,
+ emojis: [],
+ fields: []
+ },
+ media_attachments: [],
+ mentions: [],
+ tags: [],
+ card: null,
+ poll: null
+ }
}
+
function webviewFinder() {
- const webview = document.querySelector('webview')
- webview.addEventListener('did-navigate', (e) => {
- const url = webview.getURL()
- if (url.match('https://mobile.twitter.com/login')) {
- postMessage(['twitterLogin', null], '*')
- } else if (url.match('https://mobile.twitter.com/logout')) {
- postMessage(['twitterLogin', true], '*')
- }
- })
+ const webview = document.querySelector('webview')
+ webview.addEventListener('did-navigate', (e) => {
+ const url = webview.getURL()
+ if (url.match('https://mobile.twitter.com/login')) {
+ postMessage(['twitterLogin', null], '*')
+ } else if (url.match('https://mobile.twitter.com/logout')) {
+ postMessage(['twitterLogin', true], '*')
+ }
+ })
}
+
function initWebviewEvent() {
- if (document.querySelector('webview')) { webviewFinder() } else {
- const timerWV = setInterval(function () {
- document.querySelector('webview')
- ? (webviewFinder(), clearInterval(timerWV))
- : console.log('まだロード中')
- }, 500)
- }
+ if (document.querySelector('webview')) { webviewFinder() } else {
+ const timerWV = setInterval(function() {
+ document.querySelector('webview') ?
+ (webviewFinder(), clearInterval(timerWV)) :
+ console.log('まだロード中')
+ }, 500)
+ }
}
\ No newline at end of file
diff --git a/app/js/tl/misskeyparse.js b/app/js/tl/misskeyparse.js
index 73db0207..9dbf0f6b 100644
--- a/app/js/tl/misskeyparse.js
+++ b/app/js/tl/misskeyparse.js
@@ -1,328 +1,328 @@
function escapeHTMLtemp(str) {
- if (!str) {
- return ""
- }
- return str.replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''')
+ if (!str) {
+ return ""
+ }
+ return str.replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
}
-$.strip_tagstemp = function (str, allowed) {
- if (!str) {
- return ""
- }
- allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || [])
- .join('')
- var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi,
- commentsAndPhpTags = /|<\?(?:php)?[\s\S]*?\?>/gi
- return str.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
- return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''
- })
-}
-//オブジェクトパーサー(トゥート)
+$.strip_tagstemp = function(str, allowed) {
+ if (!str) {
+ return ""
+ }
+ allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || [])
+ .join('')
+ var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi,
+ commentsAndPhpTags = /|<\?(?:php)?[\s\S]*?\?>/gi
+ return str.replace(commentsAndPhpTags, '').replace(tags, function($0, $1) {
+ return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''
+ })
+ }
+ //オブジェクトパーサー(トゥート)
function misskeyParse(obj, mix, acct_id, tlid, popup, mutefilter) {
- var templete = ''
- localStorage.setItem("lastunix_" + tlid, date(obj[0].createdAt, 'unix'))
- var actb = localStorage.getItem("action_btns")
- var actb = 're,rt,fav,qt,del,pin,red'
- if (actb) {
- var actb = actb.split(',')
- var disp = {}
- for (var k = 0; k < actb.length; k++) {
- if (k < 4) {
- var tp = "type-a"
- } else {
- var tp = "type-b"
- }
- disp[actb[k]] = tp
- }
- }
- var datetype = localStorage.getItem("datetype")
- var nsfwtype = localStorage.getItem("nsfw")
- var sent = localStorage.getItem("sentence")
- var ltr = localStorage.getItem("letters")
- var gif = localStorage.getItem("gif")
- var imh = localStorage.getItem("img-height")
- //ネイティブ通知
- var native = localStorage.getItem("nativenotf")
- if (!native) {
- native = "yes"
- }
- //クライアント強調
- var empCli = localStorage.getItem("client_emp")
- if (empCli) {
- var empCli = JSON.parse(empCli)
- } else {
- var empCli = []
- }
- //クライアントミュート
- var muteCli = localStorage.getItem("client_mute")
- if (muteCli) {
- var muteCli = JSON.parse(muteCli)
- } else {
- var muteCli = []
- }
- //ユーザー強調
- var useremp = localStorage.getItem("user_emp")
- if (useremp) {
- var useremp = JSON.parse(useremp)
- }
- //ワード強調
- var wordempList = localStorage.getItem("word_emp")
- if (wordempList) {
- var wordempList = JSON.parse(wordempList)
- }
- //ワードミュート
- var wordmuteList = localStorage.getItem("word_mute")
- if (wordmuteList) {
- var wordmuteList = JSON.parse(wordmuteList)
- if (wordmuteList) {
- wordmuteList = wordmuteList.concat(mutefilter)
- }
- } else {
- wordmuteList = mutefilter
- }
- //Ticker
- var tickerck = localStorage.getItem("ticker_ok")
- if (tickerck) {
- var ticker = true
- } else {
- var ticker = false
- }
- if (!sent) {
- var sent = 500
- }
- if (!ltr) {
- var ltr = 500
- }
- if (!nsfwtype || nsfwtype == "yes") {
- var nsfw = "ok"
- } else {
- var nsfw
- }
- var cwtype = localStorage.getItem("cw")
- if (!cwtype || cwtype == "yes") {
- var cw = "ok"
- } else {
- var cw
- }
- if (!datetype) {
- datetype = "absolute"
- }
- if (!gif) {
- var gif = "yes"
- }
- if (!imh) {
- var imh = "200"
- }
- if (!emp) {
- var emp = []
- }
- if (!mute) {
- var mute = []
- }
- if (!useremp) {
- var useremp = []
- }
- if (!wordemp) {
- var wordemp = []
- }
- if (!wordmute) {
- var wordmute = []
- }
- //via通知
- var viashow = localStorage.getItem("viashow")
- if (!viashow) {
- viashow = "via-hide"
- }
- if (viashow == "hide") {
- viashow = "via-hide"
- }
- //認証なしTL
- if (mix == "noauth") {
- var noauth = "hide"
- var antinoauth = ""
- } else {
- var noauth = ""
- var antinoauth = "hide"
- }
- //マウスオーバーのみ
- var mouseover = localStorage.getItem("mouseover")
- if (!mouseover) {
- mouseover = ""
- } else if (mouseover == "yes" || mouseover == "click") {
- mouseover = "hide"
- } else if (mouseover == "no") {
- mouseover = ""
- }
- var local = []
- var times = []
- Object.keys(obj).forEach(function (key) {
- var toot = obj[key]
- var dis_name = toot.user.name
- if (dis_name) {
- dis_name = escapeHTMLtemp(dis_name)
- } else {
- disname = ""
- }
- //絵文字があれば
- if (toot.user.emojis) {
- Object.keys(toot.user.emojis).forEach(function (key5) {
- var emoji = toot.user.emojis[key5]
- var shortcode = emoji.name
- var emoji_url = ''
- var regExp = new RegExp(":" + shortcode + ":", "g")
- dis_name = dis_name.replace(regExp, emoji_url)
- })
- }
- if (mix == "notf") {
- if (gif == "yes") {
- noticeavatar = toot.user.avatarUrl
- } else {
- noticeavatar = toot.user.avatarUrl
- }
- noticeavatar = '' +
- ''
- if (toot.type == "reply") {
- var what = lang.lang_parse_mentioned
- var icon = ''
- noticeavatar = ""
- } else if (toot.type == "renote") {
- var what = lang.lang_misskeyparse_renoted
- var icon = ''
- } else if (toot.type == "quote") {
- var what = lang.lang_misskeyparse_quoted
- var icon = ''
- } else if (toot.type == "reaction") {
- var what = lang.lang_misskeyparse_reacted
- var reactions = {
- "like": "👍",
- "love": "💓",
- "laugh": "😁",
- "hmm": "🤔",
- "surprise": "😮",
- "congrats": "🎉",
- "amgry": "💢",
- "confused": "😥",
- "rip": "😇"
- }
- var icon = reactions[toot.reaction]
- var emojisData = JSON.parse(localStorage.getItem("emoji_" + acct_id))
- if (!icon) {
- if (emojisData) {
- var num = emojisData.length
- var ehtml = ""
- for (i = 0; i < num; i++) {
- var emoji = emojisData[i]
- if (":" + emoji.shortcode + ":" == toot.reaction) {
- if (emoji) {
- icon = ''
- }
- }
- }
- }
- }
- } else {
- var icon = 'info'
- }
- var noticetext = '' + date(toot.createdAt,
- datetype) +
- '' + icon + '' + dis_name +
- "(@" + toot.user.username +
- ")"
- var notice = noticetext
- var memory = localStorage.getItem("notice-mem")
- if (popup >= 0 && obj.length < 5 && noticetext != memory) {
- if (localStorage.getItem("hasNotfC_" + acct_id) != "true") {
- if (toot.type == "reply") {
- var replyct = localStorage.getItem("notf-reply_" + acct_id)
- $(".notf-reply_" + acct_id).text(replyct * 1 - (-1))
- localStorage.setItem("notf-reply_" + acct_id, replyct * 1 - (-1))
- $(".notf-reply_" + acct_id).removeClass("hide")
- } else if (toot.type == "renote" || toot.type == "quote") {
- var btct = localStorage.getItem("notf-bt_" + acct_id)
- $(".notf-bt_" + acct_id).text(btct * 1 + 1)
- localStorage.setItem("notf-bt_" + acct_id, btct * 1 - (-1))
- $(".notf-bt_" + acct_id).removeClass("hide")
- } else if (toot.type == "reaction") {
- var favct = localStorage.getItem("notf-fav_" + acct_id)
- $(".notf-fav_" + acct_id).text(favct * 1 - (-1))
- localStorage.setItem("notf-fav_" + acct_id, favct * 1 - (-1))
- $(".notf-fav_" + acct_id).removeClass("hide")
- }
- }
- var domain = localStorage.getItem("domain_" + acct_id)
- if (popup > 0) {
- M.toast({ html: "[" + domain + "]" + escapeHTMLtemp(toot.user.name) + what, displayLength: popup * 1000 })
- }
- if (native == "yes") {
- var os = localStorage.getItem("platform")
- var options = {
- body: toot.user.name + "(" + toot.user.username + ")" + what + "\n\n" + $.strip_tagstemp(toot.note.text),
- icon: toot.user.avatarUrl
- }
- var n = new Notification('TheDesk:' + domain, options)
- }
- if (localStorage.getItem("hasNotfC_" + acct_id) != "true") {
- $(".notf-icon_" + acct_id).addClass("red-text")
- }
- localStorage.setItem("notice-mem", noticetext)
- noticetext = ""
- }
- var if_notf = 'data-notfIndv="' + acct_id + "_" + toot.id + '"'
- var toot = toot.note
- var dis_name = escapeHTML(toot.user.name)
- } else {
- var if_notf = ""
- if (toot.renote) {
- var rebtxt = lang.lang_parse_btedsimple
- var rticon = "fa-retweet light-blue-text"
- var notice = '' + dis_name + "(@" + toot.user.username +
- ")
"
- var boostback = "shared"
- var uniqueid = toot.id
- if (!toot.text) {
- var toot = toot.renote
- }
- var dis_name = escapeHTML(toot.user.name)
- var uniqueid = toot.id
- var actemojick = false
- } else {
- var uniqueid = toot.id
- var notice = ""
- var boostback = ""
- //ユーザー強調
- if (toot.user.host) {
- var fullname = toot.user.username + "@" + toot.user.host
- } else {
- var domain = localStorage.getItem("domain_" + acct_id)
- var fullname = toot.user.username + "@" + domain
- }
- if (useremp) {
- Object.keys(useremp).forEach(function (key10) {
- var user = useremp[key10]
- if (user == fullname) {
- boostback = "emphasized"
- }
- })
- }
- }
- }
- var id = toot.id
- if (mix == "home") {
- var home = ""
- var divider = ''
- } else {
- var home = ""
- var divider = ''
- }
+ var templete = ''
+ localStorage.setItem("lastunix_" + tlid, date(obj[0].createdAt, 'unix'))
+ var actb = localStorage.getItem("action_btns")
+ var actb = 're,rt,fav,qt,del,pin,red'
+ if (actb) {
+ var actb = actb.split(',')
+ var disp = {}
+ for (var k = 0; k < actb.length; k++) {
+ if (k < 4) {
+ var tp = "type-a"
+ } else {
+ var tp = "type-b"
+ }
+ disp[actb[k]] = tp
+ }
+ }
+ var datetype = localStorage.getItem("datetype")
+ var nsfwtype = localStorage.getItem("nsfw")
+ var sent = localStorage.getItem("sentence")
+ var ltr = localStorage.getItem("letters")
+ var gif = localStorage.getItem("gif")
+ var imh = localStorage.getItem("img-height")
+ //ネイティブ通知
+ var native = localStorage.getItem("nativenotf")
+ if (!native) {
+ native = "yes"
+ }
+ //クライアント強調
+ var empCli = localStorage.getItem("client_emp")
+ if (empCli) {
+ var empCli = JSON.parse(empCli)
+ } else {
+ var empCli = []
+ }
+ //クライアントミュート
+ var muteCli = localStorage.getItem("client_mute")
+ if (muteCli) {
+ var muteCli = JSON.parse(muteCli)
+ } else {
+ var muteCli = []
+ }
+ //ユーザー強調
+ var useremp = localStorage.getItem("user_emp")
+ if (useremp) {
+ var useremp = JSON.parse(useremp)
+ }
+ //ワード強調
+ var wordempList = localStorage.getItem("word_emp")
+ if (wordempList) {
+ var wordempList = JSON.parse(wordempList)
+ }
+ //ワードミュート
+ var wordmuteList = localStorage.getItem("word_mute")
+ if (wordmuteList) {
+ var wordmuteList = JSON.parse(wordmuteList)
+ if (wordmuteList) {
+ wordmuteList = wordmuteList.concat(mutefilter)
+ }
+ } else {
+ wordmuteList = mutefilter
+ }
+ //Ticker
+ var tickerck = localStorage.getItem("ticker_ok")
+ if (tickerck) {
+ var ticker = true
+ } else {
+ var ticker = false
+ }
+ if (!sent) {
+ var sent = 500
+ }
+ if (!ltr) {
+ var ltr = 500
+ }
+ if (!nsfwtype || nsfwtype == "yes") {
+ var nsfw = "ok"
+ } else {
+ var nsfw
+ }
+ var cwtype = localStorage.getItem("cw")
+ if (!cwtype || cwtype == "yes") {
+ var cw = "ok"
+ } else {
+ var cw
+ }
+ if (!datetype) {
+ datetype = "absolute"
+ }
+ if (!gif) {
+ var gif = "yes"
+ }
+ if (!imh) {
+ var imh = "200"
+ }
+ if (!emp) {
+ var emp = []
+ }
+ if (!mute) {
+ var mute = []
+ }
+ if (!useremp) {
+ var useremp = []
+ }
+ if (!wordemp) {
+ var wordemp = []
+ }
+ if (!wordmute) {
+ var wordmute = []
+ }
+ //via通知
+ var viashow = localStorage.getItem("viashow")
+ if (!viashow) {
+ viashow = "via-hide"
+ }
+ if (viashow == "hide") {
+ viashow = "via-hide"
+ }
+ //認証なしTL
+ if (mix == "noauth") {
+ var noauth = "hide"
+ var antinoauth = ""
+ } else {
+ var noauth = ""
+ var antinoauth = "hide"
+ }
+ //マウスオーバーのみ
+ var mouseover = localStorage.getItem("mouseover")
+ if (!mouseover) {
+ mouseover = ""
+ } else if (mouseover == "yes" || mouseover == "click") {
+ mouseover = "hide"
+ } else if (mouseover == "no") {
+ mouseover = ""
+ }
+ var local = []
+ var times = []
+ Object.keys(obj).forEach(function(key) {
+ var toot = obj[key]
+ var dis_name = toot.user.name
+ if (dis_name) {
+ dis_name = escapeHTMLtemp(dis_name)
+ } else {
+ disname = ""
+ }
+ //絵文字があれば
+ if (toot.user.emojis) {
+ Object.keys(toot.user.emojis).forEach(function(key5) {
+ var emoji = toot.user.emojis[key5]
+ var shortcode = emoji.name
+ var emoji_url = ''
+ var regExp = new RegExp(":" + shortcode + ":", "g")
+ dis_name = dis_name.replace(regExp, emoji_url)
+ })
+ }
+ if (mix == "notf") {
+ if (gif == "yes") {
+ noticeavatar = toot.user.avatarUrl
+ } else {
+ noticeavatar = toot.user.avatarUrl
+ }
+ noticeavatar = '' +
+ ''
+ if (toot.type == "reply") {
+ var what = lang.lang_parse_mentioned
+ var icon = ''
+ noticeavatar = ""
+ } else if (toot.type == "renote") {
+ var what = lang.lang_misskeyparse_renoted
+ var icon = ''
+ } else if (toot.type == "quote") {
+ var what = lang.lang_misskeyparse_quoted
+ var icon = ''
+ } else if (toot.type == "reaction") {
+ var what = lang.lang_misskeyparse_reacted
+ var reactions = {
+ "like": "👍",
+ "love": "💓",
+ "laugh": "😁",
+ "hmm": "🤔",
+ "surprise": "😮",
+ "congrats": "🎉",
+ "amgry": "💢",
+ "confused": "😥",
+ "rip": "😇"
+ }
+ var icon = reactions[toot.reaction]
+ var emojisData = JSON.parse(localStorage.getItem("emoji_" + acct_id))
+ if (!icon) {
+ if (emojisData) {
+ var num = emojisData.length
+ var ehtml = ""
+ for (i = 0; i < num; i++) {
+ var emoji = emojisData[i]
+ if (":" + emoji.shortcode + ":" == toot.reaction) {
+ if (emoji) {
+ icon = ''
+ }
+ }
+ }
+ }
+ }
+ } else {
+ var icon = 'info'
+ }
+ var noticetext = '' + date(toot.createdAt,
+ datetype) +
+ '' + icon + '' + dis_name +
+ "(@" + toot.user.username +
+ ")"
+ var notice = noticetext
+ var memory = localStorage.getItem("notice-mem")
+ if (popup >= 0 && obj.length < 5 && noticetext != memory) {
+ if (localStorage.getItem("hasNotfC_" + acct_id) != "true") {
+ if (toot.type == "reply") {
+ var replyct = localStorage.getItem("notf-reply_" + acct_id)
+ $(".notf-reply_" + acct_id).text(replyct * 1 - (-1))
+ localStorage.setItem("notf-reply_" + acct_id, replyct * 1 - (-1))
+ $(".notf-reply_" + acct_id).removeClass("hide")
+ } else if (toot.type == "renote" || toot.type == "quote") {
+ var btct = localStorage.getItem("notf-bt_" + acct_id)
+ $(".notf-bt_" + acct_id).text(btct * 1 + 1)
+ localStorage.setItem("notf-bt_" + acct_id, btct * 1 - (-1))
+ $(".notf-bt_" + acct_id).removeClass("hide")
+ } else if (toot.type == "reaction") {
+ var favct = localStorage.getItem("notf-fav_" + acct_id)
+ $(".notf-fav_" + acct_id).text(favct * 1 - (-1))
+ localStorage.setItem("notf-fav_" + acct_id, favct * 1 - (-1))
+ $(".notf-fav_" + acct_id).removeClass("hide")
+ }
+ }
+ var domain = localStorage.getItem("domain_" + acct_id)
+ if (popup > 0) {
+ M.toast({ html: "[" + domain + "]" + escapeHTMLtemp(toot.user.name) + what, displayLength: popup * 1000 })
+ }
+ if (native == "yes") {
+ var os = localStorage.getItem("platform")
+ var options = {
+ body: toot.user.name + "(" + toot.user.username + ")" + what + "\n\n" + $.strip_tagstemp(toot.note.text),
+ icon: toot.user.avatarUrl
+ }
+ var n = new Notification('TheDesk:' + domain, options)
+ }
+ if (localStorage.getItem("hasNotfC_" + acct_id) != "true") {
+ $(".notf-icon_" + acct_id).addClass("red-text")
+ }
+ localStorage.setItem("notice-mem", noticetext)
+ noticetext = ""
+ }
+ var if_notf = 'data-notfIndv="' + acct_id + "_" + toot.id + '"'
+ var toot = toot.note
+ var dis_name = escapeHTML(toot.user.name)
+ } else {
+ var if_notf = ""
+ if (toot.renote) {
+ var rebtxt = lang.lang_parse_btedsimple
+ var rticon = "fa-retweet light-blue-text"
+ var notice = '' + dis_name + "(@" + toot.user.username +
+ ")
"
+ var boostback = "shared"
+ var uniqueid = toot.id
+ if (!toot.text) {
+ var toot = toot.renote
+ }
+ var dis_name = escapeHTML(toot.user.name)
+ var uniqueid = toot.id
+ var actemojick = false
+ } else {
+ var uniqueid = toot.id
+ var notice = ""
+ var boostback = ""
+ //ユーザー強調
+ if (toot.user.host) {
+ var fullname = toot.user.username + "@" + toot.user.host
+ } else {
+ var domain = localStorage.getItem("domain_" + acct_id)
+ var fullname = toot.user.username + "@" + domain
+ }
+ if (useremp) {
+ Object.keys(useremp).forEach(function(key10) {
+ var user = useremp[key10]
+ if (user == fullname) {
+ boostback = "emphasized"
+ }
+ })
+ }
+ }
+ }
+ var id = toot.id
+ if (mix == "home") {
+ var home = ""
+ var divider = ''
+ } else {
+ var home = ""
+ var divider = ''
+ }
/*
if (toot.account.locked) {
var locked = ' ';
@@ -330,242 +330,242 @@ function misskeyParse(obj, mix, acct_id, tlid, popup, mutefilter) {
var locked = "";
}
*/
- if (!toot.app) {
- if (toot.viaMobile) {
- var via = 'Mobile'
- } else {
- var via = ''
- viashow = "via-hide"
- }
- } else {
- var via = escapeHTML(toot.app.name)
- if (!toot.app.name) {
- viashow = "via-hide"
- }
- //強調チェック
- Object.keys(empCli).forEach(function (key6) {
- var empCliList = empCli[key6]
- if (empCliList == via) {
- boostback = "emphasized"
- }
- })
- //ミュートチェック
- Object.keys(muteCli).forEach(function (key7) {
- var muteCliList = muteCli[key7]
- if (muteCliList == via) {
- boostback = "hide"
- }
- })
- }
- if ((toot.cw || toot.cw == "") && cw) {
- var content = escapeHTML(toot.text)
- var spoil = escapeHTMLtemp(toot.cw)
- var spoiler = "cw cw_hide"
- var api_spoil = "gray"
- var spoiler_show = '' + lang.lang_parse_cwshow + '
'
- } else {
- var ct1 = nl2br(toot.text).split('
').length - 2
- var ct2 = nl2br(toot.text).split('
').length - 2
- if (ct1 > ct2) { var ct = ct1 } else { var ct = ct2 }
- if ((sent < ct && $.mb_strlen($.strip_tagstemp(toot.text)) > 5) || ($.strip_tagstemp(toot.text).length > ltr && $.mb_strlen($.strip_tagstemp(toot.text)) > 5)) {
- var content = '' + lang.lang_parse_fulltext + '
' + escapeHTMLtemp(toot.text)
- var spoil = '' + $.mb_substr($.strip_tagstemp(
- toot.text), 0, 100) +
- '' + lang.lang_parse_autofold + ''
- var spoiler = "cw cw_hide"
- var spoiler_show = '' + lang.lang_parse_more + '
'
- } else {
- var content = escapeHTMLtemp(toot.text)
- if (toot.cw) {
- var spoil = escapeHTMLtemp(toot.cw)
- } else {
- var spoil = ""
- }
+ if (!toot.app) {
+ if (toot.viaMobile) {
+ var via = 'Mobile'
+ } else {
+ var via = ''
+ viashow = "via-hide"
+ }
+ } else {
+ var via = escapeHTML(toot.app.name)
+ if (!toot.app.name) {
+ viashow = "via-hide"
+ }
+ //強調チェック
+ Object.keys(empCli).forEach(function(key6) {
+ var empCliList = empCli[key6]
+ if (empCliList == via) {
+ boostback = "emphasized"
+ }
+ })
+ //ミュートチェック
+ Object.keys(muteCli).forEach(function(key7) {
+ var muteCliList = muteCli[key7]
+ if (muteCliList == via) {
+ boostback = "hide"
+ }
+ })
+ }
+ if ((toot.cw || toot.cw == "") && cw) {
+ var content = escapeHTML(toot.text)
+ var spoil = escapeHTMLtemp(toot.cw)
+ var spoiler = "cw cw_hide"
+ var api_spoil = "gray"
+ var spoiler_show = '' + lang.lang_parse_cwshow + '
'
+ } else {
+ var ct1 = nl2br(toot.text).split('
').length - 2
+ var ct2 = nl2br(toot.text).split('
').length - 2
+ if (ct1 > ct2) { var ct = ct1 } else { var ct = ct2 }
+ if ((sent < ct && $.mb_strlen($.strip_tagstemp(toot.text)) > 5) || ($.strip_tagstemp(toot.text).length > ltr && $.mb_strlen($.strip_tagstemp(toot.text)) > 5)) {
+ var content = '' + lang.lang_parse_fulltext + '
' + escapeHTMLtemp(toot.text)
+ var spoil = '' + $.mb_substr($.strip_tagstemp(
+ toot.text), 0, 100) +
+ '' + lang.lang_parse_autofold + ''
+ var spoiler = "cw cw_hide"
+ var spoiler_show = '' + lang.lang_parse_more + '
'
+ } else {
+ var content = escapeHTMLtemp(toot.text)
+ if (toot.cw) {
+ var spoil = escapeHTMLtemp(toot.cw)
+ } else {
+ var spoil = ""
+ }
- var spoiler = ""
- var spoiler_show = ""
- }
- }
- var analyze = ''
- var urls = $.strip_tagstemp(content).replace(/\n/g, " ").match(
- /https?:\/\/([-a-zA-Z0-9@.]+)\/?(?!.*((media|tags)|mentions)).*([-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)?/
- )
- if (urls) {
- var analyze = '' + lang.lang_parse_url + '
'
- } else {
- var analyze = ''
- }
- var viewer = "
"
- var hasmedia = ""
- var youtube = ""
- if (toot.emojis) {
- var emojick = toot.emojis[0]
- } else {
- var emojick = false
- }
- //デフォ絵文字
- if (content) {
- //MFM
- content = content.replace(/^"([^"]+)"$/gmi, '$1
')
- content = content.replace(/`(.+)`/gi, '$1
')
- content = content.replace(/(http(s)?:\/\/[\x21-\x7e]+)/gi, '$1')
- content = content.replace(/\(\(\((.+)\)\)\)/gi, '$1')
- content = content.replace(/<motion>(.+)<\/motion>/gi, '$1')
- content = content.replace(/\*\*\*([^*]+)\*\*\*/gi, '$1')
- content = content.replace(/\*\*([^*]+)\*\*/gi, '$1')
- content = content.replace(/^(.+)\s(検索|search)$/gmi, 'search
')
- content = content.replace(/\[(.+)\]\($1')
- content = content.replace(/<center>/gi, '')
- content = content.replace(/<\/center>/gi, '
')
- content = content.replace(/<flip>(.+)<\/flip>/gi, '$1')
- content = content.replace(/<small>(.+)<\/small>/gi, '$1')
- content = content.replace(/<i>(.+)<\/i>/gi, '$1')
- content = content.replace(/<spin>(.+)<\/spin>/gi, '$1')
- content = content.replace(/\*\*(.+)\*\*/gi, '$1')
- content = content.replace(/<jump>(.+)<\/jump>/gi, '$1')
- content = twemoji.parse(content)
- } else {
- content = ""
- }
- //絵文字があれば
- if (emojick) {
- Object.keys(toot.emojis).forEach(function (key5) {
- var emoji = toot.emojis[key5]
- var shortcode = emoji.name
- var emoji_url = ''
- var regExp = new RegExp(":" + shortcode + ":", "g")
- content = content.replace(regExp, emoji_url)
- spoil = spoil.replace(regExp, emoji_url)
- })
- }
- if (dis_name) {
- dis_name = twemoji.parse(dis_name)
- } else {
- dis_name = ""
- }
- if (spoil) {
- spoil = twemoji.parse(spoil)
- }
- if (noticetext) {
- noticetext = twemoji.parse(noticetext)
- }
- if (notice) {
- notice = twemoji.parse(notice)
- }
+ var spoiler = ""
+ var spoiler_show = ""
+ }
+ }
+ var analyze = ''
+ var urls = $.strip_tagstemp(content).replace(/\n/g, " ").match(
+ /https?:\/\/([-a-zA-Z0-9@.]+)\/?(?!.*((media|tags)|mentions)).*([-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)?/
+ )
+ if (urls) {
+ var analyze = '' + lang.lang_parse_url + '
'
+ } else {
+ var analyze = ''
+ }
+ var viewer = "
"
+ var hasmedia = ""
+ var youtube = ""
+ if (toot.emojis) {
+ var emojick = toot.emojis[0]
+ } else {
+ var emojick = false
+ }
+ //デフォ絵文字
+ if (content) {
+ //MFM
+ content = content.replace(/^"([^"]+)"$/gmi, '$1
')
+ content = content.replace(/`(.+)`/gi, '$1
')
+ content = content.replace(/(http(s)?:\/\/[\x21-\x7e]+)/gi, '$1')
+ content = content.replace(/\(\(\((.+)\)\)\)/gi, '$1')
+ content = content.replace(/<motion>(.+)<\/motion>/gi, '$1')
+ content = content.replace(/\*\*\*([^*]+)\*\*\*/gi, '$1')
+ content = content.replace(/\*\*([^*]+)\*\*/gi, '$1')
+ content = content.replace(/^(.+)\s(検索|search)$/gmi, 'search
')
+ content = content.replace(/\[(.+)\]\($1')
+ content = content.replace(/<center>/gi, '')
+ content = content.replace(/<\/center>/gi, '
')
+ content = content.replace(/<flip>(.+)<\/flip>/gi, '$1')
+ content = content.replace(/<small>(.+)<\/small>/gi, '$1')
+ content = content.replace(/<i>(.+)<\/i>/gi, '$1')
+ content = content.replace(/<spin>(.+)<\/spin>/gi, '$1')
+ content = content.replace(/\*\*(.+)\*\*/gi, '$1')
+ content = content.replace(/<jump>(.+)<\/jump>/gi, '$1')
+ content = twemoji.parse(content)
+ } else {
+ content = ""
+ }
+ //絵文字があれば
+ if (emojick) {
+ Object.keys(toot.emojis).forEach(function(key5) {
+ var emoji = toot.emojis[key5]
+ var shortcode = emoji.name
+ var emoji_url = ''
+ var regExp = new RegExp(":" + shortcode + ":", "g")
+ content = content.replace(regExp, emoji_url)
+ spoil = spoil.replace(regExp, emoji_url)
+ })
+ }
+ if (dis_name) {
+ dis_name = twemoji.parse(dis_name)
+ } else {
+ dis_name = ""
+ }
+ if (spoil) {
+ spoil = twemoji.parse(spoil)
+ }
+ if (noticetext) {
+ noticetext = twemoji.parse(noticetext)
+ }
+ if (notice) {
+ notice = twemoji.parse(notice)
+ }
- if (toot.files) {
- var mediack = toot.files[0]
- var useparam = "files"
- } else {
- if (toot.media) {
- var mediack = toot.media[0]
- var useparam = "media"
- } else {
- var mediack = false
- }
- }
- //メディアがあれば
- var media_ids = ""
- if (mediack) {
- hasmedia = "hasmedia"
- var cwdt = 100 / toot[useparam].length
- Object.keys(toot[useparam]).forEach(function (key2) {
- var media = toot[useparam][key2]
- var purl = media.url
- media_ids = media_ids + media.id + ","
- var url = media.url
- if (media.isSensitive && nsfw) {
- var sense = "sensitive"
- } else {
- var sense = ""
- }
- if (media.type.indexOf("video") !== -1) {
- viewer = viewer + ''
- } else if (media.type.indexOf("audio") !== -1) {
- viewer = viewer + ''
- } else {
- viewer = viewer + ''
- }
+ if (toot.files) {
+ var mediack = toot.files[0]
+ var useparam = "files"
+ } else {
+ if (toot.media) {
+ var mediack = toot.media[0]
+ var useparam = "media"
+ } else {
+ var mediack = false
+ }
+ }
+ //メディアがあれば
+ var media_ids = ""
+ if (mediack) {
+ hasmedia = "hasmedia"
+ var cwdt = 100 / toot[useparam].length
+ Object.keys(toot[useparam]).forEach(function(key2) {
+ var media = toot[useparam][key2]
+ var purl = media.url
+ media_ids = media_ids + media.id + ","
+ var url = media.url
+ if (media.isSensitive && nsfw) {
+ var sense = "sensitive"
+ } else {
+ var sense = ""
+ }
+ if (media.type.indexOf("video") !== -1) {
+ viewer = viewer + ''
+ } else if (media.type.indexOf("audio") !== -1) {
+ viewer = viewer + '