Add: plugin system[WIP]

This commit is contained in:
cutls 2020-11-28 05:57:11 +09:00
parent 8873af4597
commit 7169f1147b
15 changed files with 1407 additions and 96 deletions

1
.gitignore vendored
View File

@ -25,3 +25,4 @@ app/git
*.code-workspace *.code-workspace
releasenote.md releasenote.md
app/yarn-error.log app/yarn-error.log
app/js/platform/aiscript.js

10
app/aiscript.js Normal file
View File

@ -0,0 +1,10 @@
const { AiScript, parse, values, utils } = require('@syuilo/aiscript')
global.asValue = values
global.AiScript = AiScript
global.asParse = parse
global.asCommon = {
'TheDesk:console': values.FN_NATIVE((z) => {
console.log(z[0].value)
})
}
global.asUtil = utils

View File

@ -1,3 +1,9 @@
window.onload = function () {
console.log('loaded')
initPostbox()
connection()
initPlugin(plugins)
}
$.strip_tags = function (str, allowed) { $.strip_tags = function (str, allowed) {
if (!str) { if (!str) {
return '' return ''

152
app/js/platform/plugin.js Normal file
View File

@ -0,0 +1,152 @@
var plugins = getPlugin()
function getPlugin() {
const json = localStorage.getItem('plugins')
let ret = {
buttonOnPostbox: [],
buttonOnToot: []
}
//if(!json) return ret
//const plugins = JSON.parse(json)
const plugins = [
{
id: randomStr(20),
content: `### {
name: "マイ・ファースト・プラグイン"
version: 1
event: "buttonOnPostbox"
author: "Cutls P"
}
`
}
]
for (let plugin of plugins) {
const meta = getMeta(plugin.content)
if (!meta) continue
const type = meta.event
ret[type] ? ret[type].push(plugin) : ret[type] = [plugin]
}
return ret
}
function initPlugin() {
asCommon['TheDesk:dialog'] = asValue.FN_NATIVE((z) => {
Swal.fire({
title: z[0].value,
icon: z[2] ? z[2].value : 'info',
text: z[1] ? z[1].value : ''
})
})
asCommon['TheDesk:confirm'] = asValue.FN_NATIVE(async (z) => {
const alert = await Swal.fire({
title: z[0].value,
text: z[1].value,
icon: z[2] ? z[2].value : 'info',
showCancelButton: true
})
return asUtil.jsToVal(!!(alert.value && alert.value === true))
})
asCommon['TheDesk:css'] = asValue.FN_NATIVE((z) => {
$(escapeHTML(z[0].value)).css(escapeHTML(z[1].value), escapeHTML(z[2].value))
})
asCommon['TheDesk:api'] = asValue.FN_NATIVE(async (z) => {
try {
if (!getMeta(exe).apiGet && z[0].value == "GET") return asUtil.jsToVal(false)
if (!getMeta(exe).apiPost && (z[0].value == "POST" || z[0].value == "DELETE" || z[0].value == "PUT")) return asUtil.jsToVal(false)
const domain = localStorage.getItem(`domain_${z[3].value}`)
const at = localStorage.getItem(`acct_${z[3].value}_at`)
const start = `https://${domain}/api/${z[1].value}`
const q = {
method: z[0].value,
headers: {
'content-type': 'application/json',
Authorization:
`Bearer ${at}`
}
}
if (z[2]) q.body = z[2].value
const promise = await fetch(start, q)
const json = await promise.json()
return asUtil.jsToVal(json)
} catch (e) {
return asUtil.jsToVal(e)
}
})
const { buttonOnPostbox, init } = plugins
for (let target of buttonOnPostbox) {
const meta = getMeta(target.content)
$('#dropdown2').append(`<li><a onclick="execPlugin('${target.id}','buttonOnPostbox', null);">${escapeHTML(meta.name)}</a></li>`)
}
for (let target of init) {
const as = new AiScript(asCommon)
const meta = getMeta(target.content)
M.toast({ html: `${escapeHTML(meta.name)}を実行しました`, displayLength: 1000 })
if (target) as.exec(asParse(target.content))
}
}
function getMeta(plugin) {
try {
return AiScript.collectMetadata(asParse(plugin)).get(null)
} catch (e) {
console.error(e)
return null
}
}
async function execPlugin(id, source, args) {
const coh = plugins[source]
let exe = null
for (let plugin of coh) {
if (plugin.id == id) {
exe = plugin.content
break
}
}
const common = _.cloneDeep(asCommon)
if (source == 'buttonOnToot') {
common.DATA = args
const domain = localStorage.getItem(`domain_${args.acct_id}`)
const at = localStorage.getItem(`acct_${args.acct_id}_at`)
const start = `https://${domain}/api/v1/statuses/${args.id}`
const promise = await fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
Authorization:
`Bearer ${at}`
}
})
const json = await promise.json()
common.TOOT = asUtil.jsToVal(json)
common['TheDesk:changeText'] = asValue.FN_NATIVE((z) => {
if (getMeta(exe).dangerHtml) $(`[unique-id=${args.id}] .cvo`).html(z[0].value)
})
} else if (source == 'buttonOnPostbox') {
const postDt = post(null, false, true)
common.POST = asUtil.jsToVal(postDt)
common.ACCT_ID = asUtil.jsToVal(postDt.TheDeskAcctId)
common['TheDesk:postText'] = asValue.FN_NATIVE((z) => {
$('#textarea').val(z[0].value)
})
common['TheDesk:postCW'] = asValue.FN_NATIVE((z) => {
if (z[1]) $('#cw-text').val(z[1].value)
cw(z[0] ? z[0].value : false)
})
common['TheDesk:postNSFW'] = asValue.FN_NATIVE((z) => {
nsfw(z[0] ? z[0].value : false)
})
common['TheDesk:postVis'] = asValue.FN_NATIVE((z) => {
vis(z[0].value)
})
common['TheDesk:postClearbox'] = asValue.FN_NATIVE(() => {
clear()
})
common['TheDesk:postExec'] = asValue.FN_NATIVE(() => {
if (getMeta(exe).apiPost) post()
})
}
common['TheDesk:console'] = asValue.FN_NATIVE((z) => {
console.log(z[0].value)
})
const as = new AiScript(common)
if (exe) as.exec(asParse(exe))
}

View File

@ -1,14 +1,14 @@
/*保護系*/ /*保護系*/
//画像保護 //画像保護
function nsfw() { function nsfw(force) {
if ($('#nsfw').hasClass('nsfw-avail')) { if (force || !$('#nsfw').hasClass('nsfw-avail')) {
$('#nsfw').removeClass('yellow-text')
$('#nsfw').html('visibility_off')
$('#nsfw').removeClass('nsfw-avail')
} else {
$('#nsfw').addClass('yellow-text') $('#nsfw').addClass('yellow-text')
$('#nsfw').html('visibility') $('#nsfw').html('visibility')
$('#nsfw').addClass('nsfw-avail') $('#nsfw').addClass('nsfw-avail')
} else {
$('#nsfw').removeClass('yellow-text')
$('#nsfw').html('visibility_off')
$('#nsfw').removeClass('nsfw-avail')
} }
} }
@ -80,12 +80,7 @@ loadVis()
//コンテントワーニング //コンテントワーニング
function cw(force) { function cw(force) {
if ($('#cw').hasClass('cw-avail') || !force) { if (force || !$('#cw').hasClass('cw-avail')) {
$('#cw-text').val()
$('#cw-text').hide()
$('#cw').removeClass('yellow-text')
$('#cw').removeClass('cw-avail')
} else {
$('#cw-text').show() $('#cw-text').show()
$('#cw').addClass('yellow-text') $('#cw').addClass('yellow-text')
$('#cw').addClass('cw-avail') $('#cw').addClass('cw-avail')
@ -93,6 +88,11 @@ function cw(force) {
if (cwt) { if (cwt) {
$('#cw-text').val(cwt) $('#cw-text').val(cwt)
} }
} else {
$('#cw-text').val()
$('#cw-text').hide()
$('#cw').removeClass('yellow-text')
$('#cw').removeClass('cw-avail')
} }
} }
//TLでコンテントワーニングを表示トグル //TLでコンテントワーニングを表示トグル

View File

@ -437,7 +437,6 @@ function draftToPost(json, acct_id, id) {
$('#post-acct-sel').val(acct_id) $('#post-acct-sel').val(acct_id)
$('select').formSelect() $('select').formSelect()
mdCheck() mdCheck()
var medias = $('[toot-id=' + id + ']').attr('data-medias')
mediack = null mediack = null
if(json.media_attachments) mediack = json.media_attachments[0] if(json.media_attachments) mediack = json.media_attachments[0]
//メディアがあれば //メディアがあれば
@ -684,9 +683,9 @@ function staEx(mode) {
}) })
return return
} }
function toggleAction(id) { function toggleAction(elm) {
const elm = document.getElementById(id) console.log(elm)
const instance = M.Dropdown.init(elm); const instance = M.Dropdown.init(elm)
console.log(instance.isOpen) console.log(instance.isOpen)
instance.open() instance.open()
} }

View File

@ -334,9 +334,14 @@ function cardCheck(tlid) {
} }
} }
function mov(id, tlid, type) { function mov(id, tlid, type, rand, target) {
const dropdownTrigger = `dropdown_${tlid}_${id}` const dropdownTrigger = `dropdown_${rand}`
const elm = document.getElementById(dropdownTrigger) let elm = document.querySelector(`#timeline_${tlid} #${dropdownTrigger}`)
if(tlid == 'notf') {
const timeline = $(target).parents('.notf-indv-box').attr('id')
elm = document.querySelector(`#${timeline} #${dropdownTrigger}`)
console.log(`#${timeline} #${dropdownTrigger}`)
}
const instance = M.Dropdown.getInstance(elm) const instance = M.Dropdown.getInstance(elm)
if(instance) { if(instance) {
if(instance.isOpen) return false if(instance.isOpen) return false

View File

@ -765,9 +765,10 @@ function misskeyParse(obj, mix, acct_id, tlid, popup, mutefilter) {
} else { } else {
var actemojick = false var actemojick = false
} }
var rand = randomStr(8)
templete = templete + '<div id="pub_' + toot.id + '" class="cvo ' + templete = templete + '<div id="pub_' + toot.id + '" class="cvo ' +
boostback + ' ' + fav_app + ' ' + rt_app + ' ' + hasmedia + '" toot-id="' + id + '" unique-id="' + uniqueid + '" data-medias="' + media_ids + ' " unixtime="' + date(obj[ boostback + ' ' + fav_app + ' ' + rt_app + ' ' + hasmedia + '" toot-id="' + id + '" unique-id="' + uniqueid + '" data-medias="' + media_ids + ' " unixtime="' + date(obj[
key].created_at, 'unix') + '" ' + if_notf + ' onmouseover="mov(\'' + toot.id + '\',\'' + tlid + '\',\'mv\')" onclick="mov(\'' + toot.id + '\',\'' + tlid + '\',\'cl\')" onmouseout="resetmv(\'mv\')" reacted="' + reacted + '">' + key].created_at, 'unix') + '" ' + if_notf + ' onmouseover="mov(\'' + toot.id + '\',\'' + tlid + '\',\'mv\', \''+rand+'\')" onclick="mov(\'' + toot.id + '\',\'' + tlid + '\',\'cl\', \''+rand+'\')" onmouseout="resetmv(\'mv\')" reacted="' + reacted + '">' +
'<div class="area-notice"><span class="gray sharesta">' + notice + home + '<div class="area-notice"><span class="gray sharesta">' + notice + home +
'</span></div>' + '</span></div>' +
'<div class="area-icon"><a onclick="udg(\'' + toot.user.id + '<div class="area-icon"><a onclick="udg(\'' + toot.user.id +

View File

@ -271,8 +271,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
var noticetext = `<span onclick="notfFilter('${toot.account.id}','${tlid}');" class=" pointer big-text ${notfFilHide}"><i class="fas fa-filter" var noticetext = `<span onclick="notfFilter('${toot.account.id}','${tlid}');" class=" pointer big-text ${notfFilHide}"><i class="fas fa-filter"
title="${lang.lang_parse_notffilter}"> title="${lang.lang_parse_notffilter}">
</i><span class="voice">${lang.lang_parse_notffilter}</span></span> </i><span class="voice">${lang.lang_parse_notffilter}</span></span>
<span class="cbadge cbadge-hover" title="${date(toot.created_at, 'absolute')}(${ <span class="cbadge cbadge-hover" title="${date(toot.created_at, 'absolute')}(${lang.lang_parse_notftime
lang.lang_parse_notftime
})" aria-hidden="true"><i class="far fa-clock"></i> })" aria-hidden="true"><i class="far fa-clock"></i>
${date(toot.created_at, datetype)} ${date(toot.created_at, datetype)}
</span> </span>
@ -709,8 +708,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
var featured = ` <a onclick="tagFeature('${tag.name}','${acct_id}')" class="pointer" title="add it to Featured tags">Feature</a> ` var featured = ` <a onclick="tagFeature('${tag.name}','${acct_id}')" class="pointer" title="add it to Featured tags">Feature</a> `
tags = tags =
tags + tags +
`<span class="hide" data-tag="${tag.name}" data-regTag="${tag.name.toLowerCase()}">#${ `<span class="hide" data-tag="${tag.name}" data-regTag="${tag.name.toLowerCase()}">#${tag.name
tag.name
}: }:
<a onclick="tl('tag','${tag.name}','${acct_id}','add')" class="pointer" <a onclick="tl('tag','${tag.name}','${acct_id}','add')" class="pointer"
title="${lang.lang_parse_tagTL.replace( title="${lang.lang_parse_tagTL.replace(
@ -957,11 +955,9 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
bgColorCSS = bgColorCSS + bg + ',' bgColorCSS = bgColorCSS + bg + ','
} }
bgColorCSS = `linear-gradient(90deg, ${bgColorCSS} transparent)` bgColorCSS = `linear-gradient(90deg, ${bgColorCSS} transparent)`
var tickerdom = `<div aria-hidden="true" style="user-select:none;cursor:default;background:${bgColorCSS} !important; color:${ var tickerdom = `<div aria-hidden="true" style="user-select:none;cursor:default;background:${bgColorCSS} !important; color:${fontColor
fontColor
};width:100%; height:0.9rem; font-size:0.8rem;" class="tickers"> };width:100%; height:0.9rem; font-size:0.8rem;" class="tickers">
<img draggable="false" src="${ <img draggable="false" src="${value.favicon
value.favicon
}" style="height:100%;" onerror="this.src=\'../../img/loading.svg\'" loading="lazy"> }" style="height:100%;" onerror="this.src=\'../../img/loading.svg\'" loading="lazy">
<span style="position:relative; top:-0.2rem;">${escapeHTML(value.name)}</span> <span style="position:relative; top:-0.2rem;">${escapeHTML(value.name)}</span>
</div>` </div>`
@ -981,8 +977,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
poll + poll +
`<div class="quote-renote"> `<div class="quote-renote">
<div class="renote-icon"> <div class="renote-icon">
<a onclick="udg('${toot.quote.account.id}','${acct_id}');" user="${ <a onclick="udg('${toot.quote.account.id}','${acct_id}');" user="${toot.quote.account.acct
toot.quote.account.acct
}" class="udg"> }" class="udg">
<img draggable="false" src="${toot.quote.account.avatar}" loading="lazy"> <img draggable="false" src="${toot.quote.account.avatar}" loading="lazy">
</a> </a>
@ -994,8 +989,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
${toot.quote.content} ${toot.quote.content}
</div> </div>
<div class="renote-details"> <div class="renote-details">
<a onclick="details('${ <a onclick="details('${toot.quote.id
toot.quote.id
}','${acct_id}','${tlid}','normal')" class="waves-effect waves-dark btn-flat details" style="padding:0"> }','${acct_id}','${tlid}','normal')" class="waves-effect waves-dark btn-flat details" style="padding:0">
<i class="text-darken-3 material-icons">more_vert</i> <i class="text-darken-3 material-icons">more_vert</i>
</a> </a>
@ -1022,6 +1016,15 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
if (trans != '') { if (trans != '') {
menuct++ menuct++
} }
//このトゥート内のアクションを完了させるために、適当にIDを振る
var rand = randomStr(8)
//プラグイン機構
var plugin = plugins.buttonOnToot
var pluginHtml = ''
for (let target of plugin) {
const meta = getMeta(target.content)
pluginHtml = pluginHtml + `<li><a onclick="execPlugin('${target.id}','buttonOnToot',{id: '${uniqueid}', acct_id: '${acct_id}'});">${escapeHTML(meta.name)}</a></li>`
}
templete = templete =
templete + templete +
`<div `<div
@ -1032,8 +1035,8 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
'unix' 'unix'
)}" )}"
${if_notf} ${if_notf}
onmouseover="mov('${uniqueid}','${tlid}','mv')" onmouseover="mov('${uniqueid}','${tlid}','mv', '${rand}', this)"
onclick="mov('${uniqueid}','${tlid}','cl')" onclick="mov('${uniqueid}','${tlid}','cl', '${rand}', this)"
onmouseout="resetmv('mv')" onmouseout="resetmv('mv')"
> >
<div class="area-notice grid"><span class="gray sharesta">${notice}${home}</span></div> <div class="area-notice grid"><span class="gray sharesta">${notice}${home}</span></div>
@ -1094,8 +1097,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
</a> </a>
</div> </div>
<div class="action ${can_rt} ${disp['rt']} ${noauth}"> <div class="action ${can_rt} ${disp['rt']} ${noauth}">
<a onclick="rt('${ <a onclick="rt('${toot.id
toot.id
}','${acct_id}','${tlid}')" class="waves-effect waves-dark btn-flat actct bt-btn" }','${acct_id}','${tlid}')" class="waves-effect waves-dark btn-flat actct bt-btn"
style="padding:0" title="${lang.lang_parse_bt}"> style="padding:0" title="${lang.lang_parse_bt}">
<i class="fas fa-retweet ${if_rt} rt_${toot.id}"></i> <i class="fas fa-retweet ${if_rt} rt_${toot.id}"></i>
@ -1130,8 +1132,8 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
</div> </div>
<div class="area-side"> <div class="area-side">
<div class="action ${noauth}"> <div class="action ${noauth}">
<a onclick="toggleAction('trigger_${tlid}_${uniqueid}')" data-target="dropdown_${tlid}_${uniqueid}" <a onclick="toggleAction(this)" data-target="dropdown_${rand}"
class="ctxMenu waves-effect waves-dark btn-flat" style="padding:0" id="trigger_${tlid}_${uniqueid}"> class="ctxMenu waves-effect waves-dark btn-flat" style="padding:0" id="trigger_${rand}">
<i class="text-darken-3 material-icons act-icon" aria-hidden="true">expand_more</i> <i class="text-darken-3 material-icons act-icon" aria-hidden="true">expand_more</i>
<span class="voice">Other actions</span> <span class="voice">Other actions</span>
</a> </a>
@ -1144,7 +1146,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
<span class="voice">${lang.lang_parse_detail}</span> <span class="voice">${lang.lang_parse_detail}</span>
</div> </div>
</div> </div>
<ul class="dropdown-content contextMenu" id="dropdown_${tlid}_${uniqueid}"> <ul class="dropdown-content contextMenu" id="dropdown_${rand}">
<li class="${viashow} via-dropdown" onclick="client('${$.strip_tags(via)}')" title="${lang.lang_parse_clientop}"> <li class="${viashow} via-dropdown" onclick="client('${$.strip_tags(via)}')" title="${lang.lang_parse_clientop}">
via ${escapeHTML(via)}</a> via ${escapeHTML(via)}</a>
</li> </li>
@ -1169,6 +1171,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {
style="padding:0"> style="padding:0">
<i class="fas text-darken-3 fa-globe"></i>${lang.lang_parse_link} <i class="fas text-darken-3 fa-globe"></i>${lang.lang_parse_link}
</li> </li>
${pluginHtml}
</ul> </ul>
</div> </div>
` `
@ -1566,7 +1569,7 @@ function mastodonBaseStreaming(acct_id) {
setTimeout(function () { setTimeout(function () {
mastodonBaseWsStatus[domain] = 'available' mastodonBaseWsStatus[domain] = 'available'
}, 3000) }, 3000)
mastodonBaseWs[domain].send(JSON.stringify({type: 'subscribe', stream: 'user'})) mastodonBaseWs[domain].send(JSON.stringify({ type: 'subscribe', stream: 'user' }))
$('.notice_icon_acct_' + acct_id).removeClass('red-text') $('.notice_icon_acct_' + acct_id).removeClass('red-text')
} }
mastodonBaseWs[domain].onmessage = function (mess) { mastodonBaseWs[domain].onmessage = function (mess) {

View File

@ -101,7 +101,6 @@ if (location.search) {
$('.mini-btn').text('expand_less') $('.mini-btn').text('expand_less')
} }
} }
window.onload = function () { initPostbox(); connection() }
function initPostbox() { function initPostbox() {
$('#posttgl').click(function (e) { $('#posttgl').click(function (e) {
if (!$('#post-box').hasClass('appear')) { if (!$('#post-box').hasClass('appear')) {

View File

@ -7,8 +7,8 @@
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"construct": "cd view/make && node make --automatic && cd ../../", "construct": "cd view/make && node make --automatic && cd ../../ && browserify aiscript.js -o js/platform/aiscript.js",
"construct:store": "cd view/make && node make --automatic --store && cd ../../", "construct:store": "cd view/make && node make --automatic --store && cd ../../ && browserify aiscript.js -o js/platform/aiscript.js",
"dev": "npx electron ./ --dev", "dev": "npx electron ./ --dev",
"dist": "build --linux snap", "dist": "build --linux snap",
"watchview": "node view/make/make.js --automatic --watch", "watchview": "node view/make/make.js --automatic --watch",
@ -60,6 +60,7 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.15.1", "@fortawesome/fontawesome-free": "^5.15.1",
"@syuilo/aiscript": "^0.11.1",
"electron-dl": "^3.0.2", "electron-dl": "^3.0.2",
"jimp": "^0.16.1", "jimp": "^0.16.1",
"jquery": "^3.5.1", "jquery": "^3.5.1",
@ -76,6 +77,7 @@
"itunes-nowplaying-mac": "0.3.1" "itunes-nowplaying-mac": "0.3.1"
}, },
"devDependencies": { "devDependencies": {
"browserify": "^17.0.0",
"chokidar": "^3.4.3", "chokidar": "^3.4.3",
"electron": "^10.1.5", "electron": "^10.1.5",
"electron-builder": "^22.9.1", "electron-builder": "^22.9.1",

View File

@ -1221,8 +1221,10 @@
<!--JS--> <!--JS-->
<script type="text/javascript" src="../../@@node_base@@/jquery/dist/jquery.js"></script> <script type="text/javascript" src="../../@@node_base@@/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="../../js/platform/first.js"></script> <script type="text/javascript" src="../../js/platform/first.js"></script>
<script type="text/javascript" src="../../@@node_base@@/grapheme-splitter/index.js"></script> <script type="text/javascript" src="../../js/platform/aiscript.js"></script>
<script type="text/javascript" src="../../js/platform/plugin.js"></script>
<script type="text/javascript" src="../../@@node_base@@/materialize-css/dist/js/materialize.js"></script> <script type="text/javascript" src="../../@@node_base@@/materialize-css/dist/js/materialize.js"></script>
<script type="text/javascript" src="../../@@node_base@@/grapheme-splitter/index.js"></script>
<script type="text/javascript" src="../../@@node_base@@/lodash/lodash.min.js"></script> <script type="text/javascript" src="../../@@node_base@@/lodash/lodash.min.js"></script>
<script type="text/javascript" src="main.js"></script> <script type="text/javascript" src="main.js"></script>
<script type="text/javascript" src="../../js/common/time.js"></script> <script type="text/javascript" src="../../js/common/time.js"></script>

View File

@ -43,7 +43,7 @@
<script src="../../@@node_base@@/vue/dist/vue.min.js"></script> <script src="../../@@node_base@@/vue/dist/vue.min.js"></script>
<script type="text/javascript" src="setting.vue.js"></script> <script type="text/javascript" src="setting.vue.js"></script>
<script type="text/javascript" src="../../@@node_base@@/sweetalert2/dist/sweetalert2.all.min.js"></script> <script type="text/javascript" src="../../@@node_base@@/sweetalert2/dist/sweetalert2.all.min.js"></script>
<script>function renderMem() {return false; }</script> <script>function renderMem() { return false; }</script>
<h4>@@setting@@</h4> <h4>@@setting@@</h4>
<ul class="collapsible" data-collapsible="accordion"> <ul class="collapsible" data-collapsible="accordion">
@ -157,7 +157,7 @@
<input type="checkbox" class="filled-in" id="use-color_1" value="1" checked disabled /> <input type="checkbox" class="filled-in" id="use-color_1" value="1" checked disabled />
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
<input type="color" id="color-picker1_value"> <input type="color" id="color-picker1_value">
</div> </div>
<div> <div>
<h5>Subcolor</h5>@@subcolor@@<br /> <h5>Subcolor</h5>@@subcolor@@<br />
@ -165,7 +165,7 @@
<input type="checkbox" class="filled-in" id="use-color_2" value="1" checked disabled /> <input type="checkbox" class="filled-in" id="use-color_2" value="1" checked disabled />
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
<input type="color" id="color-picker2_value"> <input type="color" id="color-picker2_value">
</div> </div>
<div> <div>
<h5>Accent</h5>@@accent@@<br /> <h5>Accent</h5>@@accent@@<br />
@ -173,7 +173,7 @@
<input type="checkbox" class="filled-in" id="use-color_3" value="1" checked disabled /> <input type="checkbox" class="filled-in" id="use-color_3" value="1" checked disabled />
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
<input type="color" id="color-picker3_value"> <input type="color" id="color-picker3_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
@ -183,9 +183,9 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('background','modal')">Background</a> <a class="pointer" onclick="copyColor('background','modal')">Background</a>
<br /> <br />
<input type="color" id="color-picker4_value"> <input type="color" id="color-picker4_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>Modal Footer</h5>@@modalFooter@@<br /> <h5>Modal Footer</h5>@@modalFooter@@<br />
@ -194,10 +194,10 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('background','modalFooter')">Background</a>/ <a class="pointer" onclick="copyColor('background','modalFooter')">Background</a>/
<a class="pointer" onclick="copyColor('modal','modalFooter')">Modal</a> <a class="pointer" onclick="copyColor('modal','modalFooter')">Modal</a>
<br /> <br />
<input type="color" id="color-picker5_value"> <input type="color" id="color-picker5_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>3rd Color</h5>@@thirdColor@@<br /> <h5>3rd Color</h5>@@thirdColor@@<br />
@ -206,9 +206,9 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('subcolor','third')">Subcolor</a> <a class="pointer" onclick="copyColor('subcolor','third')">Subcolor</a>
<br /> <br />
<input type="color" id="color-picker6_value"> <input type="color" id="color-picker6_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>4th Color</h5>@@forthColor@@<br /> <h5>4th Color</h5>@@forthColor@@<br />
@ -217,10 +217,10 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('subcolor','forth')">Subcolor</a>/ <a class="pointer" onclick="copyColor('subcolor','forth')">Subcolor</a>/
<a class="pointer" onclick="copyColor('third','forth')">3rd Color</a> <a class="pointer" onclick="copyColor('third','forth')">3rd Color</a>
<br /> <br />
<input type="color" id="color-picker7_value"> <input type="color" id="color-picker7_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>Bottom</h5>@@bottom@@<br /> <h5>Bottom</h5>@@bottom@@<br />
@ -229,9 +229,9 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('subcolor','bottom')">Subcolor</a> <a class="pointer" onclick="copyColor('subcolor','bottom')">Subcolor</a>
<br /> <br />
<input type="color" id="color-picker8_value"> <input type="color" id="color-picker8_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>2nd Accent</h5>@@emphasized@@<br /> <h5>2nd Accent</h5>@@emphasized@@<br />
@ -240,9 +240,9 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('accent','emphasized')">Accent</a> <a class="pointer" onclick="copyColor('accent','emphasized')">Accent</a>
<br /> <br />
<input type="color" id="color-picker9_value"> <input type="color" id="color-picker9_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>Postbox</h5>@@postbox@@<br /> <h5>Postbox</h5>@@postbox@@<br />
@ -251,9 +251,9 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('subcolor','postbox')">Subcolor</a> <a class="pointer" onclick="copyColor('subcolor','postbox')">Subcolor</a>
<br /> <br />
<input type="color" id="color-picker10_value"> <input type="color" id="color-picker10_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>Active</h5>@@active@@<br /> <h5>Active</h5>@@active@@<br />
@ -262,9 +262,9 @@
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
@@copyFrom@@: @@copyFrom@@:
<a class="pointer" onclick="copyColor('accent','active')">Accent</a> <a class="pointer" onclick="copyColor('accent','active')">Accent</a>
<br /> <br />
<input type="color" id="color-picker11_value"> <input type="color" id="color-picker11_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>Selected</h5>@@selected@@<br /> <h5>Selected</h5>@@selected@@<br />
@ -272,7 +272,7 @@
<input type="checkbox" class="filled-in" id="use-color_12" value="1" /> <input type="checkbox" class="filled-in" id="use-color_12" value="1" />
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
<input type="color" id="color-picker12_value"> <input type="color" id="color-picker12_value">
</div> </div>
<div class="advanced hide"> <div class="advanced hide">
<h5>Selected with shared</h5>@@selectedWithShare@@<br /> <h5>Selected with shared</h5>@@selectedWithShare@@<br />
@ -280,7 +280,7 @@
<input type="checkbox" class="filled-in" id="use-color_13" value="1" /> <input type="checkbox" class="filled-in" id="use-color_13" value="1" />
<span>@@use@@</span> <span>@@use@@</span>
</label><br /> </label><br />
<input type="color" id="color-picker13_value"> <input type="color" id="color-picker13_value">
</div> </div>
</div><br /><br /> </div><br /><br />
<button class="btn-large waves-effect" onclick="customComp()">@@change@@</button>&nbsp;<button <button class="btn-large waves-effect" onclick="customComp()">@@change@@</button>&nbsp;<button
@ -385,13 +385,6 @@
</template><br> </template><br>
</template> </template>
</div> </div>
</div>
</li>
<li>
<div class="collapsible-header">
<i class="material-icons">keyboard</i>@@keysc@@
</div>
<div class="collapsible-body">
<h5>@@iks@@</h5> <h5>@@iks@@</h5>
@@okswarn@@<br> @@okswarn@@<br>
Ctrl+Shift+1:<input type="text" style="width:11.5rem" id="oks-1"> Ctrl+Shift+1:<input type="text" style="width:11.5rem" id="oks-1">
@ -400,6 +393,15 @@
<button onclick="oks(2)" class="btn waves-effect" style="width:7.7rem;">@@set@@</button><br><br> <button onclick="oks(2)" class="btn waves-effect" style="width:7.7rem;">@@set@@</button><br><br>
Ctrl+Shift+3:<input type="text" style="width:11.5rem" id="oks-3"> Ctrl+Shift+3:<input type="text" style="width:11.5rem" id="oks-3">
<button onclick="oks(3)" class="btn waves-effect" style="width:7.7rem;">@@set@@</button><br><br> <button onclick="oks(3)" class="btn waves-effect" style="width:7.7rem;">@@set@@</button><br><br>
</div>
</li>
<li>
<div class="collapsible-header">
<i class="material-icons">power</i>@@plugin@@
</div>
<div class="collapsible-body">
</div> </div>
</li> </li>
<li> <li>

File diff suppressed because it is too large Load Diff

117
plugin.md Normal file
View File

@ -0,0 +1,117 @@
# TheDesk Plugin
[AiScript](https://github.com/syuilo/aiscript)で書きます。
[AiScriptの書き方](https://github.com/syuilo/aiscript/blob/master/docs/get-started.md)
## メタデータ
```
### {
name: "マイ・ファースト・プラグイン"
version: 1
event: "buttonOnPostbox"
author: "Cutls P"
}
```
これを冒頭に入れます。
* dangerHtml: true|false
`TheDesk:changeText`にアクセスするために必要です。
* apiGetl: true|false
`TheDesk:api`にGETメソッドでアクセスするときに必要です。
* apiPost: true|false
`TheDesk:api`にPOST/PUT/DELETEメソッドでアクセスするときや、`postExec`を実行するときに必要です。
### event
eventに設定できるもの
* `buttonOnPostbox`
投稿フォームの…(90°回転)で出てくるメニュー内に表示されます
* `buttonOnToot`
トゥートの詳細メニューに表示されます
* `init`
起動時(なるべく早い段階で)
追加予定…
## 変数
### buttonOnTootのとき
* DATA
```
{
id: "トゥートのID文字列",
acct_id: "アカウントのTheDesk内部ID"
}
```
* TOOT
トゥートのAPIを叩いた時と同じオブジェクトが返ります。なお、プラグインが実行されてから取得します。
プラグインの実行ボタン押下から実行までの時間差はこれによるものです。
### buttonOnPostboxのとき
* POST
投稿するときのオブジェクトがそのまま入りますが、`TheDeskAcctId`というTheDeskが内部で扱うアカウントのID(string)が入ったプロパティが追加されます。
* ACCT_ID
TheDeskが内部で扱うアカウントのID(string)
## 関数
### TheDesk:dialog(title: string, text: string, type?: string)
typeのデフォルトは'info'で、他に'error','question','success'などがある
### TheDesk:confirm(title: string, text: string, type?: string)
typeのデフォルトは'info'で、他に'error','question','success'などがある
返り値はboolean(true|false)
### TheDesk:css(query: string, attr: string, val: string)
jQueryの`$(query).css(attr, val)`に相当
### TheDesk:api(method: 'GET'|'POST'|'PUT'|'DELETE', endpoint: string, body: string, acct_id: string)
bodyにもstringを投げてください。
endpointは`v1`から書いてください。(`v1/accounts...`)
返り値はjsonのオブジェクト。
### TheDesk:changeText(body: string)
`buttonOnToot`で使用可能
該当トゥート(や他タイムラインの同一トゥート)のテキストを書き換えます。
`dangerHtml`をtrueにしてください。
HTMLを引数にすることに留意してください。
### TheDesk:postText(text: string)
`buttonOnPostbox`で使用可能
トゥートボックスの中身を書き換えます。
### TheDesk:postCW(force: boolean, text: string)
`buttonOnPostbox`で使用可能
CWを切り替えます。forceはデフォルトでfalseで、trueにするとオンに、falseにするとトグルになります。
textには警告文を入れます。
### TheDesk:postNSFW(force: boolean)
`buttonOnPostbox`で使用可能
NSFWを切り替えます。forceはデフォルトでfalseで、trueにするとオンに、falseにするとトグルになります。
### TheDesk:postVis(vis: 'public'|'unlisted'|'private'|'direct')
`buttonOnPostbox`で使用可能
公開範囲を変更します。
### TheDesk:postNSFW(force: postClearbox)
`buttonOnPostbox`で使用可能
投稿ボックスをクリアします。
### TheDesk:postExec()
`buttonOnPostbox`で使用可能
`apiPost`をtrueにしてください。
トゥートボタンを押したのと同じ挙動をします。