This commit is contained in:
cutls 2018-01-28 21:22:43 +09:00
commit 30132ca31d
139 changed files with 40821 additions and 0 deletions

36
README.md Normal file
View File

@ -0,0 +1,36 @@
# TheDesk
Mastodon client for Windows
オープンソースSNSマストドンのWindowsクライアント
Download:[TheDesk](https://desk.cutls.com)
## License
Apache License, Version 2.0
## Component/構成
app:Raw files(you can download to modify or check)
app:そのままのファイル
## Language/言語
Japanese
日本語
## Requirement/環境
- Windows 64bit(to launch TheDesk/実行に必要)
- Electron beta.1.8.2-beta4
- electron-dl
- electron-about-window
- Ability to read unformated files!
### Why do we use Electron beta version?/Beta版の利用について
Some animated emojis are not GIF but PNG, only rendered by Electron beta version(Chromium 59 and above).
アニメ絵文字の一部がChromium 59以降のみ対応のAPNGで提供されているためBetaを利用しています。
## See also/詳しく
[TheDesk - マストドン日本語ウィキ](https://ja.mstdn.wiki/TheDesk)

60
acct.html Normal file
View File

@ -0,0 +1,60 @@
<!doctype html>
<html lang="ja">
<head>
<title>Account Manager - TheDesk</title>
<link href="./css/materialize.css" type="text/css" rel="stylesheet">
<link href="./css/master.css" type="text/css" rel="stylesheet">
<link href="./css/auth.css" type="text/css" rel="stylesheet">
<link href='./css/font-awesome.css' rel='stylesheet' type='text/css'>
<link href='./css/tl.css' rel='stylesheet' type='text/css'>
<link href='./css/userdata.css' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons|Open+Sans:300" rel="stylesheet">
<style>.acct{display:flex; justify-content:space-around;}
.text{overflow-x: scroll;}
</style>
<meta charset="utf-8">
</head>
<body id="mainView">
<script type="text/javascript" src="./js/common/jquery.js"></script>
<script type="text/javascript" src="./js/platform/first.js"></script>
<script type="text/javascript" src="./js/common/materialize.js"></script>
<script type="text/javascript" src="./js/ui/tips.js"></script>
<script type="text/javascript" src="./js/common/time.js"></script>
<script type="text/javascript" src="./js/common/modal.js"></script>
<div id="tools">
<div id="notice" >Account Manager</div>
<a onclick="notfToggle()" class="setting nex"><i class="material-icons nex notf-icon">notifications</i></a>
<a href="index.html" class="setting nex"><i class="material-icons nex">home</i></a>
<a onclick="udg()" class="pointer"><img src="./img/loading.svg" width="24" class="my-prof"></a>
</div>
<div id="notf-box" class="hide"><div id="notifications">Notifications will be showed here...</div><button class="btn waves-effect orange more-hide" style="width:calc( 100% - 10px); padding:0;" onclick="notfToggle()">閉じる</button></div>
<a href="setting.html" class="btn waves-effect orange nex" style="width:100%; max-width:200px;">戻る</a><br>
<div id="acct-list"></div>
<div class="divider"></div>
アカウントを追加<br>
<div id="add">
<input type="text" id="url" style="width:70%" placeholder="mstdn.jp">
<button class="btn waves-effect" onclick="instance()">Login</button><br>
<span style="font-family:Open Sans;">Supports</span>
<div id="support"></div>
</div>
<div id="auth" style="display:none">
指定されたコードを貼り付けてください。ログインウィンドウは閉じていただいて構いません。<br>
<input type="text" id="code" placeholder="コードを入力">
<button class="btn waves-effect" onclick="code()">認証</button><br>
</div>
現在ログイン中のインスタンス情報 by <a href="https://instances.social" target="_blank">instances.social API</a><br>
<img src="./img/loading.svg" id="ins-prof" width="200"><br>
<span id="ins-upd"></span>現在<br>
ドメイン名:<span class="now-domain"></span><br>
いつから:<span id="ins-add"></span><br>
接続済みインスタンス:<span id="ins-connect"></span><br>
トゥート数:<span id="ins-toot"></span><br>
ユーザー数:<span id="ins-user"></span><br>
コネクション:<span id="ins-per"></span>%<br>
マストドンバージョン:<span id="ins-ver"></span><br>
マストドンアップデート:<span id="ins-sys"></span><br>
<script type="text/javascript" src="./js/login/manager.js"></script>
<script type="text/javascript" src="./js/tl/date.js"></script>
<script type="text/javascript" src="./js/platform/end.js"></script>

2
css/about.css Normal file
View File

@ -0,0 +1,2 @@
/*このソフトについてを押した時に読み込まれます*/
body{font-family:Open Sans;}

4
css/auth.css Normal file
View File

@ -0,0 +1,4 @@
/*ログイン画面とその認証までのCSSです*/
#masara{display:none}
#auth{display:none}
#tl{display:none;}

2337
css/font-awesome.css vendored Normal file

File diff suppressed because it is too large Load Diff

177
css/master.css Normal file
View File

@ -0,0 +1,177 @@
/*共通CSS*/
.btn {
margin: 5px;
text-transform: none;
}
.markdown {
display: none;
}
help {
display: none;
font-size: 10px;
color: gray;
}
.show-help {
display: inline;
}
option {
display: none;
}
#mainView {
padding: 10px;
padding-top: 50px;
}
#message {
display: none;
position: fixed;
bottom: 0;
left: 0;
background-color: black;
color: white;
z-index: 9999;
}
#imagemodal, #videomodal {
display: none;
max-width: 100vw;
max-height: 100vh;
top:0;
background-color: white;
position: fixed;
z-index: 9;
}
#imagemodal .modal-content {
overflow: hidden;
}
#imagewrap {
width: 100%;
height: 100%;
}
.pointer {
cursor: pointer;
}
.bbcode-pulse-loadings, .fa-pulse {
display: inline-block;
animation-duration: 3s;
animation-fill-mode: both;
animation-iteration-count: infinite;
animation-name: pulse;
}
@keyframes pulse {
from, 50%, to {
opacity: 1;
}
25%, 75% {
opacity: 0;
}
}
code:before, .pre:before {
content: "Code";
font-size: 30px;
line-height: 1em;
font-family: monospace, monospace;
color: #999;
position: absolute;
right: 0;
top: 0;
}
code, pre {
color: white;
display: block;
border-left: 5px solid;
border-color: #079903;
padding-left: 10px;
margin-top: 5px;
margin-bottom: 5px;
margin-left: 5px;
background-color: #000;
padding: 1em 1em 1em;
position: relative;
-webkit-border-top-left-radius: 10px;
-webkit-border-bottom-right-radius: 10px;
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius-topleft: 10px;
-moz-border-radius-bottomright: 10px;
-moz-border-radius-bottomleft: 10px;
}
blockquote, .quote p {
margin: 0;
}
blockquote, .quote {
color: black;
background-color: #ddd;
padding: 1em 1em 1em;
position: relative;
-webkit-border-top-left-radius: 10px;
-webkit-border-bottom-right-radius: 10px;
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius-topleft: 10px;
-moz-border-radius-bottomright: 10px;
-moz-border-radius-bottomleft: 10px;
}
blockquote:before, .quote:before {
content: "Quote";
font-size: 30px;
line-height: 1em;
font-family: Open Sans, cursive;
color: #999;
position: absolute;
right: 0;
top: 0;
}
#drag {
display: none;
position: fixed;
width: 100vw;
height: 100vh;
background-color: rgba(255, 255, 255, 0.8);
z-index: 99999;
justify-content: center;
align-items: center;
}
#drag-content {
font-size: 200%;
}
/*black theme*/
.blacktheme body {
color: white;
background-color: #212121;
}
.blacktheme #drag {
color: white;
background-color: rgba(0, 0, 0, 0.8);
position: fixed;
width: 100vw;
height: 100vh;
z-index: 99999;
justify-content: center;
align-items: center;
}
.blacktheme #imagemodal, #videomodal, #tootmodal {
background-color: black;
}
.blacktheme .collapsible-header {
background-color: #212121;
}
.blacktheme .tabs {
background-color: #212121;
}
/*スクロールバー*/
::-webkit-scrollbar {
width: 5px;
height: 10px;
background: rgba(0, 0, 0, 0.05);
}
::-webkit-scrollbar-track {
-webkit-border-radius: 5px;
border-radius: 5px;
}
/* Handle */
::-webkit-scrollbar-thumb {
-webkit-border-radius: 5px;
border-radius: 5px;
background: #9e9e9e;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
}

9389
css/materialize.css vendored Normal file

File diff suppressed because it is too large Load Diff

16
css/materialize.min.css vendored Normal file

File diff suppressed because one or more lines are too long

75
css/post.css Normal file
View File

@ -0,0 +1,75 @@
/*トゥートボックス向けCSS*/
#post-box {
position: absolute;
right: 3px;
bottom: 3px;
background-color: white;
border: thin solid gray;
z-index: 1000;
width: 350px;
min-width:350px;
max-width:100%;
padding: 5px;
}
.cancel {
position: absolute;
top: 3px;
right: 3px;
font-size: 7px;
color: gray;
cursor: pointer;
}
.more-show {
display: none;
}
#drag {
width: 100%;
height: 100px;
background-color: #e0e0e0;
color: black;
}
#post-btn {
display: none;
}
#vis {
text-transform: capitalize;
}
#cw-text {
display: none;
}
.cw {
display: none;
}
.sensitive {
filter: blur(50px);
}
#emoji {
position: fixed;
bottom: 120px;
right: 20px;
width: 300px;
height: 370px;
z-index: 1003;
padding: 5px;
}
#emoji-list {
width: 100%;
height: calc(100% - 110px);
overflow-y: scroll;
}
.emoji-control {}
#preview-field {
display: none;
}
/*black theme*/
.blacktheme #post-box {
background-color: #424242;
}
.blacktheme #drag {
width: 100%;
height: 100px;
background-color: #004d40;
color: white;
padding: 3px;
}

142
css/tl.css Normal file
View File

@ -0,0 +1,142 @@
/*TL CSS(ただしBBCode pulse:master.css/spin:font-awesome*/
#timeline-container {
display: flex;
width: 100vw;
height: 100vh;
}
.box {
overflow-y: scroll;
overflow-x: hidden;
min-width: 300px;
height: 100vh;
flex: 1;
}
@media screen and (max-width: 600px) {
#timeline-container {
display: block;
overflow-x: hidden;
}
.box {
width: 100vw;
}
.fixed-action-btn {
position: absolute;
}
}
.additional {
overflow-x: scroll;
width: 100%;
}
.cvo {
padding-left: 5px;
padding-right: 2px;
word-break: break-all;
}
.gray {
color: gray;
}
.sml {
font-size: 80%;
}
.toot {
overflow: hide;
}
.toot-img {
object-fit: cover;
width: 100%;
height: 200px;
}
.toot img:not(.emoji-img) {
max-width: 100%;
max-height: 300px;
}
.cbadge {
display: inline-block;
min-width: 10px;
padding: 3px 7px;
font-size: 12px;
margin-right: 5px;
line-height: 1;
color: #fff;
text-align: center;
white-space: nowrap;
vertical-align: middle;
background-color: #777;
border-radius: 10px;
}
p {
margin: 0;
margin-bottom: 10px;
}
.shared {
background-color: #cfd8dc;
}
.udg {
cursor: pointer;
}
.notice {
top: -7px;
display: inline-block;
position: relative;
font-family: Open Sans;
margin-right: 10px;
}
#tools {
position: fixed;
top: 10px;
right: 10px;
float: right;
}
.setting {
font-size: 7px;
color: gray;
cursor: pointer;
}
#toot-this .details {
display: none;
}
.notf-box {
position: fixed;
right: 3px;
bottom: 300px;
background-color: white;
border: thin solid gray;
z-index: 1001;
width: 400px;
padding: 5px;
min-height: 100px;
max-height: 500px;
}
.notf-indv-box {
min-height: 100px;
max-height: 400px;
overflow-y: scroll;
overflow-x: hidden;
border: thin solid gray;
}
#src-contents {
min-height: 100px;
max-height: 190px;
overflow-y: scroll;
}
.mention {
color: black;
cursor: text;
}
/*black theme*/
.blacktheme #notf-box, .notf-box {
background-color: #424242;
}
.blacktheme .modal-footer {
background-color: #424242;
}
.blacktheme .btn-flat {
color: white
}
.blacktheme .shared {
background-color: #004d40;
}
.blacktheme .mention {
color: white;
}

37
css/userdata.css Normal file
View File

@ -0,0 +1,37 @@
/*アイコンをクリックした時とかにでてくるユーザーデータ*/
#his-data {
background-repeat: no-repeat;
background-image: url('/img/loading.svg');
overflow-y: hidden;
}
#his-prof {
float: left;
width: 100px;
}
.his-float {
float: left;
width: calc(50% - 50px);
height: 122px;
overflow-y: scroll;
padding: 5px;
}
#his-data-show {
margin: 50px;
background-color: rgba(255, 255, 255, 0.8);
width: calc(100% - 50px);
height: calc(100% - 50px);
margin-bottom: 0;
padding: 5px;
}
.tab-content {
overflow-y: scroll;
height: calc(100% - 240px)
}
.my-data-width {
width: 11.11%;
}
/*black theme*/
.blacktheme #his-data-show {
background-color: rgba(0, 0, 0, 0.8);
}

BIN
desk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
fonts/FontAwesome.otf Normal file

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
img/desk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

4
img/loading.svg Normal file
View File

@ -0,0 +1,4 @@
<svg fill="gray" height="512" viewBox="0 0 24 24" width="512" xmlns="http://www.w3.org/2000/svg">
<path d="M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4zM6 12c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46C15.03 4.46 13.57 4 12 4c-4.42 0-8 3.58-8 8H1l4 4 4-4H6z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 389 B

378
index.html Normal file
View File

@ -0,0 +1,378 @@
<!doctype html>
<html lang="ja">
<head>
<title>TheDesk</title>
<meta content="width=device-width,initial-scale=1.0" name="viewport">
<link href="./css/materialize.css" type="text/css" rel="stylesheet">
<link href="./css/auth.css" type="text/css" rel="stylesheet">
<link href='./css/font-awesome.css' rel='stylesheet' type='text/css'>
<link href='./css/tl.css' rel='stylesheet' type='text/css'>
<link href='./css/userdata.css' rel='stylesheet' type='text/css'>
<link href='./css/post.css' rel='stylesheet' type='text/css'>
<link href="./css/master.css" type="text/css" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons|Open+Sans:300" rel="stylesheet">
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript" src="./js/common/jquery.js"></script>
<script type="text/javascript" src="./js/platform/first.js"></script>
<script type="text/javascript" src="./js/common/materialize.js"></script>
<script type="text/javascript" src="./js/ui/tips.js"></script>
<script type="text/javascript" src="./js/common/time.js"></script>
<script type="text/javascript" src="./js/common/version.js"></script>
<script type="text/javascript" src="./js/common/keyshortcut.js"></script>
<script type="text/javascript" src="./js/common/modal.js"></script>
<script>
var ver="Miho (ver.3)";
//betaを入れるとバージョンチェックしない
//var ver="beta";
var acct_id=0;
var tlid=0;
verck(ver);
</script>
<div id="masara">
<!--最初にログインする-->
ログインしたいインスタンスのアドレス<br>
<input type="text" id="url" style="width:70%" placeholder="mstdn.jp">
<button class="btn waves-effect" onclick="instance()">Login</button><br>
<span style="font-family:Open Sans;">Supports</span>
<div id="support">
</div>
<br>
各インスタンスの独自機能もAPIの範囲内で実装させていただきます。お知らせください。<a href="https://kirishima.cloud/@Cutls" target="_blank">Cutls P(@Cutls@kirishima.cloud)</a>まで。<br>
ログイン後は設定画面から@Cutls@kirishima.cloudにコンタクトをとることができます。<br>
<button class="btn waves-effect indigo" onclick="about()">このソフトについて</button><br>
</div>
<div id="auth">
<!--PINコードで認証-->
指定されたコードを貼り付けてください。ログインウィンドウは閉じていただいて構いません。<br>
<input type="text" id="code" placeholder="コードを入力">
<button class="btn waves-effect" onclick="code()">認証</button><br>
</div>
<div id="tl">
<!--TL-->
<!--ドラッグハンドラ-->
<div id="drag"><div id="drag-content">ここにドラッグして添付(ドラッグと同時にアップロードされます)<br><button class="btn waves-effect" onclick="closedrop()">閉じる</button></div></div>
<!--アカウント追加-->
<div id="add-box" class="hide notf-box">
<div class="input-field">
アカウント選択<br>
<select id="add-acct-sel" class="acct-sel" style="color:black">
</select>
<label></label>
</div><div class="input-field">
<select id="type-sel" style="color:black">
<option value="local">ローカル</option>
<option value="home">ホーム</option>
<option value="pub">連合</option>
<option value="mix">統合(ローカルとホーム)</option>
<option value="notf">通知</option>
</select>
<label>表示するタイムライン</label>
</div>
<button class="btn waves-effect blue " style="width:calc( 100% - 10px); padding:0;" onclick="addColumn()">追加</button>
<br><br>
<button class="btn waves-effect orange " style="width:calc( 100% - 10px); padding:0;" onclick="addToggle()">閉じる</button>
</div>
<!--検索-->
<div id="src-box" class="hide notf-box">
<div class="input-field">
<i class="material-icons prefix">search</i>
<input id="src" type="text" class="validate" style="width:calc( 70% - 40px); padding:0;">
<br>ハッシュタグを検索するときは#を抜いてください。<br>
検索に使用するアカウント選択を<br>
<div class="input-field">
<select id="src-acct-sel" class="acct-sel">
</select>
<label></label>
</div>
<label for="src">検索</label>
<button class="btn waves-effect indigo" style="width:calc( 30% - 40px); padding:0;" onclick="src()">検索</button>
</div>
<div id="search">
<div id="src-contents"></div>
<button class="btn waves-effect orange " style="width:calc( 100% - 10px); padding:0;" onclick="srcToggle()">閉じる</button>
</div>
</div>
<!--TLのTL-->
<div id="timeline-container">
</div>
<div id="post-box">
<!--トゥートボックス-->
<span class="cancel"><i class="material-icons" onclick="hide()" title="このボックスを閉じる(X)">cancel</i></span><br>
<a onclick="addToggle()" class="setting nex"><i class="material-icons nex" title="カラム追加">add</i></a>
<a id="clear" class="setting nex"><i class="material-icons nex" title="トゥートボックスのクリア">clear</i></a>
<a onclick="zoomBox()" class="setting nex"><i class="material-icons nex" title="ボックスの拡大・縮小(E)">zoom_out_map</i></a>
<a onclick="srcToggle()" class="setting nex"><i class="material-icons nex" title="検索">search</i></a>
<a href="setting.html" class="setting nex"><i class="material-icons nex" title="設定">settings</i></a>
<a href="acct.html"><i class="material-icons nex" title="アカウント管理">account_circle</i></a>
<a href="index.html" class="setting nex"><i class="material-icons nex" title="スーパーリロード">refresh</i></a>
<div class="row" style="margin-bottom:0;">
<span class="sml"><span class="gray">画面内どこでもドラッグ・アンド・ドロップできます。</span><br></span>アカウント選択</span><br>
<div class="input-field">
<select id="post-acct-sel" class="acct-sel">
</select>
</div>
<!--Markdown-->
<div class="row">
<div class="markdown">
<div class="col s12 more-show">
<i class="material-icons pointer setting" onclick="tagsel('b')" title="太字(Ctrl+B)テキストボックス内を選択してから押すと囲みます。">format_bold</i>
<i class="material-icons pointer setting" onclick="tagsel('i')" title="斜字(Ctrl+I)テキストボックス内を選択してから押すと囲みます。">format_italic</i>
<i class="material-icons pointer setting" onclick="tagsel('u')" title="下線(Ctrl+U)テキストボックス内を選択してから押すと囲みます。">format_underlined</i>
<i class="material-icons pointer setting" onclick="tagsel('s')" title="取り消し(Ctrl+S)テキストボックス内を選択してから押すと囲みます。">strikethrough_s</i>
<i class="material-icons pointer setting" onclick="markdown('>','no','yes')" title="引用">format_quote</i>
<i class="material-icons pointer setting" onclick="markdown('#','no','yes')" title="見出し">short_text</i>
<i class="material-icons pointer setting" onclick="markdown('`','yes','no')" title="コード挿入">code</i>
<i class="material-icons pointer setting" onclick="tagsel('spin')" title="回転 テキストボックス内を選択してから押すと囲みます。">autorenew</i>
<i class="material-icons pointer setting" onclick="tagsel('pulse')" title="点滅 テキストボックス内を選択してから押すと囲みます。">flare</i>
<i class="material-icons pointer setting" onclick="tagsel('flip=vertical')" title="上下反転 テキストボックス内を選択してから押すと囲みます。">swap_vert</i>
<i class="material-icons pointer setting" onclick="tagsel('flip=horizontal')" title="左右反転 テキストボックス内を選択してから押すと囲みます。">swap_horiz</i>
<span class="sml gray pointer"><a onclick="mdToggle()">Markdownエディタを隠す</a></span><br>
<i class="material-icons pointer setting" onclick="tagsel('size')" title="文字サイズ変更 テキストボックス内を選択してから押すと囲みます。">format_size</i><input id="size" style="width: calc(50% - 20px); margin: 0; height: 24px;" value="12">px
<i class="material-icons pointer setting" onclick="tagsel('colorhex')" title="文字色変更 テキストボックス内を選択してから押すと囲みます。">color_lens</i><input id="colorhex" style="width: calc(50% - 50px); margin: 0; height: 24px;" type="color"><br>
<i class="material-icons pointer setting" onclick="markdownLink()" title="リンク挿入">link</i><input id="linkt" style="width: calc(50% - 20px); margin: 0; height: 24px;" placeholder="リンクテキスト">&nbsp;<input id="link2" style="width: calc(50% - 20px); margin: 0; height: 24px;" placeholder="リンクアドレス"><br>
<i class="material-icons pointer setting" onclick="markdownImage()" title="インライン画像挿入">image</i><input id="image" style="width: calc(50% - 20px); margin: 0; height: 24px;" placeholder="代替テキスト">&nbsp;<input id="image2" style="width: calc(50% - 20px); margin: 0; height: 24px;" placeholder="画像アドレス">
</div>
</div>
<div class="input-field col s12" id="preview-field" style="margin-top: 0;">
<div id="md-preview"></div>
<span class="sml gray pointer"><a onclick="previewEdit()">Edit</a></span>
</div>
<div class="input-field col s12" id="toot-field" style="margin-top: 0;">
<textarea id="textarea" class="materialize-textarea" style="margin-bottom:0" data-length="500"></textarea>
<label for="textarea"></label>
<span class="sml gray pointer more-show markdown" id="preview-btn"><a onclick="preview()">Preview</a></span>
<span class="sml gray pointer more-show anti-markdown hide"><a onclick="mdToggle()">Markdownエディタを表示</a></span>
</div>
<div id="suggest"></div>
<br>
<!--hidden area-->
<input type="hidden" id="reply">
<input type="hidden" id="media">
<!--END hidden area-->
<div class="col s12">
<button class="btn waves-effect indigo" style="width:100%; padding:0; margin-top:20px;" onclick="post()" id="toot-post-btn">トゥート</button> </div>
<div class="col s12">
<button class="btn waves-effect orange more-hide" style="width:100%; padding:0;" onclick="more()">もっと</button>
<!--もっと-->
<span id="preview"></span>
<span class="more-show sml">返信モード:<span id="rec">いいえ</span>/添付:<span id="mec">なし</span>/公開範囲:<span id="vis">public</span>/画像制限:<span id="nsc">なし</span></span><br>
<span id="file-wrap"><input class="more-show" type="file" name="pic" id="upfile" onchange="pimg(document.getElementById('upfile').files);" multiple></span>
<input type="text" id="cw-text" placeholder="警告文">
</div></div>
<div class="col s3">
<button class="btn waves-effect more-show blue darken-3" style="width:100%; padding:0; margin-top:0;" id="cw" onclick="cw()" title="コンテンツワーニング(トゥートを表示する前にメッセージで隠す)(青:OFF)">CW</button>
</div>
<div class="col s3">
<button class="dropdown-button btn waves-effect more-show pink " style="width:100%; padding:0; margin-top:0;" data-activates='dropdown1'><i class="material-icons">lock</i></button>
<!-- 公開範囲 Dropdown Structure -->
<ul id='dropdown1' class='dropdown-content'>
<li>公開範囲指定</li>
<li><a onclick="vis('public')">公開(Public)</a></li>
<li><a onclick="vis('unlisted')">未収載(Unlisted)</a></li>
<li><a onclick="vis('private')">非公開(Private)</a></li>
<li><a onclick="vis('direct')" class="disabled direct">ダイレクト(Direct)</a></li>
</ul>
</div>
<div class="col s3">
<!--絵文字ピッカー-->
<div id="emoji" class="hide shared">
<span class="gray sml">インスタンスによって実装が異なります。<i><a onclick="emojiGet('true')" class="pointer">絵文字更新</a></i><br></span>
<div id="emoji-list" class="" style="">
</div>
<div class="emoji-control center">
<button class="btn waves-effect blue" style="width:30%; padding:0;" onclick="emojiList('before')" id="emoji-before"><i class="material-icons">navigate_before</i></button>
<span id="emoji-count"></span>/<span id="emoji-sum"></span>
<button class="btn waves-effect blue" style="width:30%; padding:0;" onclick="emojiList('next')" id="emoji-next"><i class="material-icons">navigate_next</i></button>
</div>
</div>
<button class="btn waves-effect more-show pink" style="width:100%; padding:0; margin-top:0;" onclick="emoji()"><i class="material-icons" title="絵文字挿入">add</i></button>
</div>
<div class="col s3">
<button class="btn waves-effect more-show blue darken-3" style="width:100%; padding:0; margin-top:0;" onclick="nsfw()" id="nsfw" title="画像に制限を付与(青:OFF)"><i class="material-icons">photo</i><i class="material-icons" id="nsi">lock_open</i></button>
</div>
<div class="col s12">
<button class="btn waves-effect more-show orange" style="width:100%; padding:0; margin-top:0;" onclick="less()">閉じる</button>
</div>
</div>
</div>
<!--最小化-->
<div class="fixed-action-btn horizontal" id="menu-btn" onclick="show()">
<a class="btn-floating btn-large red">
<i class="large material-icons">mode_edit</i>
</a>
</div>
</div>
<!-- Modal Structure Image-->
<div id="imagemodal" class="modal modal-fixed-footer" style="margin-top:-10%">
<div class="modal-content">
<div id="imagewrap">
<img src="" id="imgmodal">
</div><br>
</div>
<div class="modal-footer">
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
<button class="btn waves-effect orange" onclick="imgCont('prev')" id="image-prev"></button>
<button class="btn waves-effect" onclick="zoom(2)">2x</button>
<button class="btn waves-effect" onclick="zoom(0.5)">0.5x</button>
<button class="btn waves-effect orange" onclick="imgCont('next')" id="image-next"></button>
</div>
</div>
<!-- Modal Structure Video-->
<div id="videomodal" class="modal modal-fixed-footer">
<div class="modal-content">
<video src="" id="video" style="width:100%;" controls >
</div>
<div class="modal-footer">
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
</div>
</div>
<!-- Modal Structure Tootdata-->
<div id="tootmodal" class="modal modal-fixed-footer">
<div class="modal-content">
<ul class="collapsible" data-collapsible="accordion">
<li>
<div class="collapsible-header"><i class="material-icons">arrow_upward</i>これよりあとのコンテクスト</div>
<div class="collapsible-body toot-reset" id="toot-after"></div>
</li>
<li>
<div class="collapsible-header"><i class="material-icons">reply_all</i>このトゥートからのリプライ</div>
<div class="collapsible-body toot-reset" id="toot-reply"></div>
</li>
<li>
<div class="collapsible-header active"><i class="material-icons">more_horiz</i>対象のトゥート</div>
<div class="collapsible-body toot-reset" id="toot-this"></div>
</li>
<li>
<div class="collapsible-header"><i class="material-icons">arrow_downward</i>これより前のLocal TL</div>
<div class="collapsible-body toot-reset" id="toot-before"></div>
</li>
<li>
<div class="collapsible-header"><i class="material-icons">star</i>このトゥートをお気に入りに登録した人</div>
<div class="collapsible-body toot-reset" id="toot-fav"></div>
</li>
<li>
<div class="collapsible-header"><i class="text-darken-3 fa fa-retweet"></i>このトゥートをブーストした人</div>
<div class="collapsible-body toot-reset" id="toot-rt"></div>
</li>
</ul>
<div id="toot-tools">
</div>
<div id="toot-after"></div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
</div>
</div>
<!-- Modal Structure Userdata -->
<div id="his-data" class="modal bottom-sheet modal-fixed-footer" style="max-height:750px; height:90%;">
<div id="his-data-content" class="modal-content" style="padding-bottom: 0;overflow-y:hidden;">
<div id="his-data-show">
<img src="./img/loading.svg" id="his-prof" style="">
<div class="his-float">
<span id="his-name" style="font-size:200%">Loading...</span><br>
@<span id="his-acct"></span>
<span class="gray" id="his-relation"></span><br>
<span class="cbadge"><span id="his-sta"></span>トゥート</span><span class="cbadge">フォロー:<span id="his-follow"></span></span>
<span class="cbadge">フォロワー:<span id="his-follower"></span></span><span class="cbadge">Since:<span id="his-since"></span>
</div>
<div class="his-float">
<span id="his-des"></span><br>
</div>
<div class="row">
<div class="col s12"id="his-data-nav">
<ul class="tabs">
<li class="tab col s4"><a href="#his-tl">Timeline</a></li>
<li class="tab col s4"><a href="#his-follow-list">Follows</a></li>
<li class="tab col s4"><a href="#his-follower-list">Followers</a></li>
</ul>
</div>
<div class="col s12" id="my-data-nav" style="display:none;">
<ul class="tabs">
<li class="tab col my-data-width"><a href="#his-tl">Timeline</a></li>
<li class="tab col my-data-width"><a href="#his-follow-list">Follows</a></li>
<li class="tab col my-data-width"><a href="#his-follower-list">Followers</a></li>
<li class="tab col my-data-width"><a href="#his-fav-list">Favorites</a></li>
<li class="tab col my-data-width"><a href="#his-blocking-list">Blocking</a></li>
<li class="tab col my-data-width"><a href="#his-muting-list">Muting</a></li>
<li class="tab col my-data-width"><a href="#his-domain-list">Domain Blocking</a></li>
<li class="tab col my-data-width"><a href="#his-prof-list">Edit Profile</a></li>
<li class="tab col my-data-width"><a href="#his-request-list">Follow Request</a></li>
</ul>
</div>
<div id="his-tl" class="col s12 tab-content"> <div id="his-tl-contents" class="cont-series"></div><button class="btn waves-effect " style="width:100%; padding:0;" onclick="utl('--now','more')">もっと</button></div>
<div id="his-follow-list" class="col s12 tab-content"> <div id="his-follow-list-contents" class="cont-series"></div><button class="btn waves-effect " style="width:100%; padding:0;" onclick="flw('--now','more')">もっと</button></div>
<div id="his-follower-list" class="col s12 tab-content"><div id="his-follower-list-contents" class="cont-series"></div><button class="btn waves-effect " style="width:100%; padding:0;" onclick="fer('--now','more')">もっと</button></div>
<div id="his-fav-list" class="col s12 tab-content"><div id="his-fav-list-contents" class="cont-series"></div><button class="btn waves-effect" style="width:100%; padding:0;" onclick="showFav('more')">もっと</button></div>
<div id="his-blocking-list" class="col s12 tab-content"><div id="his-blocking-list-contents"class="cont-series" ></div><button class="btn waves-effect " style="width:100%; padding:0;" onclick="showBlo('more')">もっと</button></div>
<div id="his-muting-list" class="col s12 tab-content"><div id="his-muting-list-contents" class="cont-series"></div><button class="btn waves-effect " style="width:100%; padding:0;" onclick="showMut('more')">もっと</button></div>
<div id="his-domain-list" class="col s12 tab-content">
<div id="his-domain-list-contents" class="cont-series"></div>
<button class="btn waves-effect " style="width:100%; padding:0;" onclick="showDom('more')">もっと</button>
ブロックするドメイン<br><input type="text" placeholder="example.com" id="domainblock"><button class="btn waves-effect" onclick="addDomainblock()">ブロック</button><br>
</div>
<div id="his-prof-list" class="col s12 tab-content">
名前<br>
<input type="text" placeholder="名前" id="his-name-val" width="max-width:150px;"><br>
自己紹介<br>
<div class="input-field col s12">
<textarea placeholder="自己紹介" id="his-des-val" class="materialize-textarea"></textarea>
<label for="his-des-val">自己紹介</label>
</div>
<button onclick="profedit()" class="btn waves-effect indigo">適用</button><br><br>
プロフィール画像変更:<span id="prof-change"><input type="file" onchange="imgChange(this,'avatar')"></span><br>
ヘッダー画像変更:<span id="header-change"><input type="file" onchange="imgChange(this,'header')"></span>
</div>
<div id="his-request-list" class="col s12 tab-content"><div id="his-request-list-contents" class="cont-series"></div><button class="btn waves-effect " style="width:100%; padding:0;" onclick="showReq('more')">もっと</button></div>
</div>
</div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-action waves-effect waves-green btn-flat" id="his-follow-btn" onclick="follow()">フォロー</a>
<a href="#!" class="modal-action waves-effect waves-green btn-flat" id="his-mute-btn" onclick="mute()">ミュート</a>
<a href="#!" class="modal-action waves-effect waves-green btn-flat" id="his-block-btn" onclick="block()">ブロック</a>
<a href="#!" class="modal-action waves-effect waves-green btn-flat" onclick="hisclose()">Close</a>
</div>
</div>
<!--左下メッセージ-->
<div id="message"></div>
<script type="text/javascript" src="./js/common/about.js"></script>
<script type="text/javascript" src="./js/tl/parse.js"></script>
<script type="text/javascript" src="./js/ui/scroll.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/date.js"></script>
<script type="text/javascript" src="./js/tl/notification.js"></script>
<script type="text/javascript" src="./js/tl/datails.js"></script>
<script type="text/javascript" src="./js/tl/mix.js"></script>
<script type="text/javascript" src="./js/tl/src.js"></script>
<script type="text/javascript" src="./js/ui/layout.js"></script>
<script type="text/javascript" src="./js/login/login.js"></script>
<script type="text/javascript" src="./js/ui/post-box.js"></script>
<script type="text/javascript" src="./js/ui/img.js"></script>
<script type="text/javascript" src="./js/ui/theme.js"></script>
<script type="text/javascript" src="./js/post/post.js"></script>
<script type="text/javascript" src="./js/post/reply.js"></script>
<script type="text/javascript" src="./js/post/secure.js"></script>
<script type="text/javascript" src="./js/post/img.js"></script>
<script type="text/javascript" src="./js/post/status.js"></script>
<script type="text/javascript" src="./js/post/emoji.js"></script>
<script type="text/javascript" src="./js/post/suggest.js"></script>
<script type="text/javascript" src="./js/post/bb-md.js"></script>
<script type="text/javascript" src="./js/userdata/showOnTL.js"></script>
<script type="text/javascript" src="./js/userdata/his-data.js"></script>
<script type="text/javascript" src="./js/userdata/prof-edit.js"></script>
<script type="text/javascript" src="./js/platform/end.js"></script>

6
js/common/about.js Normal file
View File

@ -0,0 +1,6 @@
//このソフトについて
function about() {
var electron = require("electron");
var ipc = electron.ipcRenderer;
ipc.send('about', 'go');
}

7
js/common/hammer.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
js/common/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

101
js/common/keyshortcut.js Normal file
View File

@ -0,0 +1,101 @@
$(function($) {
//キーボードショートカット
$(window).keydown(function(e) {
var hasFocus = $('input').is(':focus');
var hasFocus2 = $('textarea').is(':focus');
//Ctrl+Enter:投稿
if (event.ctrlKey) {
if (e.keyCode === 13) {
post();
return false;
}
}
//input/textareaにフォーカスなし時
if (!hasFocus && !hasFocus2) {
//X:開閉
if (e.keyCode === 88) {
if ($("#post-box").hasClass("hidenbox")) {
show();
$('textarea').focus();
} else {
hide();
}
return false;
}
//N:新トゥート
if (e.keyCode === 78) {
if ($("#post-box").hasClass("hidenbox")) {
show();
}
$('textarea').focus();
return false;
}
//E:拡張On/Off
if (e.keyCode === 69) {
zoomBox();
return false;
}
//Ctrl+Space:読み込み
if (event.ctrlKey) {
if (e.keyCode === 32) {
parseColumn();
return false;
}
}
//Sift+C:全消し
if (event.shiftKey) {
if (e.keyCode === 67) {
clear();
return false;
}
}
}
//textareaフォーカス時
if (hasFocus2) {
if (event.ctrlKey) {
//Ctrl+B:太字
if (e.keyCode === 66) {
tagsel('b');
return false;
}
//Ctrl+I:斜字
if (e.keyCode === 73) {
tagsel('i');
return false;
}
//Ctrl+U:下線
if (e.keyCode === 85) {
tagsel('u');
return false;
}
//Ctrl+S:取り消し線
if (e.keyCode === 83) {
tagsel('s');
return false;
}
}
//F5:スーパーリロード?
if (e.keyCode === 116) {
location.href = "index.html"
return false;
}
}
//37,39
if (e.keyCode === 37) {
if($("#imagemodal").hasClass("open")){
imgCont('prev');
return false;
}
}
if (e.keyCode === 39) {
if($("#imagemodal").hasClass("open")){
imgCont('next');
return false;
}
}
});
//クリアボタン
$("#clear").click(function() {
clear();
});
});

10021
js/common/materialize.js vendored Normal file

File diff suppressed because it is too large Load Diff

6
js/common/materialize.min.js vendored Normal file

File diff suppressed because one or more lines are too long

18
js/common/modal.js Normal file
View File

@ -0,0 +1,18 @@
//モーダル・ドロップダウンの各種設定
$(document).ready(function(){
// the "href" attribute of the modal trigger must specify the modal ID that wants to be triggered
$('.modal').modal();
$('.dropdown-button').dropdown({
inDuration: 300,
outDuration: 225,
constrainWidth: false, // Does not change width of dropdown to that of the activator
hover: true, // Activate on hover
gutter: 0, // Spacing from edge
belowOrigin: false, // Displays dropdown below the button
alignment: 'left', // Displays dropdown with edge aligned to the left of button
stopPropagation: false // Stops event propagation
}
);
});

232
js/common/time.js Normal file
View File

@ -0,0 +1,232 @@
/**
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* @name timeago
* @version 1.6.1
* @requires jQuery v1.2.3+
* @author Ryan McGeary
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Copyright (c) 2008-2017, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowPast: true,
allowFuture: false,
localeTitle: false,
cutoff: 0,
autoDispose: true,
strings: {
prefixAgo: null,
prefixFromNow: "今から",
suffixAgo: "",
suffixFromNow: "",
inPast: '',
seconds: "%d秒前",
minute: "1分前",
minutes: "%d分前",
hour: "1時間前",
hours: "%d時間前",
day: "昨日",
days: "%d日前",
month: "昨月",
months: "%dヶ月前",
year: "去年",
years: "%d年前",
wordSeparator: " ",
numbers: []
}
},
inWords: function(distanceMillis) {
if (!this.settings.allowPast && ! this.settings.allowFuture) {
throw 'timeago allowPast and allowFuture settings can not both be set to false.';
}
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}
if (!this.settings.allowPast && distanceMillis >= 0) {
return this.settings.strings.inPast;
}
var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 42 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.round(days)) ||
days < 45 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
years < 1.5 && substitute($l.year, 1) ||
substitute($l.years, Math.round(years));
var separator = $l.wordSeparator || "";
if ($l.wordSeparator === undefined) { separator = " "; }
return $.trim([prefix, words, suffix].join(separator));
},
parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
return new Date(s);
},
datetime: function(elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
}
});
// functions that can be called via $(el).timeago('action')
// init is default when no action is given
// functions are called with context of a single element
var functions = {
init: function() {
functions.dispose.call(this);
var refresh_el = $.proxy(refresh, this);
refresh_el();
var $s = $t.settings;
if ($s.refreshMillis > 0) {
this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
}
},
update: function(timestamp) {
var date = (timestamp instanceof Date) ? timestamp : $t.parse(timestamp);
$(this).data('timeago', { datetime: date });
if ($t.settings.localeTitle) {
$(this).attr("title", date.toLocaleString());
}
refresh.apply(this);
},
updateFromDOM: function() {
$(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
refresh.apply(this);
},
dispose: function () {
if (this._timeagoInterval) {
window.clearInterval(this._timeagoInterval);
this._timeagoInterval = null;
}
}
};
$.fn.timeago = function(action, options) {
var fn = action ? functions[action] : functions.init;
if (!fn) {
throw new Error("Unknown function name '"+ action +"' for timeago");
}
// each over objects here and call the requested function
this.each(function() {
fn.call(this, options);
});
return this;
};
function refresh() {
var $s = $t.settings;
//check if it's still visible
if ($s.autoDispose && !$.contains(document.documentElement,this)) {
//stop if it has been removed
$(this).timeago("dispose");
return this;
}
var data = prepareData(this);
if (!isNaN(data.datetime)) {
if ( $s.cutoff === 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
$(this).text(inWords(data.datetime));
} else {
if ($(this).attr('title').length > 0) {
$(this).text($(this).attr('title'));
}
}
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if ($t.settings.localeTitle) {
element.attr("title", element.data('timeago').datetime.toLocaleString());
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}));

25
js/common/version.js Normal file
View File

@ -0,0 +1,25 @@
//バージョンチェッカー
function verck(ver) {
localStorage.setItem("ver", ver);
var start = "https://desk.cutls.com/ver.json";
fetch(start, {
method: 'GET'
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(mess) {
console.log(mess);
if (mess) {
if (mess.desk == ver) {
todo("お使いのバージョン" + mess.desk + "は最新です。");
//betaならアプデチェックしない
} else if (ver != "beta") {
var electron = require("electron");
var ipc = electron.ipcRenderer;
ipc.send('update', "true");
}
}
});
}

247
js/login/login.js Normal file
View File

@ -0,0 +1,247 @@
/*ログイン処理・認証までのJS*/
//最初に読むやつ
function ck() {
var domain = localStorage.getItem("domain_0");
var at = localStorage.getItem(domain + "_at");
if (at) {
ckdb();
$("#tl").show();
parseColumn();
multi();
} else {
$("#masara").show();
console.log("Please Login");
support();
}
}
ck();
//ログインポップアップ
function login(url) {
var start = "https://" + url + "/api/v1/apps";
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
scopes: 'read write follow',
client_name: "TheDesk(PC)",
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
website: "https://desk.cutls.com"
})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var auth = "https://" + url + "/oauth/authorize?client_id=" + json[
"client_id"] + "&client_secret=" + json["client_secret"] +
"&response_type=code&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=read+write+follow";
localStorage.setItem("domain_" + acct_id, url);
localStorage.setItem("client_id", json["client_id"]);
localStorage.setItem("client_secret", json["client_secret"]);
$("#auth").show();
$("#masara").hide();
window.open(auth);
});
}
//テキストボックスにURL入れた
function instance() {
var url = $("#url").val();
login(url);
}
//コードを入れた後認証
function code() {
var code = $("#code").val();
var url = localStorage.getItem("domain_" + acct_id);
var start = "https://" + url + "/oauth/token";
var id = localStorage.getItem("client_id");
var secret = localStorage.getItem("client_secret");
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
grant_type: "authorization_code",
redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
client_id: id,
client_secret: secret,
code: code
})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
if (json["access_token"]) {
localStorage.setItem(url + "_at", json["access_token"]);
getdata();
}
});
}
//名前とか@とか取得
function getdata() {
var acct_id = 0;
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/verify_credentials";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
if (json.error) {
console.error("Error:" + json.error);
Materialize.toast("エラーが発生しました。しばらく待ってから再起動してください。Error:" + json.error,
5000);
return;
}
var obj = [{
at: at,
name: json["display_name"],
domain: domain,
user: json["acct"],
prof: json["avatar"]
}];
var json = JSON.stringify(obj);
console.log(obj);
localStorage.setItem("multi", json);
localStorage.setItem("name_" + acct_id, json["display_name"]);
localStorage.setItem("user_" + acct_id, json["acct"]);
localStorage.setItem("user-id_" + acct_id, json["id"]);
localStorage.setItem("prof_" + acct_id, json["avatar"]);
$("#my-prof").attr("src", json["avatar"]);
$("#auth").hide();
$("#tl").show();
parseColumn()
ckdb();
});
}
//TheDesk独自のマストドンDBでMarkdownやBBCodeの対応、文字数制限をチェック
function ckdb() {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var bbcode = domain + "_bbcode";
var letters = domain + "_letters";
var start = "https://desk.cutls.com/mastodon_data.json";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json'
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
console.log(json[letters]);
if (json[bbcode]) {
if (json[bbcode] == "enabled") {
} else {
$("[data-activates='bbcode']").addClass("disabled");
$("[data-activates='bbcode']").prop("disabled", true);
}
} else {
$("[data-activates='bbcode']").addClass("disabled");
$("[data-activates='bbcode']").addClass("disabled", true);
}
if (json[letters]) {
$("#textarea").attr("data-length", json[letters]);
} else {}
if (json[domain + "_markdown"] == "enabled") {
$(".markdown").show();
}
});
}
//サポートインスタンス取得
function support() {
var start = "https://desk.cutls.com/mastodon_data.json";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json'
},
//body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
Object.keys(json).forEach(function(key) {
var instance = json[key];
if (instance == "instance") {
templete = '<button class="btn waves-effect" onclick="login(\'' + key +
'\')">' + json[key + "_name"] + '(' + key + ')</button>';
$("#support").append(templete);
}
});
});
}
//アカウントを選択…を実装
function multi() {
var multi = localStorage.getItem("multi");
if (!multi) {
var obj = [{
at: localStorage.getItem(localStorage.getItem("domain_" + acct_id) + "_at"),
name: localStorage.getItem("name_" + acct_id),
domain: localStorage.getItem("domain_" + acct_id),
user: localStorage.getItem("user_" + acct_id),
prof: localStorage.getItem("prof_" + acct_id)
}];
var json = JSON.stringify(obj);
localStorage.setItem("multi", json);
} else {
var obj = JSON.parse(multi);
}
var templete;
var last = localStorage.getItem("last-use");
var sel;
Object.keys(obj).forEach(function(key) {
var acct = obj[key];
var list = key * 1 + 1;
if (key == last) {
sel = "selected";
} else {
sel = "";
}
templete = '<option value="' + key + '" data-icon="' + acct.prof +
'" class="left circle" ' + sel + '>' + acct.user + '@' + acct.domain +
'</option>';
$(".acct-sel").append(templete);
$('select').material_select('update');
});
}
//現在使用停止(Uzukiより前)
function multiLogin(target) {
var multi = localStorage.getItem("multi");
var obj = JSON.parse(multi);
var acct = obj[target];
localStorage.setItem("domain_" + target, acct.domain);
localStorage.setItem(domain + "_at", acct.at);
localStorage.setItem("acct", target);
location.href = "index.html";
}

7
js/login/logout.js Normal file
View File

@ -0,0 +1,7 @@
//ログアウトします
function logout(){
localStorage.removeItem(localStorage.getItem("domain_"+acct_id)+"_at");
localStorage.removeItem("domain_"+acct_id);
location.href="index.html";
todc();
}

298
js/login/manager.js Normal file
View File

@ -0,0 +1,298 @@
//アカウントマネージャ
//最初に読むやつ
function load() {
$("#acct-list").html("");
var prof = localStorage.getItem("prof");
$(".my-prof").attr("src", prof);
var name = localStorage.getItem("name");
$("#now-name").text(name);
var user = localStorage.getItem("user");
$("#now-user").text(user);
var domain = localStorage.getItem("domain");
$(".now-domain").text(domain);
var multi = localStorage.getItem("multi");
if (!multi) {
var obj = [{
at: localStorage.getItem(localStorage.getItem("domain_0") + "_at"),
name: localStorage.getItem("name_0"),
domain: localStorage.getItem("domain_0"),
user: localStorage.getItem("user_0"),
prof: localStorage.getItem("prof_0"),
id: localStorage.getItem("user-id_0")
}];
var json = JSON.stringify(obj);
localStorage.setItem("multi", json);
} else {
var obj = JSON.parse(multi);
}
console.log(obj);
var templete;
Object.keys(obj).forEach(function(key) {
var acct = obj[key];
var list = key * 1 + 1;
templete = '<div class="acct" id="acct_' + key + '">' + list +
'.<img src="' + acct.prof + '" width="40" height="40"><div class="text">' +
acct.name + '&nbsp;<span class="gray">' + acct.user + '@' + acct.domain +
'</span></div><button class="btn waves-effect disTar" onclick="data(\'' +
acct.domain +
'\')">インスタンスデータ表示</button><button class="btn waves-effect" onclick="refresh(' +
key +
')">情報更新</button><button class="btn waves-effect red disTar" onclick="multiDel(' +
key + ')">削除</button><br></div>';
$("#acct-list").append(templete);
});
var acctN = localStorage.getItem("acct");
if (!acctN) {
localStorage.setItem("acct", 0);
var acctN = 0;
}
}
//最初に読む
load();
support();
//instances.social
function data(domain) {
$("#ins-upd").text("Loading...");
$("#ins-add").text("Loading...");
$("#ins-connect").text("Loading...");
$("#ins-toot").text("Loading...");
$("#ins-sys").text("Loading...");
$("#ins-per").text("Loading...");
$("#ins-user").text("Loading...");
$("#ins-ver").text("Loading...");
$("#ins-prof").attr('src', "./img/loading.svg");
var start = "https://instances.social/api/1.0/instances/show?name=" + domain;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer tC8F6xWGWBUwGScyNevYlx62iO6fdQ4oIK0ad68Oo7ZKB8GQdGpjW9TKxBnIh8grAhvd5rw3iyP9JPamoDpeLQdz62EToPJUW99hDx8rfuJfGdjQuimZPTbIOx0woA5M'
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
if (!json.error) {
$("#ins-upd").text(date(json.checked_at, 'full'));
$("#ins-add").text(date(json.added_at, 'full'));
$("#ins-connect").text(json.connections);
$("#ins-toot").text(json.statuses);
$("#ins-sys").text(date(json.updated_at, 'full'));
$("#ins-per").text(json.uptime * 100);
$("#ins-user").text(json.users);
$("#ins-ver").text(json.version);
$("#ins-prof").attr('src', json.thumbnail);
}
});
}
//アカウントデータ 消す
function multiDel(target) {
var multi = localStorage.getItem("multi");
var obj = JSON.parse(multi);
if (confirm(obj[target]["user"] + "@" + obj[target]["domain"] + "を削除します")) {
obj.splice(target, 1);
var json = JSON.stringify(obj);
localStorage.setItem("multi", json);
load();
}
}
//サポートインスタンス
function support() {
var start = "https://desk.cutls.com/mastodon_data.json";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json'
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
Object.keys(json).forEach(function(key) {
var instance = json[key];
if (instance == "instance") {
templete = '<button class="btn waves-effect" onclick="login(\'' + key +
'\')">' + json[key + "_name"] + '(' + key + ')</button>';
$("#support").append(templete);
}
});
});
}
//URL指定してポップアップ
function login(url) {
var multi = localStorage.getItem("multi");
var obj = JSON.parse(multi);
var ng;
Object.keys(obj).forEach(function(key) {
var acct = obj[key];
if (acct.domain == url) {
Materialize.toast(url + "は登録できません。同一インスタンスには一つのアカウントでしかログインできません。", 5000);
ng = "true";
return;
}
});
if (ng) {
return;
}
var start = "https://" + url + "/api/v1/apps";
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
scopes: 'read write follow',
client_name: "TheDesk(PC)",
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
website: "https://desk.cutls.com"
})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var auth = "https://" + url + "/oauth/authorize?client_id=" + json[
"client_id"] + "&client_secret=" + json["client_secret"] +
"&response_type=code&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=read+write+follow";
localStorage.setItem("domain_tmp", url);
localStorage.setItem("client_id", json["client_id"]);
localStorage.setItem("client_secret", json["client_secret"]);
$("#auth").show();
$("#add").hide();
window.open(auth);
});
}
//テキストボックスにURL入れた
function instance() {
var url = $("#url").val();
login(url);
}
//コード入れてAccessTokenゲット
function code() {
var code = $("#code").val();
var url = localStorage.getItem("domain_tmp");
localStorage.removeItem("domain_tmp");
var start = "https://" + url + "/oauth/token";
var id = localStorage.getItem("client_id");
var secret = localStorage.getItem("client_secret");
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
grant_type: "authorization_code",
redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
client_id: id,
client_secret: secret,
code: code
})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
if (json["access_token"]) {
$("#auth").hide();
$("#add").show();
getdata(url, json["access_token"]);
}
});
}
//ユーザーデータ取得
function getdata(domain, at) {
var start = "https://" + domain + "/api/v1/accounts/verify_credentials";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
if (json.error) {
console.error("Error:" + json.error);
Materialize.toast("エラーが発生しました。しばらく待ってから再起動してください。Error:" + json.error,
5000);
return;
}
var add = {
at: at,
name: json["display_name"],
domain: domain,
user: json["acct"],
prof: json["avatar"],
id: json["id"]
};
var multi = localStorage.getItem("multi");
var obj = JSON.parse(multi);
obj.push(add);
console.log(obj);
var json = JSON.stringify(obj);
localStorage.setItem("multi", json);
load();
});
}
//ユーザーデータ更新
function refresh(target) {
var multi = localStorage.getItem("multi");
var obj = JSON.parse(multi);
var start = "https://" + obj[target].domain +
"/api/v1/accounts/verify_credentials";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + obj[target].at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
if (json.error) {
console.error("Error:" + json.error);
Materialize.toast("エラーが発生しました。しばらく待ってから再起動してください。Error:" + json.error,
5000);
return;
}
var ref = {
at: obj[target].at,
name: json["display_name"],
domain: obj[target].domain,
user: json["acct"],
prof: json["avatar"],
id: json["id"]
};
obj[target] = ref;
console.log(obj);
var json = JSON.stringify(obj);
localStorage.setItem("multi", json);
load();
});
}

67
js/platform/end.js Normal file
View File

@ -0,0 +1,67 @@
//プラットフォーム別 最後に読むやつ
//リンクを外部で開くか内部で出すか
$(document).on('click', 'a', e => {
var $a = $(e.target);
var url = $a.attr('href');
if (!url) {
var url = $a.parent().attr('href');
}
var urls = url.match(/https?:\/\/([-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)/);
//hrefがhttp/httpsならブラウザで
if (urls[0]) {
const {
shell
} = require('electron');
shell.openExternal(url);
} else {
location.href = url;
}
return false;
});
//よく使うライブラリ
/*マルチバイト用切り出し*/
$.isSurrogatePear = function(upper, lower) {
return 0xD800 <= upper && upper <= 0xDBFF && 0xDC00 <= lower && lower <=
0xDFFF;
};
$.mb_strlen = function(str) {
var ret = 0;
for (var i = 0; i < str.length; i++, ret++) {
var upper = str.charCodeAt(i);
var lower = str.length > (i + 1) ? str.charCodeAt(i + 1) : 0;
if ($.isSurrogatePear(upper, lower)) {
i++;
}
}
return ret;
};
$.mb_substr = function(str, begin, end) {
var ret = '';
for (var i = 0, len = 0; i < str.length; i++, len++) {
var upper = str.charCodeAt(i);
var lower = str.length > (i + 1) ? str.charCodeAt(i + 1) : 0;
var s = '';
if ($.isSurrogatePear(upper, lower)) {
i++;
s = String.fromCharCode(upper, lower);
} else {
s = String.fromCharCode(upper);
}
if (begin <= len && len < end) {
ret += s;
}
}
return ret;
};
$.strip_tags = function(str, allowed) {
allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || [])
.join('');
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
return str.replace(commentsAndPhpTags, '').replace(tags, function($0, $1) {
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
};

3
js/platform/first.js Normal file
View File

@ -0,0 +1,3 @@
//jQuery読む
window.jQuery = window.$ = require('./js/common/jquery.js');
var Hammer = require('./js/common/hammer.min.js');

194
js/post/bb-md.js Normal file
View File

@ -0,0 +1,194 @@
//BBCodeとMarkdownの入力・パーサー
//BOXのトグルボタン
function mdToggle(){
$(".markdown").toggleClass("hide");
$(".anti-markdown").toggleClass("hide");
if($(".markdown").hasClass("hide")){
localStorage.setItem("md","hide");
}else{
localStorage.removeItem("md");
}
}
//最初に読み込みます(MD対応インスタンスかチェック)
if(localStorage.getItem("md")=="hide"){
$(".markdown").addClass("hide");
$(".anti-markdown").removeClass("hide");
}
//タグを選んだ時に(BB版)
function tagsel(tag){
if(tag=="large" || tag=="size" || tag=="color" || tag=="colorhex"){
var sub=$("#"+tag).val();
var sub = sub.replace( /#/g , "" ) ;
surroundHTML(tag+"="+sub,tag);
}else if(tag=="flip=vertical" || tag=="flip=horizontal"){
surroundHTML(tag,"flip");
}else{
surroundHTML(tag,tag);
}
$("#textarea").focus();
}
//HTMLをエスケープしてXSSを防ぐ
function escape_html (string) {
if(typeof string !== 'string') {
return string;
}
return string.replace(/[&'`"<>]/g, function(match) {
return {
'&': '&amp;',
"'": '&#x27;',
'`': '&#x60;',
'"': '&quot;',
'<': '&lt;',
'>': '&gt;',
}[match]
});
}
//PHPのnl2brと同様
function nl2br(str) {
str = str.replace(/\r\n/g, "<br />");
str = str.replace(/(\n|\r)/g, "<br />");
return str;
}
//テキストボックスで選択したやつをタグで囲む(BB版)
function surroundHTML(tagS,tagE) {
var target = document.getElementById("textarea");
var pos = getAreaRange(target);
var val = target.value;
var range = val.slice(pos.start, pos.end);
var beforeNode = val.slice(0, pos.start);
var afterNode = val.slice(pos.end);
var insertNode;
if (range || pos.start != pos.end) {
insertNode = '[' + tagS + ']' + range + '[/' + tagE + ']';
target.value = beforeNode + insertNode + afterNode;
}
else if (pos.start == pos.end) {
insertNode = '[' + tagS + ']' + '[/' + tagE + ']';
target.value = beforeNode + insertNode + afterNode;
}
}
function markdown(tag,ck,br){
surroundMD(tag,tag,ck);
$("#textarea").focus();
}
function surroundMD(tagS,tagE,ck,br) {
var target = document.getElementById("textarea");
var pos = getAreaRange(target);
var val = target.value;
var range = val.slice(pos.start, pos.end);
var beforeNode = val.slice(0, pos.start);
var afterNode = val.slice(pos.end);
var insertNode;
if(br=="yes"){
var br="\n";
}else{
var br="";
}
if ((range || pos.start != pos.end )&& ck=="yes") {
insertNode = tagS + range + tagE ;
target.value = beforeNode + insertNode + br + afterNode;
}
else if (pos.start == pos.end || ck=="no") {
insertNode = tagS + range;
target.value = beforeNode + insertNode + br + afterNode;
}
}
//テキストボックスの前後チェック
function getAreaRange(obj) {
var pos = new Object();
if(window.getSelection()) {
pos.start = obj.selectionStart;
pos.end = obj.selectionEnd;
}
return pos;
}
//Markdownのリンク挿入
function markdownLink(){
var linkIns="["+$("#linkt").val()+"]"+"("+$("#link2").val()+")";
if(linkIns!="[]()"){
$("#textarea").val($("#textarea").val()+linkIns);
$("#linkt").val("");
$("#link2").val("");
$("#textarea").focus();
}
}
//Markdownのimg挿入
function markdownImage(){
var imgIns="!["+$("#image").val()+"]"+"("+$("#image2").val()+")";
if(imgIns!="![]()"){
$("#textarea").val($("#textarea").val()+imgIns);
$("#image").val("");
$("#image2").val("");
$("#textarea").focus();
}
}
//文字数をチェック(hタグ用)
function str_count(all, part) {
return (all.match(new RegExp(part, "g")) || []).length;
}
//プレビュー
function preview(){
$("#preview-field").show();
$("#toot-field").hide();
$("#preview-btn").hide();
var bb=escape_html($("#textarea").val());
//quote
var bb=bb.replace(/>(.+)$/g,'<blockquote>$1<\/blockquote>');
//spin
var bb=bb.replace(/\[spin\](.+)\[\/spin\]/g,'<span class="fa fa-spin">$1<\/span>');
//pulse
var bb=bb.replace(/\[pulse\](.+)\[\/pulse\]/g,'<span class="bbcode-pulse-loading">$1<\/span>');
//large
var bb=bb.replace(/\[large=([0-9]{1,2})x\](.+)\[\/large\]/g,'<span class="fa fa-$1x">$2<\/span>');
//vertical
var bb=bb.replace(/\[flip=vertical\](.+)\[\/flip\]/g,'<span class="fa fa-flip-vertical">$1<\/span>');
//horizontal
var bb=bb.replace(/\[flip=horizontal\](.+)\[\/flip\]/g,'<span class="fa fa-flip-horizontal">$1<\/span>');
//b
var bb=bb.replace(/\[b\](.+)\[\/b\]/g,'<b>$1<\/b>');
//i
var bb=bb.replace(/\[i\](.+)\[\/i\]/g,'<i>$1<\/i>');
//u
var bb=bb.replace(/\[u\](.+)\[\/u\]/g,'<u>$1<\/u>');
//s
var bb=bb.replace(/\[s\](.+)\[\/s\]/g,'<s>$1<\/s>');
//size
var bb=bb.replace(/\[size=([0-9]{1,2})\](.+)\[\/size\]/g,'<span style="font-size:$1px">$2<\/span>');
//colorhex
var bb=bb.replace(/\[colorhex=([A-Fa-f0-9]+)\](.+)\[\/colorhex\]/g,'<span style="color:#$1">$2<\/span>');
//code
var bb=bb.replace(/`(.+)`/g,'<code>$1<\/code>');
//index
var m;
m=bb.match(/^#{1,6}(.+)$/gm);
if(m){
for(let i = 0; i < m.length; i++) {
var t=m[i].match(/^#{1,6}(.+)$/);
var indexct='<h'+str_count(m[i],"#")+'>'+t[1]+'</h'+str_count(m[i],"#")+'>';
var bb=bb.replace(new RegExp(m[i], ""),indexct);
}
}
//img
var bb=bb.replace(/!\[(.+)\]\((https:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)\)/g,'<img src="$2" text="$1" style="width:100%">');
//link
var bb=bb.replace(/\[(.+)\]\((https?:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)\)/g,'<a href="$2" target="_blank">$1<\/a>');
$("#md-preview").html(nl2br(bb));
}
//Editで戻る
function previewEdit(){
$("#preview-field").hide();
$("#toot-field").show();
$("#preview-btn").show();
$("#md-preview").html("");
}

114
js/post/emoji.js Normal file
View File

@ -0,0 +1,114 @@
//絵文字ピッカー
//最初に読み込む
$("#emoji-before").addClass("disabled");
$("#emoji-next").addClass("disabled");
//絵文字ボタンのトグル
function emoji() {
var acct_id = $("#post-acct-sel").val();
if ($("#emoji").hasClass("hide")) {
$("#emoji").removeClass("hide")
if (!localStorage.getItem("emoji_" + acct_id)) {
var html =
'<button class="btn waves-effect green" style="width:100%; padding:0; margin-top:0;" onclick="emojiGet(\'true\');">絵文字リスト取得</button>';
$("#emoji-list").html(html);
} else {
emojiList('home');
}
} else {
$("#emoji").addClass("hide")
}
}
//絵文字リスト挿入
function emojiGet(parse) {
$('#emoji-list').html('Loading...');
var acct_id = $("#post-acct-sel").val();
var domain = localStorage.getItem("domain_" + acct_id);
var start = "https://" + domain + "/api/v1/custom_emojis";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json'
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
if (parse == "true") {
$('#emoji-list').html('Parsing...');
//絵文字をマストドン公式と同順にソート
json.sort(function(a, b) {
if (a.shortcode < b.shortcode) return -1;
if (a.shortcode > b.shortcode) return 1;
return 0;
});
localStorage.setItem("emoji_" + acct_id, JSON.stringify(json));
} else {
localStorage.setItem("emoji_" + acct_id, JSON.stringify(json));
}
localStorage.setItem("emojiseek", 0);
emojiList('home')
});
}
//リストの描画
function emojiList(target) {
var acct_id = $("#post-acct-sel").val();
var start = localStorage.getItem("emojiseek");
if (target == "next") {
var start = start * 1 + 127;
localStorage.setItem("emojiseek", start);
} else if (target == "before") {
var start = start - 127;
localStorage.setItem("emojiseek", start);
} else {
var start = 0;
localStorage.getItem("emojiseek", 0)
}
var html = '';
var obj = JSON.parse(localStorage.getItem("emoji_" + acct_id));
var num = obj.length;
if (num < start) {
var start = 0;
localStorage.setItem("emojiseek", start);
}
var page = Math.ceil(num / 126);
$("#emoji-sum").text(page);
var ct = Math.ceil(start / 126);
if (ct == 0) {
var ct = 1;
$("#emoji-before").addClass("disabled");
} else {
$("#emoji-before").removeClass("disabled");
}
$("#emoji-next").removeClass("disabled");
$("#emoji-count").text(ct);
for (i = start; i < start + 126; i++) {
var emoji = obj[i];
if (emoji) {
html = html + '<a onclick="emojiInsert(\':' + emoji.shortcode +
':\')" class="pointer"><img src="' + emoji.url + '" width="20"></a>';
}
}
$("#emoji-list").html(html);
}
//絵文字など様々なものをテキストボックスに挿入
function emojiInsert(code, del) {
var now = $("#textarea").val();
if (!del) {
$("#textarea").val(now + " " + code);
emoji();
} else {
var regExp = new RegExp(del, "g");
var now = now.replace(now, "");
$("#textarea").val(now + " " + code);
}
$("#textarea").focus();
}

132
js/post/img.js Normal file
View File

@ -0,0 +1,132 @@
//ドラッグ・アンド・ドロップからアップロードまで。uiのimg.jsとは異なります。
var obj = $("body");
var system;
//ドラッグスタート
obj.on('dragstart', function(e) {
system = "locked"
});
//何もなくファイルが通過
obj.on('dragend', function(e) {
system = "";
});
//ドラッグファイルが画面上に
obj.on('dragenter', function(e) {
if (system != "locked") {
$("#drag").css('display', 'flex');
more();
}
});
$("body").on('dragover', function(e) {
e.stopPropagation();
e.preventDefault();
});
//ドロップした
$("body").on('drop', function(e) {
if (system != "locked") {
$("#drag").css('display', 'none');
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
pimg(files);
}
});
//何もなくファイルが通過
$("#drag").on('dragleave', function(e) {
$("#drag").css('display', 'none');
});
//複数アップ
function pimg(files) {
console.log(files);
for (i = 0; i < files.length; i++) {
handleFileUpload(files[i], obj);
}
}
//ドラッグ・アンド・ドロップを終了
function closedrop() {
$("#drag").css('display', 'none');
}
//ファイルプレビュー
function handleFileUpload(files, obj) {
var fr = new FileReader();
fr.onload = function(evt) {
var b64 = evt.target.result;
if (files["type"] == "image/png" || files["type"] == "image/jpeg" || files[
"type"] == "image/gif") {
var html = '<img src="' + b64 + '" style="width:50px; max-height:100px;">';
$('#preview').append(html);
} else {
$('#preview').append(files["name"] + "はプレビューできません");
}
$('#b64-box').val(b64);
var ret = media(b64, files["type"])
}
fr.readAsDataURL(files);
$("#mec").append(files["name"] + "/");
}
//ファイルアップロード
function media(b64, type) {
$("#toot-post-btn").prop("disabled", true);
todo("Image Upload...");
var media = toBlob(b64, type);
console.log(media);
var fd = new FormData();
fd.append('file', media);
var acct_id = $("#post-acct-sel").val();
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/media";
fetch(start, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + at
},
body: fd
}).then(function(response) {
console.log(response)
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
var img = localStorage.getItem("img");
if (!img) {
var img = "no-act";
}
if (img != "inline") {
if ($("#media").val()) {
$("#media").val($("#media").val() + ',' + json["id"]);
} else {
$("#media").val(json["id"]);
}
}
if (img == "url") {
$("#textarea").val($("#textarea").val() + " " + json["text_url"])
}
todc();
$("#toot-post-btn").prop("disabled", false);
});
}
//Base64からBlobへ
function toBlob(base64, type) {
var bin = atob(base64.replace(/^.*,/, ''));
var buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
// Blobを作成
try {
var blob = new Blob([new Uint8Array(buffer)], {
type: type
});
} catch (e) {
return false;
}
return blob;
}

97
js/post/post.js Normal file
View File

@ -0,0 +1,97 @@
/*投稿系*/
//投稿
function post() {
var str = $("#textarea").val();
var acct_id = $("#post-acct-sel").val();
localStorage.setItem("last-use", acct_id);
todo("Posting");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses";
var reply = $("#reply").val();
var media = $("#media").val();
if ($("#nsfw").hasClass("nsfw-avail")) {
var nsfw = "true";
} else {
var nsfw = "false";
}
var vis = $("#vis").text();
if ($("#cw").hasClass("cw-avail")) {
var spo = $("#cw-text").val();
} else {
var spo = "";
}
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({
status: str,
in_reply_to_id: reply,
media_ids: media.split(","),
sensitive: nsfw,
spoiler_text: spo,
visibility: vis
})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
var box = localStorage.getItem("box");
if (box == "yes") {
hide();
}
todc();
clear();
});
}
//クリア(Shift+C)
function clear() {
$("#textarea").val("");
$("#textarea").attr("placeholder", "象");
$("#reply").val("");
$("#media").val("");
var cwt = localStorage.getItem("cw-text");
if (cwt) {
$("#cw-text").val(cwt);
} else {
$("#cw-text").val("");
}
$("#cw").addClass("blue");
$("#cw").removeClass("yellow");
$("#cw").removeClass("cw-avail");
$("#rec").text("いいえ");
$("#mec").text("なし");
var vis = localStorage.getItem("vis");
if (!vis) {
$("#vis").text("public");
} else {
if (vis == "memory") {
localStorage.setItem("vis-memory", $("#vis").text());
} else {
$("#vis").text(vis);
}
}
$("#nsfw").addClass("blue");
$("#nsfw").removeClass("yellow");
$("#nsi").html("lock_open");
$("#nsfw").removeClass("nsfw-avail");
$("#nsc").text("なし");
$("#drag").css("background-color", "#e0e0e0");
$("#preview").html("");
if ($("#post-box").hasClass("post-more")) {
$("#file-wrap").html(
'<input class="more-show" style="display:inline-block;" type="file" name="pic" id="upfile" onchange="pimg(document.getElementById(\'upfile\').files);" multiple>'
);
} else {
$("#file-wrap").html(
'<input class="more-show" type="file" name="pic" id="upfile" onchange="pimg(document.getElementById(\'upfile\').files);" multiple>'
);
}
}

9
js/post/reply.js Normal file
View File

@ -0,0 +1,9 @@
/*リプライ*/
function re(id,at){
show();
$("#reply").val(id);
var te=$("#textarea").val();
$("#textarea").val("@"+at+" "+te);
$("#rec").text("はい");
$("#textarea").attr("placeholder","返信モードです。クリアするときはShift+Cを押してください。");
}

50
js/post/secure.js Normal file
View File

@ -0,0 +1,50 @@
/*保護系*/
//画像保護
function nsfw(){
if($("#nsfw").hasClass("nsfw-avail")){
$("#nsfw").addClass("blue");
$("#nsfw").removeClass("yellow");
$("#nsi").html("lock_open");
$("#nsfw").removeClass("nsfw-avail");
$("#nsc").text("なし");
}else{
$("#nsfw").removeClass("blue");
$("#nsfw").addClass("yellow");
$("#nsi").html("lock_outline");
$("#nsfw").addClass("nsfw-avail");
$("#nsc").text("あり");
}
}
//投稿公開範囲
function vis(set){
$("#vis").text(set);
var vis=localStorage.getItem("vis");
if(vis=="memory"){
localStorage.setItem("vis-memory",set);
}
}
//コンテンツワーニング
function cw(){
if($("#cw").hasClass("cw-avail")){
$("#cw-text").val();
$("#cw-text").hide();
$("#cw").addClass("blue");
$("#cw").removeClass("yellow");
$("#cw").removeClass("cw-avail");
}else{
$("#cw-text").show();
$("#cw").removeClass("blue");
$("#cw").addClass("yellow");
$("#cw").addClass("cw-avail");
var cwt=localStorage.getItem("cw-text");
if(cwt){
$("#cw-text").val(cwt);
}
}
}
//TLでコンテンツワーニングを表示トグル
function cw_show(id){
$(".cw_hide_"+id).toggleClass("cw");
}

268
js/post/status.js Normal file
View File

@ -0,0 +1,268 @@
//お気に入り登録やブースト等、フォローやブロック等
//お気に入り登録
function fav(id, acct_id) {
if ($("#pub_" + id).hasClass("faved")) {
var flag = "unfavourite";
} else {
var flag = "favourite";
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id + "/" + flag;
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
$("#pub_" + id + " .fav_ct").text(json.favourites_count);
if (!json.reblog) {
$("#pub_" + id + " .rt_ct").text(json.reblogs_count - 1);
} else {
$("#pub_" + id + " .rt_ct").text(json.reblog.reblogs_count);
}
if ($("#pub_" + id).hasClass("faved")) {
$("#pub_" + id).removeClass("faved");
$("#fav_" + id).removeClass("yellow-text");
} else {
$("#pub_" + id).addClass("faved");
$("#fav_" + id).addClass("yellow-text");
}
});
}
//ブースト
function rt(id, acct_id) {
if ($("#pub_" + id).hasClass("rted")) {
var flag = "unreblog";
} else {
var flag = "reblog";
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id + "/" + flag;
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
$("#pub_" + id + " .fav_ct").text(json.favourites_count);
if (!json.reblog) {
$("#pub_" + id + " .rt_ct").text(json.reblogs_count - 1);
} else {
$("#pub_" + id + " .rt_ct").text(json.reblog.reblogs_count);
}
if ($("#pub_" + id).hasClass("rted")) {
$("#pub_" + id).removeClass("rted");
$("#rt_" + id).removeClass("teal-text");
} else {
$("#pub_" + id).addClass("rted");
$("#rt_" + id).addClass("teal-text");
}
});
}
//フォロー
function follow(acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var id = $("#his-data").attr("user-id");
if ($("#his-data").hasClass("following")) {
var flag = "unfollow";
} else {
var flag = "follow";
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/" + id + "/" + flag;
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
if ($("#his-data").hasClass("following")) {
$("#his-data").removeClass("following");
$("#his-follow-btn").text("フォロー");
} else {
$("#his-data").addClass("following");
$("#his-follow-btn").text("フォロー解除");
}
});
}
//ブロック
function block(acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var id = $("#his-data").attr("user-id");
if ($("#his-data").hasClass("blocking")) {
var flag = "unblock";
} else {
var flag = "block";
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/" + id + "/" + flag;
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
if ($("#his-data").hasClass("blocking")) {
$("#his-data").removeClass("blocking");
$("#his-block-btn").text("ブロック");
} else {
$("#his-data").addClass("blocking");
$("#his-block-btn").text("ブロック解除");
}
});
}
//ミュート
function mute(acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var id = $("#his-data").attr("user-id");
if ($("#his-data").hasClass("muting")) {
var flag = "unmute";
} else {
var flag = "mute";
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/" + id + "/" + flag;
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
if ($("#his-data").hasClass("muting")) {
$("#his-data").removeClass("muting");
$("#his-mute-btn").text("ミュート");
} else {
$("#his-data").addClass("muting");
$("#his-mute-btn").text("ミュート解除");
}
});
}
//投稿削除
function del(id, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id;
fetch(start, {
method: 'DELETE',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
//ここで消さなくてもStreamingが消す
//$("#pub_"+id).hide();
});
}
//フォロリク
function request(id, flag, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/follow_requests/" + id + "/" + flag;
fetch(start, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
showReq();
});
}
//ドメインブロック(未実装)
function domainblock(add, flag, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/domain_blocks"
fetch(start, {
method: flag,
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({
domain: add
})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
showDom();
});
}
function addDomainblock() {
var domain = $("#domainblock").val();
domainblock(domain, 'POST');
}

70
js/post/suggest.js Normal file
View File

@ -0,0 +1,70 @@
//入力時にハッシュタグと@をサジェスト
var timer = null;
var input = document.getElementById("textarea");
var prev_val = input.value;
var oldSuggest;
var suggest;
input.addEventListener("focus", function() {
$("#suggest").html("");
window.clearInterval(timer);
timer = window.setInterval(function() {
var new_val = input.value;
if (prev_val != new_val) {
var tag = new_val.match(/#(\S{3,})/);
var acct = new_val.match(/@(\S{3,})/);
if (tag && tag[1]) {
var q = tag[1];
} else if (acct[1]) {
var q = acct[1];
} else {
return;
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
suggest = "https://" + domain + "/api/v1/search?q=" + q
if (suggest != oldSuggest) {
console.log(suggest)
fetch(suggest, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
if (json.hashtags[0] && tag[1]) {
var tags = "";
Object.keys(json.hashtags).forEach(function(key4) {
var tag = json.hashtags[key4];
tags = tags + '<a onclick="emojiInsert(\'#' + tag + '\',\'#' + q +
'\')" class="pointer">#' + tag + '</a> ';
});
$("#suggest").html("Tags:" + tags);
} else if (json.accounts[0] && acct[1]) {
var accts = "";
Object.keys(json.accounts).forEach(function(key3) {
var acct = json.accounts[key3];
accts = accts + '<a onclick="emojiInsert(\'@' + acct.acct +
'\',\'@' + q + '\')" class="pointer">@' + acct.acct + '</a> ';
});
$("#suggest").html("@:" + accts);
} else {
$("#suggest").html("Not Found");
}
});
}
};
oldSuggest = suggest;
prev_value = new_val;
}, 1000);
}, false);
input.addEventListener("blur", function() {
window.clearInterval(timer);
}, false);

72
js/tl/card.js Normal file
View File

@ -0,0 +1,72 @@
//カード処理やメンション、ハッシュタグの別途表示
//全てのTL処理で呼び出し
function additional(acct_id, tlid) {
//メンション系
$(".mention").attr("href", "#");
//トゥートサムネ
$("#timeline_" + tlid + " .toot a:not(.parsed)").each(function(i, elem) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var card = localStorage.getItem("card_" + tlid);
var text = $(this).attr('href');
var urls = text.match(
/https?:\/\/([-a-zA-Z0-9@.]+)\/media\/([-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)/
);
if (urls) {
$(this).remove();
} else if (!card) {
var id = $(this).parents('.cvo').attr("toot-id");
var start = "https://" + domain + "/api/v1/statuses/" + id + "/card";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
//body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
if (json.title) {
$("[toot-id=" + id + "] .additional").html(
"<span class=\"gray\">URLチェック:<br>Title:" + json.title + "<br>" +
json.description + "</span>");
}
if (json.html) {
$("[toot-id=" + id + "] .additional").html(json.html);
}
if (json.title) {
$("[toot-id=" + id + "] a:not(.parsed)").addClass("parsed");
$("[toot-id=" + id + "]").addClass("parsed");
}
});
}
});
}
//各TL上方のLink[On/Off]
function cardToggle(tlid) {
var card = localStorage.getItem("card_" + tlid);
if (!card) {
localStorage.setItem("card_" + tlid, "true");
$("#sta-card-" + tlid).text("Off");
} else {
localStorage.removeItem("card_" + tlid);
$("#sta-card-" + tlid).text("On");
}
}
//各TL上方のLink[On/Off]をチェック
function cardCheck(tlid) {
var card = localStorage.getItem("card_" + tlid);
if (!card) {
$("#sta-card-" + tlid).text("On");
} else {
$("#sta-card-" + tlid).text("Off");
}
}

149
js/tl/datails.js Normal file
View File

@ -0,0 +1,149 @@
//トゥートの詳細
function details(id, acct_id) {
$(".toot-reset").html("トゥートはありません");
var html = $("#pub_" + id).html();
$("#toot-this").html(html);
$('#tootmodal').modal('open');
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
$("#toot-this .fav_ct").text(json.favourites_count);
$("#toot-this .rt_ct").text(json.reblogs_count);
if (json.in_reply_to_id) {
replyTL(json.in_reply_to_id, acct_id);
}
context(id, acct_id);
faved(id, acct_id);
rted(id, acct_id);
});
}
//返信タイムライン
function replyTL(id, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse([json]);
$("#toot-reply").prepend(templete);
jQuery("time.timeago").timeago();
if (json.in_reply_to_id) {
replyTL(json.in_reply_to_id, acct_id);
}
});
}
//コンテクストってなんですか
function context(id, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id + "/context";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse(json.descendants);
$("#toot-after").html(templete);
beforeToot(id, acct_id);
jQuery("time.timeago").timeago();
});
}
//前のトゥート(Back TL)
function beforeToot(id, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain +
"/api/v1/timelines/public?local=true&max_id=" + id;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse(json);
$("#toot-before").html(templete);
jQuery("time.timeago").timeago();
});
}
//ふぁぼ一覧
function faved(id, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id + "/favourited_by";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = userparse(json);
$("#toot-fav").html(templete);
});
}
//ブースト一覧
function rted(id, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/statuses/" + id + "/reblogged_by";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = userparse(json);
$("#toot-rt").html(templete);
});
}

69
js/tl/date.js Normal file
View File

@ -0,0 +1,69 @@
//日付パーサー
function date(str, datetype) {
if (datetype == "relative") {
return '<time class="timeago" datetime="' + str + '"></time>';
} else {
var date = new Date(str);
if (datetype == "unix") {
var unixm = date.getTime();
return Math.floor(unixm / 1000);
}
var now = new Date();
var month = date.getMonth() + 1;
if (date.getMinutes() < 10) {
var min = "0" + date.getMinutes();
} else {
var min = date.getMinutes();
}
if (date.getSeconds() < 10) {
var sec = "0" + date.getSeconds();
} else {
var sec = date.getSeconds();
}
if (datetype == "full") {
var ret = date.getFullYear() + "年" + month + "月" + date.getDate() + "日 " +
date.getHours() + ":" + min + ":" + sec;
}
if (date.getFullYear() == now.getFullYear()) {
if (date.getMonth() == now.getMonth()) {
if (date.getDate() == now.getDate()) {
if (datetype == "medium") {
var ret = '<time class="timeago" datetime="' + str + '"></time>';
} else {
var ret = date.getHours() + ":" + min + ":" + sec;
}
} else {
var ret = month + "月" + date.getDate() + "日 " + date.getHours() + ":" +
min + ":" + sec;
}
} else {
var ret = month + "月" + date.getDate() + "日 " + date.getHours() + ":" + min +
":" + sec;
}
} else {
var ret = date.getFullYear() + "年" + month + "月" + date.getDate() + "日 " +
date.getHours() + ":" + min + ":" + sec;
}
if (datetype == "double") {
return '<time class="timeago" datetime="' + str + '"></time>/' + ret;
} else {
return ret;
}
}
}
//特殊フォーマット(インスタンス情報で利用)
function crat(str) {
var date = new Date(str);
format_str = 'YYYY-MM-DD hh:mm:ss';
format_str = format_str.replace(/YYYY/g, date.getFullYear());
format_str = format_str.replace(/MM/g, date.getMonth());
format_str = format_str.replace(/DD/g, date.getDate());
format_str = format_str.replace(/hh/g, date.getHours());
format_str = format_str.replace(/mm/g, date.getMinutes());
format_str = format_str.replace(/ss/g, date.getSeconds());
return format_str;
}

231
js/tl/mix.js Normal file
View File

@ -0,0 +1,231 @@
//Integrated TL
function mixtl(acct_id, tlid) {
var type = "mix";
localStorage.removeItem("morelock")
$("#notice_" + tlid).text("Integrated TL");
localStorage.setItem("now", type);
todo("Integrated TL Loading...(Local)");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
//まずLocal
var start = "https://" + domain + "/api/v1/timelines/public?local=true";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
//パースして描画
var templete = parse(json, 'mix', acct_id);
$("#timeline_" + tlid).html(templete[0]);
jQuery("time.timeago").timeago();
$(window).scrollTop(0);
var locals = templete[1];
todo("Integrated TL Loading...(Home)");
//Home
var start = "https://" + domain + "/api/v1/timelines/home";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(obj) {
//ホームのオブジェクトをUnix時間で走査
Object.keys(obj).forEach(function(key) {
var skey = obj.length - key - 1;
var toot = obj[skey];
var id = toot.id;
var tarunix = date(toot.created_at, 'unix');
var beforekey2;
var key2;
//ホームのオブジェクトに対してLocalのオブジェクトを時間走査
Object.keys(locals).forEach(function(key2) {
if (!$("#timeline_" + tlid + " [toot-id=" + obj[0].id + "]").length &&
key2 < date(obj[0].created_at, 'unix')) {
$("#timeline_" + tlid + " .cvo").first().prepend(parse([obj[0]],
'home', acct_id));
}
if (!$("#timeline_" + tlid + " [toot-id=" + toot.id + "]").length) {
if (key2 > tarunix) {
var local = locals[key2];
$("#timeline_" + tlid + " [toot-id=" + local + "]").append(parse(
[toot], 'home', acct_id));
tarunix = 0;
}
}
});
});
todc();
mixre(acct_id, tlid);
additional(acct_id, tlid);
jQuery("time.timeago").timeago();
});
});
}
//Streamingに接続
function mixre(acct_id, tlid) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var type = "mix";
localStorage.setItem("now", type);
var startHome = "wss://" + domain +
"/api/v1/streaming/?stream=user&access_token=" + at;
var startLocal = "wss://" + domain +
"/api/v1/streaming/?stream=public:local&access_token=" + at;
var wshid = websocketHome.length;
var wslid = websocketLocal.length;
websocketHome[wshid] = new WebSocket(startHome);
websocketLocal[wslid] = new WebSocket(startLocal);
websocketHome[wshid].onopen = function(mess) {
console.log("Connect Streaming API(Home)");
}
websocketLocal[wslid].onopen = function(mess) {
console.log("Connect Streaming API(Local)");
}
websocketLocal[wslid].onmessage = function(mess) {
console.log("Receive Streaming API:");
var obj = JSON.parse(JSON.parse(mess.data).payload);
console.log(obj);
var type = JSON.parse(mess.data).event;
if (type == "delete") {
$("[toot-id=" + obj + "]").hide();
} else if (type == "update") {
var templete = parse([obj], '', acct_id);
if (!$("#timeline_" + tlid + " [toot-id=" + obj.id + "]").length) {
var pool = localStorage.getItem("pool_" + tlid);
if (pool) {
pool = templete + pool;
} else {
pool = templete
}
localStorage.setItem("pool_" + tlid, pool);
scrollck();
additional(acct_id, tlid);
jQuery("time.timeago").timeago();
todc();
}
}
}
websocketHome[wshid].onmessage = function(mess) {
console.log("Receive Streaming API:(Home)");
var obj = JSON.parse(JSON.parse(mess.data).payload);
console.log(obj);
var type = JSON.parse(mess.data).event;
if (type == "delete") {
$("[toot-id=" + obj + "]").hide();
} else if (type == "update") {
var templete = parse([obj], '', acct_id);
if (!$("#timeline_" + tlid + " [toot-id=" + obj.id + "]").length) {
if ($(window).scrollTop() > 0) {
var pool = localStorage.getItem("pool");
if (pool) {
pool = templete + pool;
} else {
pool = templete
}
localStorage.setItem("pool", pool);
} else {
$("#timeline_" + tlid).prepend(templete);
}
additional(acct_id, tlid);
jQuery("time.timeago").timeago();
}
}
}
websocketLocal[wslid].onerror = function(error) {
console.error('WebSocket Error ' + error);
};
websocketHome[wshid].onerror = function(error) {
console.error('WebSocket Error ' + error);
};
}
//ある程度のスクロールで発火
function mixmore(tlid) {
var multi = localStorage.getItem("column");
var obj = JSON.parse(multi);
var acct_id = obj[tlid].domain;
todo("Integrated TL MoreLoading...(Local)");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var sid = $("#timeline_" + tlid + " .cvo").last().attr("toot-id");
var start = "https://" + domain +
"/api/v1/timelines/public?local=true&max_id=" + sid;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse(json, 'mix', acct_id);
$("#timeline_" + tlid).append(templete[0]);
var locals = templete[1];
todo("Integrated TL MoreLoading...(Home)");
console.log(sid);
var start = "https://" + domain + "/api/v1/timelines/home?max_id=" + sid;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(obj) {
if (!$("[toot-id=" + obj[0].id + "]").length) {
$("#timeline_" + tlid + " .cvo").first().prepend(parse([obj[0]], 'home',
acct_id));
}
Object.keys(obj).forEach(function(key) {
var skey = obj.length - key - 1;
var toot = obj[skey];
var id = toot.id;
var tarunix = date(toot.created_at, 'unix');
var beforekey2;
var key2;
Object.keys(locals).forEach(function(key2) {
if (!$("[toot-id=" + toot.id + "]").length) {
if (key2 > tarunix) {
var local = locals[key2];
$("[toot-id=" + local + "]").append(parse([toot], 'home',
acct_id));
tarunix = 0;
}
}
});
});
additional(acct_id, tlid);
jQuery("time.timeago").timeago();
todc();
});
});
}

293
js/tl/notification.js Normal file
View File

@ -0,0 +1,293 @@
//通知
//取得+Streaming接続
function notf(acct_id, tlid, sys) {
todo("Notifications Loading...");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/notifications";
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
//body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parseNotf(json, -1, tlid, acct_id);
if (sys == "direct") {
$("#timeline_" + tlid).html(templete[0]);
} else {
$("#notifications_" + tlid).html(templete[0]);
}
jQuery("time.timeago").timeago();
$("#notf-box").addClass("fetched");
todc();
});
var start = "wss://" + domain + "/api/v1/streaming/?stream=user&access_token=" +
at;
console.log(start);
var websocket = new WebSocket(start);
console.log(websocket);
websocket.onopen = function(mess) {
console.log("Connect Streaming API:");
console.log(mess);
}
websocket.onmessage = function(mess) {
console.log("Receive Streaming API:");
var obj = JSON.parse(JSON.parse(mess.data).payload);
console.log(obj);
var type = JSON.parse(mess.data).event;
if (type == "notification") {
var popup = localStorage.getItem("popup");
if (!popup) {
popup = 0;
}
var templete = parseNotf([obj], popup, tlid, acct_id);
var notices = templete[1];
console.log(templete);
if (sys == "direct") {
$("#timeline_" + tlid).prepend(templete[0]);
} else {
$("#notifications_" + tlid).prepend(templete[0]);
}
jQuery("time.timeago").timeago();
}
}
websocket.onerror = function(error) {
console.error('WebSocket Error ' + error);
};
}
//通知トグルボタン
function notfToggle(acct, tlid) {
$("#notf-box_" + tlid).toggleClass("hide");
if (!$("#notf-box_" + tlid).hasClass("fetched")) {
notf(acct, tlid);
}
$(".notf-icon_" + tlid).removeClass("red-text");
}
//通知オブジェクトパーサー
function parseNotf(obj, popup, tlid, acct_id) {
var templete = '';
var datetype = localStorage.getItem("datetype");
var nsfwtype = localStorage.getItem("nsfw");
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";
}
Object.keys(obj).forEach(function(key) {
var eachobj = obj[key];
var toot = eachobj.status;
//トゥートである
if (toot) {
if (!toot.application) {
var via = "<i>Unknown</i>";
} else {
var via = toot.application.name;
}
if (toot.account.locked) {
var locked = ' <i class="fa fa-lock red-text"></i>';
} else {
var locked = "";
}
var id = toot.id;
if (eachobj.type == "mention") {
var what = "返信しました";
} else if (eachobj.type == "reblog") {
var what = "ブーストしました";
} else if (eachobj.type == "favourite") {
var what = "ふぁぼしました";
}
var noticetext = eachobj.account.display_name + "(" + eachobj.account.acct +
")が" + what;
if (popup >= 0 && obj.length < 5) {
Materialize.toast(noticetext, popup * 1000);
$(".notf-icon_" + tlid).addClass("red-text");
}
if (toot.spoiler_text && cw) {
var spoiler = "cw cw_hide_" + toot.id;
var spoiler_show = '<a onclick="cw_show(\'' + toot.id + '\')">見る</a>';
} else {
var spoiler = "";
var spoiler_show = "";
}
var viewer = "";
var youtube = "";
var mediack = toot.media_attachments[0];
if (mediack) {
Object.keys(toot.media_attachments).forEach(function(key2) {
var media = toot.media_attachments[key2];
var purl = media.preview_url;
var url = media.url;
if (toot.sensitive && nsfw) {
var sense = "sensitive"
} else {
var sense = ""
}
viewer = viewer + '<a onclick="imgv(\'' + url + '\',\'' + toot.account
.acct + '\',\'' + media.type + '\')"><img src="' + purl + '" class="' +
sense +
'" width="250" style="object-fit: cover; width: 100%; height: 200px;"></a></span>';
});
} else {
viewer = "";
}
var menck = toot.mentions[0];
var mentions = "";
if (menck) {
mentions = "Links: ";
Object.keys(toot.mentions).forEach(function(key3) {
var mention = toot.mentions[key3];
mentions = mentions + '<a onclick="udg(\'' + mention.id +
'\')" class="pointer">@' + mention.acct + '</a> ';
});
}
var tagck = toot.tags[0];
var tags = "";
if (tagck) {
if (!menck) {
tags = "Links: ";
}
Object.keys(toot.tags).forEach(function(key4) {
var tag = toot.tags[key4];
tags = tags + '<a onclick="tl(\'tag\',\'' + tag.name +
'\')" class="pointer">#' + tag.name + '</a> ';
});
}
if (toot.favourited) {
var if_fav = " yellow-text";
var fav_app = "faved";
} else {
var if_fav = "";
var fav_app = "";
}
if (toot.reblogged) {
var if_rt = "teal-text";
var rt_app = "rted";
} else {
var if_rt = "";
var rt_app = "";
}
if (toot.account.acct == localStorage.getItem("user_" + acct_id)) {
var if_mine = "";
} else {
var if_mine = "hide";
}
if (toot.favourited) {
var if_fav = " yellow-text";
var fav_app = "faved";
} else {
var if_fav = "";
var fav_app = "";
}
if (toot.reblogged) {
var if_rt = "teal-text";
var rt_app = "rted";
} else {
var if_rt = "";
var rt_app = "";
}
templete = templete + '<div each=' + toot.datab + ' id="pub_' + toot.id +
'" class="cvo ' + fav_app + ' ' + rt_app +
'" style="padding-top:5px;" notf-id="' + eachobj.id + '">' +
'<span class="gray sharesta">' + noticetext +
'<br><span class="cbadge"><i class="fa fa-clock-o"></i>' + date(eachobj.created_at,
datetype) + '</span></span>' +
'<div style="padding:0; margin:0; width:400px; max-width:100%; display:flex; align-items:flex-end;">' +
'<div style="flex-basis:40px;"><a onclick="udg(\'' + toot.account.id +
'\',\'' + acct_id + '\');" user="' + toot.account.acct + '" class="udg">' +
'<img src="' + toot.account.avatar +
'" width="20" class="prof-img" user="' + toot.account.acct +
'"></a></div>' +
'<div style="flex-grow:3; overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">' +
toot.account.display_name + '</div>' +
'<div class="sml gray" style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;"> @' +
toot.account.acct + locked + '</div>' +
'</div>' +
'<span class="toot ' + spoiler + '">' + toot.content +
'</span><span class="gray cw_text_' + toot.id + '">' + toot.spoiler_text +
spoiler_show + '</span>' +
'' + viewer + '' +
'<div class="additional"></div><span class="cbadge"><i class="fa fa-clock-o"></i>' +
date(toot.created_at, datetype) + '</span>' +
'<span class="cbadge">via ' + via + '</span>' + mentions + tags +
'<div style="padding:0; margin:0; top:-20px; display:flex; justify-content:space-around; width:500px; max-width:100%; ">' +
'<div><a onclick="re(\'' + toot.id + '\',\'' + toot.account.acct + '\',' +
acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="fa fa-share"></i><help>返信</help></a></div>' +
'<div><a onclick="rt(\'' + toot.id + '\',' + acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="text-darken-3 fa fa-retweet ' +
if_rt + '" id="rt_' + toot.id + '"></i><span class="rt_ct">' + toot.reblogs_count +
'</span><help>ブースト</help></a></div>' +
'<div><a onclick="fav(\'' + toot.id + '\',' + acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="fa text-darken-3 fa-star' +
if_fav + '" id="fav_' + toot.id + '"></i><span class="fav_ct">' + toot.favourites_count +
'<help>お気に入り</help></a></span></div>' +
'<div class=' + if_mine + '><a onclick="del(\'' + toot.id + '\',' +
acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="fa fa-trash-o"></i><help>削除</help></a></div>' +
'<div><a onclick="details(\'' + toot.id + '\',' + acct_id +
')" class="waves-effect waves-dark btn-flat details" style="padding:0"><i class="text-darken-3 material-icons">more_vert</i><help>詳細表示</help></a></div>' +
'</div>' +
'<div class="divider"></div>' +
'</div>' +
'</div>';
} else if (eachobj.type == "follow") {
//フォロー等のユーザーデータである
var tooter = eachobj.account;
if (tooter.locked) {
var locked = ' <i class="fa fa-lock red-text"></i>';
} else {
var locked = "";
}
templete = templete +
'<div class="cvo " style="padding-top:5px;" notf-id=' + eachobj.id + '>' +
'<div style="padding:0; margin:0; width:400px; max-width:100%; display:flex; align-items:flex-end;">' +
'<div style="flex-basis:40px;"><a onclick="udg(\'' + tooter.id + '\',\'' +
acct_id + '\');" user="' + tooter.acct + '" class="udg">' +
'<img src="' + tooter.avatar + '" width="40" class="prof-img" user="' +
tooter.acct + '"></a></div>' +
'<div style="flex-grow:3; overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">' +
tooter.display_name + '<div class="gray sharesta">にフォローされました</div></div>' +
'<div class="sml gray" style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;"> @' +
tooter.acct + locked + '</div>' +
'</div>' +
'<div style="justify-content:space-around"> <div class="cbadge">Follows:' +
tooter.following_count + '</div><div class="cbadge">Followers:' + tooter.followers_count +
'</div>' +
'<div class="divider"></div>' +
'</div>' +
'</div>';
var noticetext = eachobj.account.display_name + "(" + eachobj.account.acct +
")がフォローしました";
if (popup >= 0 && obj.length < 5) {
Materialize.toast(noticetext, popup * 1000);
$(".notf-icon").addClass("red-text");
}
}
});
if (!noticetext) {
var noticetext = null;
}
return [templete, noticetext];
}

250
js/tl/parse.js Normal file
View File

@ -0,0 +1,250 @@
//オブジェクトパーサー(トゥート)
function parse(obj, mix, acct_id) {
var templete = '';
var datetype = localStorage.getItem("datetype");
var nsfwtype = localStorage.getItem("nsfw");
var sent = localStorage.getItem("sentence");
if (!sent) {
var sent = 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";
}
var local = [];
Object.keys(obj).forEach(function(key) {
var toot = obj[key];
var id = toot.id;
//Integratedである場合はUnix時間をキーに配列を生成しておく
if (mix == "mix") {
local[date(obj[key].created_at, 'unix')] = toot.id;
}
if (mix == "home") {
var home = "Home TLより"
} else {
var home = "";
}
if (toot.reblog) {
var notice = toot.account.display_name + "(" + toot.account.acct +
")がブースト<br>";
var boostback = "shared";
var toot = toot.reblog;
} else {
var notice = "";
var boostback = "";
}
if (toot.account.locked) {
var locked = ' <i class="fa fa-lock red-text"></i>';
} else {
var locked = "";
}
if (!toot.application) {
var via = "<i>Unknown</i>";
} else {
var via = toot.application.name;
}
if (toot.spoiler_text && cw) {
var content = toot.content;
var spoil = toot.spoiler_text;
var spoiler = "cw cw_hide_" + toot.id;
var api_spoil = "gray";
var spoiler_show = '<a href="#" onclick="cw_show(\'' + toot.id +
'\')" class="nex parsed">見る</a>';
} else {
var ct = toot.content.split('</p>').length + toot.content.split('<br />').length -
2;
if (sent < ct && $.mb_strlen(toot.content) > 5) {
var content = '<span class="gray">以下全文</span><br>' + toot.content
var spoil = $.strip_tags($.mb_substr(toot.content, 0, 100)) +
'<span class="gray">自動折りたたみ</span>';
var spoiler = "cw cw_hide_" + toot.id;
var spoiler_show = '<a href="#" onclick="cw_show(\'' + toot.id +
'\')" class="nex parsed">続き…</a>';
} else {
var content = toot.content;
var spoil = toot.spoiler_text;
var spoiler = "";
var spoiler_show = "";
}
}
var viewer = "";
var youtube = "";
var emojick = toot.emojis[0];
//絵文字があれば
if (emojick) {
Object.keys(toot.emojis).forEach(function(key5) {
var emoji = toot.emojis[key5];
var shortcode = emoji.shortcode;
var emoji_url = '<img src="' + emoji.url +
'" style="width:2em" class="emoji-img">';
var regExp = new RegExp(":" + shortcode + ":", "g");
content = content.replace(regExp, emoji_url);
});
}
var mediack = toot.media_attachments[0];
//メディアがあれば
if (mediack) {
Object.keys(toot.media_attachments).forEach(function(key2) {
var media = toot.media_attachments[key2];
var purl = media.preview_url;
var url = media.url;
if (toot.sensitive && nsfw) {
var sense = "sensitive"
} else {
var sense = ""
}
viewer = viewer + '<a onclick="imgv(\''+id+'\',\''+key2+'\')" id="'+id+'-image-'+key2+'" data-url="'+url+'" data-type="'+media.type+'"><img src="' + purl + '" class="' + sense +
' toot-img" style=""></a></span>';
});
} else {
viewer = "";
}
var menck = toot.mentions[0];
var mentions = "";
//メンションであれば
if (menck) {
mentions = "Links: ";
Object.keys(toot.mentions).forEach(function(key3) {
var mention = toot.mentions[key3];
mentions = mentions + '<a onclick="udg(\'' + mention.id + '\',' +
acct_id + ')" class="pointer">@' + mention.acct + '</a> ';
});
}
var tagck = toot.tags[0];
var tags = "";
//タグであれば
if (tagck) {
if (!menck) {
tags = "Links: ";
}
Object.keys(toot.tags).forEach(function(key4) {
var tag = toot.tags[key4];
tags = tags + '<a onclick="tl(\'tag\',\'' + tag.name + '\',' + acct_id +
',\'add\')" class="pointer">#' + tag.name + '</a> ';
});
}
if (toot.account.acct == localStorage.getItem("user_" + acct_id)) {
var if_mine = "";
} else {
var if_mine = "hide";
}
if (toot.favourited) {
var if_fav = " yellow-text";
var fav_app = "faved";
} else {
var if_fav = "";
var fav_app = "";
}
if (toot.reblogged) {
var if_rt = "teal-text";
var rt_app = "rted";
} else {
var if_rt = "";
var rt_app = "";
}
templete = templete + '<div id="pub_' + toot.id + '" class="cvo ' +
boostback + ' ' + fav_app + ' ' + rt_app +
'" style="padding-top:5px;" toot-id="' + id + '" unixtime="' + date(obj[
key].created_at, 'unix') + '">' +
'<span class="gray sharesta">' + notice + home + '</span>' +
'<div style="padding:0; margin:0; width:400px; max-width:100%; display:flex; align-items:flex-end;">' +
'<div style="flex-basis:40px;"><a onclick="udg(\'' + toot.account.id +
'\',' + acct_id + ');" user="' + toot.account.acct + '" class="udg">' +
'<img src="' + toot.account.avatar +
'" width="40" class="prof-img" user="' + toot.account.acct +
'"></a></div>' +
'<div style="flex-grow:3; overflow: hidden;white-space: nowrap;text-overflow: ellipsis;"><big>' +
toot.account.display_name + '</big></div>' +
'<div class="sml gray" style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;"> @' +
toot.account.acct + locked + '</div>' +
'</div>' +
'<div style="display:none; justify-content:space-around" class="sml gray"> <div>Follows:' +
toot.account.following_count + '</div><div>Followers:' + toot.account.followers_count +
'</div>' +
'<div>Toots:' + toot.account.statuses_count + '</div></div>' +
'<span class="toot ' + spoiler + '">' + content + '</span><span class="' +
api_spoil + ' cw_text_' + toot.id + '">' + spoil + spoiler_show +
'</span>' +
'' + viewer + '' +
'<div class="additional"></div><span class="cbadge"><i class="fa fa-clock-o"></i>' +
date(toot.created_at, datetype) + '</span>' +
'<span class="cbadge">via ' + via +
'<help class="white-text">どこから投稿したか</help></span>' + mentions + tags +
'<div style="padding:0; margin:0; top:-20px; display:flex; justify-content:space-around; width:500px; max-width:100%; ">' +
'<div><a onclick="re(\'' + toot.id + '\',\'' + toot.account.acct + '\',' +
acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="fa fa-share"></i></a></div>' +
'<div><a onclick="rt(\'' + toot.id + '\',' + acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="text-darken-3 fa fa-retweet ' +
if_rt + '" id="rt_' + toot.id + '"></i><span class="rt_ct">' + toot.reblogs_count +
'</span></a></div>' +
'<div><a onclick="fav(\'' + toot.id + '\',' + acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="fa text-darken-3 fa-star' +
if_fav + '" id="fav_' + toot.id + '"></i><span class="fav_ct">' + toot.favourites_count +
'</a></span></div>' +
'<div class=' + if_mine + '><a onclick="del(\'' + toot.id + '\',' +
acct_id +
')" class="waves-effect waves-dark btn-flat" style="padding:0"><i class="fa fa-trash-o"></i></a></div>' +
'<div><a onclick="details(\'' + toot.id + '\',' + acct_id +
')" class="waves-effect waves-dark btn-flat details" style="padding:0"><i class="text-darken-3 material-icons">more_vert</i></a></div>' +
'</div>' +
'<div class="divider"></div>' +
'</div>' +
'</div>';
});
if (mix == "mix") {
return [templete, local]
} else {
return templete;
}
}
//オブジェクトパーサー(ユーザーデータ)
function userparse(obj, auth) {
var templete = '';
Object.keys(obj).forEach(function(key) {
var toot = obj[key];
if (toot.locked) {
var locked = ' <i class="fa fa-lock red-text"></i>';
} else {
var locked = "";
}
if (auth) {
var auth = '<i class="material-icons gray pointer" onclick="request(\'' +
toot.id + '\',\'authorize\',' + acct_id + ')">person_add</i>';
} else {
var auth = "";
}
templete = templete +
'<div class="cvo " style="padding-top:5px;" user-id="' + toot.id + '">' +
'<div style="padding:0; margin:0; width:400px; max-width:100%; display:flex; align-items:flex-end;">' +
'<div style="flex-basis:40px;"><a onclick="udg(\'' + toot.id + '\',' +
acct_id + ');" user="' + toot.acct + '" class="udg">' +
'<img src="' + toot.avatar + '" width="40" class="prof-img" user="' + toot
.acct + '"></a></div>' +
'<div style="flex-grow:3; overflow: hidden;white-space: nowrap;text-overflow: ellipsis;"><big>' +
toot.display_name + '</big></div>' +
'<div class="sml gray" style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;"> @' +
toot.acct + locked + '</div>' +
'</div>' + auth +
'<div style="justify-content:space-around"> <div class="cbadge">Follows:' +
toot.following_count + '</div><div class="cbadge">Followers:' + toot.followers_count +
'</div>' +
'<div class="divider"></div>' +
'</div>' +
'</div>';
});
return templete;
}

55
js/tl/src.js Normal file
View File

@ -0,0 +1,55 @@
//検索
//検索ボックストグル
function srcToggle() {
$("#src-box").toggleClass("hide");
$('ul.tabs').tabs('select_tab', 'src-sta');
$("#src-contents").html("");
}
//検索取得
function src() {
var q = $("#src").val();
var acct_id = $("#src-acct-sel").val();
localStorage.setItem("last-use", acct_id);
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (user == "--now") {
var user = $('#his-data').attr("user-id");
}
var start = "https://" + domain + "/api/v1/search?q=" + q
console.log(start)
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
//トゥート
if (json.statuses[0]) {
var templete = parse(json.statuses);
$("#src-contents").append("Mentions<br>" + templete);
}
//アカウント
if (json.accounts[0]) {
var templete = userparse(json.accounts);
$("#src-contents").append("Accounts<br>" + templete);
}
//ハッシュタグ
if (json.hashtags[0]) {
var tags = "";
Object.keys(json.hashtags).forEach(function(key4) {
var tag = json.hashtags[key4];
tags = tags + '<a onclick="tl(\'tag\',\'' + tag + '\',\'' + acct_id +
'\',\'add\')" class="pointer">#' + tag + '</a><br> ';
});
$("#src-contents").append("Tags<br>" + tags);
}
jQuery("time.timeago").timeago();
});
}

240
js/tl/tl.js Normal file
View File

@ -0,0 +1,240 @@
//TL取得
function tl(type, data, acct_id, tlid) {
scrollevent();
localStorage.removeItem("morelock");
localStorage.removeItem("pool");
//タグの場合はカラム追加して描画
if (tlid == "add") {
console.log("add");
var newtab = $(".box").length;
var add = {
domain: acct_id,
type: "tag",
data: data
};
var multi = localStorage.getItem("column");
var obj = JSON.parse(multi);
obj.push(add);
console.log(obj);
var json = JSON.stringify(obj);
localStorage.setItem("column", json);
parseColumn();
return;
}
if (!type) {
var type = localStorage.getItem("now");
if (!type) {
//デフォルト
var type = "local";
}
}
if (type == "mix") {
//Integratedなら飛ばす
mixtl(acct_id, tlid);
return;
} else if (type == "notf") {
//通知なら飛ばす
notf(acct_id, tlid, 'direct');
$("#notice_" + tlid).text(cap(type, data) + " TL(" + localStorage.getItem(
"user_" + acct_id) + "@" + domain + ")");
return;
}
localStorage.setItem("now", type);
todo(cap(type) + " TL Loading...");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
$("#notice_" + tlid).text(cap(type, data) + " TL(" + localStorage.getItem(
"user_" + acct_id) + "@" + domain + ")");
var start = "https://" + domain + "/api/v1/timelines/" + com(type, data);
console.log(start);
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse(json, '', acct_id);
$("#timeline_" + tlid).html(templete);
additional(acct_id, tlid);
jQuery("time.timeago").timeago();
todc();
reload(type, '', acct_id, tlid);
$(window).scrollTop(0);
});
}
//Streaming接続
function reload(type, cc, acct_id, tlid) {
if (!type) {
var type = localStorage.getItem("now");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
localStorage.setItem("now", type);
if (type == "home") {
var start = "wss://" + domain +
"/api/v1/streaming/?stream=user&access_token=" + at;
} else if (type == "pub") {
var start = "wss://" + domain +
"/api/v1/streaming/?stream=public&access_token=" + at;
} else if (type == "local") {
var start = "wss://" + domain +
"/api/v1/streaming/?stream=public:local&access_token=" + at;
}
console.log(start);
var wsid = websocket.length;
websocket[wsid] = new WebSocket(start);
websocket[wsid].onopen = function(mess) {
console.log(tlid + ":Connect Streaming API:" + type);
console.log(mess);
}
websocket[wsid].onmessage = function(mess) {
console.log(tlid + ":Receive Streaming API:");
console.log(websocket[wsid]);
var typeA = JSON.parse(mess.data).event;
if (typeA == "delete") {
var obj = JSON.parse(mess.data).payload;
$("[toot-id=" + obj + "]").hide();
} else if (typeA == "update") {
var obj = JSON.parse(JSON.parse(mess.data).payload);
console.log(obj);
var templete = parse([obj], '', acct_id);
var pool = localStorage.getItem("pool_" + tlid);
if (pool) {
pool = templete + pool;
} else {
pool = templete
}
localStorage.setItem("pool_" + tlid, pool);
scrollck();
additional(acct_id, tlid);
jQuery("time.timeago").timeago();
todc();
}
websocket[wsid].onclose = function(mess) {
console.log("Close Streaming API:" + type);
}
}
websocket[wsid].onerror = function(error) {
console.error('WebSocket Error ' + error);
};
}
//一定のスクロールで発火
function moreload(type, tlid) {
var multi = localStorage.getItem("column");
var obj = JSON.parse(multi);
var acct_id = obj[tlid].domain;
if (!type) {
var type = localStorage.getItem("now");
}
var sid = $("#timeline_" + tlid + " .cvo").last().attr("toot-id");
console.log(localStorage.getItem("morelock") + ":" + sid)
if (localStorage.getItem("morelock") != sid) {
localStorage.setItem("morelock", sid);
if (type == "mix") {
mixmore();
return;
}
localStorage.setItem("now", type);
todo(cap(type) + " TL MoreLoading");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/timelines/" + com(type) +
"max_id=" + sid;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse(json, '', acct_id);
$("#timeline_" + tlid).append(templete);
additional(acct_id, tlid);
jQuery("time.timeago").timeago();
todc();
});
}
}
//WebSocket切断
function tlCloser() {
Object.keys(websocket).forEach(function(tlid) {
if (websocketOld[tlid]) {
websocketOld[tlid].close();
console.log("Close Streaming API: Old" + tlid);
}
if (websocket[0]) {
console.log(websocket[0]);
websocket[tlid].close();
console.log("Close Streaming API:" + tlid);
}
});
websocket = [];
Object.keys(websocketHome).forEach(function(tlid) {
if (websocketHome[tlid]) {
websocketHome[tlid].close();
console.log("Close Streaming API:MixHome" + tlid);
}
});
websocketHome = [];
Object.keys(websocketLocal).forEach(function(tlid) {
if (websocketLocal[tlid]) {
websocketLocal[tlid].close();
console.log("Close Streaming API:MixLocal" + tlid);
}
});
websocketLocal = [];
}
//TLのタイトル
function cap(type, data) {
if (type == "home") {
return "Home"
} else if (type == "local") {
return "Local"
} else if (type == "pub") {
return "Public"
} else if (type == "tag") {
return "#" + data
} else if (type == "list") {
return "List(id:" + data + ")"
} else if (type == "notf") {
return "Notification"
}
}
//TLのURL
function com(type, data) {
if (type == "home") {
return "home?"
} else if (type == "local") {
return "public?local=true&"
} else if (type == "pub") {
return "public?"
} else if (type == "tag") {
return "tag/" + data + "?"
}
if (type == "list") {
return "list/" + data + "?"
}
}

162
js/ui/img.js Normal file
View File

@ -0,0 +1,162 @@
/*イメージビューワー*/
//postのimg.jsとは異なります。
function imgv(id, key) {
$('#imgmodal').attr('src', './img/loading.svg');
var murl = $("#" + id + "-image-" + key).attr("data-url");
var type = $("#" + id + "-image-" + key).attr("data-type");
$(document).ready(function() {
if (type == "image") {
$('#imgmodal').attr('src', murl);
$('#imagewrap').dragScroll(); // ドラッグスクロール設定
$('#imagemodal').modal('open');
$('#imagemodal').attr('data-key', key);
$('#imagemodal').attr('data-id', id);
} else if (type == "video" || type == "gifv") {
$('#video').attr('src', murl);
$('#videomodal').modal('open');
}
var element = new Image();
var width;
element.onload = function() {
var width = element.naturalWidth;
var height = element.naturalHeight;
$("#imgmodal").attr('width', width);
$("#imagemodal").css('height', "calc(100vh - 20px)");
}
if ($("#" + id + "-image-" + (key * 1 + 1)).length == 0) {
$("#image-next").prop("disabled", true);
}
if ($("#" + id + "-image-" + (key * 1 - 1)).length == 0) {
$("#image-prev").prop("disabled", true);
}
element.src = murl;
});
}
//イメージビューワーの送り
function imgCont(type) {
var key = $('#imagemodal').attr('data-key');
var id = $('#imagemodal').attr('data-id');
if (type == "next") {
key++;
} else if (type == "prev") {
key = key * 1 - 1;
}
$('#imgmodal').attr('src', './img/loading.svg');
var murl = $("#" + id + "-image-" + key).attr("data-url");
var type = $("#" + id + "-image-" + key).attr("data-type");
$(document).ready(function() {
if (type == "image") {
$('#imgmodal').attr('src', murl);
$('#imagewrap').dragScroll(); // ドラッグスクロール設定
$('#imagemodal').attr('data-key', key);
$('#imagemodal').attr('data-id', id);
} else if (type == "video" || type == "gifv") {
$('#video').attr('src', murl);
$('#videomodal').modal('open');
}
var element = new Image();
var width;
element.onload = function() {
var width = element.naturalWidth;
var height = element.naturalHeight;
$("#imgmodal").attr('width', width);
$("#imagemodal").css('height', "calc(100vh - 20px)");
}
if ($("#" + id + "-image-" + (key * 1 + 1)).length == 0) {
$("#image-next").prop("disabled", true);
} else {
$("#image-next").prop("disabled", false);
}
console.log("#" + id + "-image-" + (key * 1 - 1));
if ($("#" + id + "-image-" + (key * 1 - 1)).length == 0) {
$("#image-prev").prop("disabled", true);
} else {
$("#image-prev").prop("disabled", false);
}
element.src = murl;
});
}
//ズームボタン(z:倍率)
function zoom(z) {
var wdth = $('#imagewrap img').width();
var wdth = wdth * z;
$('#imagewrap img').attr("width", wdth);
}
//スマホ対応ドラッグ移動システム
(function() {
$.fn.dragScroll = function() {
var target = this;
$(this).mousedown(function(event) {
$(this)
.data('down', true)
.data('x', event.clientX)
.data('y', event.clientY)
.data('scrollLeft', this.scrollLeft)
.data('scrollTop', this.scrollTop);
return false;
}).css({
'overflow': 'hidden', // スクロールバー非表示
'cursor': 'move'
});
// ウィンドウから外れてもイベント実行
$(document).mousemove(function(event) {
if ($(target).data('down') == true) {
// スクロール
target.scrollLeft($(target).data('scrollLeft') + $(target).data('x') -
event.clientX);
target.scrollTop($(target).data('scrollTop') + $(target).data('y') -
event.clientY);
return false; // 文字列選択を抑止
}
}).mouseup(function(event) {
$(target).data('down', false);
});
$(this).on('touchstart', function(event) {
$(this)
.data('down', true)
.data('x', getX(event))
.data('y', getY(event))
.data('scrollLeft', this.scrollLeft)
.data('scrollTop', this.scrollTop);
return false;
}).css({
'overflow': 'hidden', // スクロールバー非表示
'cursor': 'move'
}); //指が触れたか検知
$(this).on('touchmove', function(event) {
if ($(target).data('down') == true) {
// スクロール
console.log($(target).data('x'));
target.scrollLeft($(target).data('scrollLeft') + $(target).data('x') -
getX(event));
target.scrollTop($(target).data('scrollTop') + $(target).data('y') -
getY(event));
return false; // 文字列選択を抑止
} else {}
}); //指が動いたか検知
$(this).on('touchend', function(event) {
$(target).data('down', false);
});
return this;
}
})(jQuery);
function getX(event) {
return event.originalEvent.touches[0].pageX;
}
function getY(event) {
return event.originalEvent.touches[0].pageY;
}
//マウスホイールで拡大
var element = document.getElementById("imagemodal");
element.onmousewheel = function(e) {
var delta = e.wheelDelta;
if (delta > 0) {
zoom(1.1)
} else {
zoom(0.9)
}
}

133
js/ui/layout.js Normal file
View File

@ -0,0 +1,133 @@
//レイアウトの設定
var websocketOld = [];
var websocket = [];
var websocketHome = [];
var websocketLocal = [];
//カラム追加ボックストグル
function addToggle() {
$("#add-box").toggleClass("hide");
}
//最初、カラム変更時に発火
function parseColumn() {
var multi = localStorage.getItem("multi");
if (!multi) {
var obj = [{
at: localStorage.getItem(localStorage.getItem("domain_0") + "_at"),
name: localStorage.getItem("name_0"),
domain: localStorage.getItem("domain_0"),
user: localStorage.getItem("user_0"),
prof: localStorage.getItem("prof_0")
}];
var json = JSON.stringify(obj);
localStorage.setItem("multi", json);
} else {
var obj = JSON.parse(multi);
var templete;
Object.keys(obj).forEach(function(key) {
var acct = obj[key];
localStorage.setItem("name_" + key, acct.name);
localStorage.setItem("user_" + key, acct.user);
localStorage.setItem("user-id_" + key, acct.user);
localStorage.setItem("prof_" + key, acct.prof);
localStorage.setItem("domain_" + key, acct.domain);
localStorage.setItem(acct.domain + "_at", acct.at);
});
}
var col = localStorage.getItem("column");
if (!col) {
var obj = [{
domain: 0,
type: 'local'
}];
var json = JSON.stringify(obj);
localStorage.setItem("column", json);
} else {
var obj = JSON.parse(col);
}
if ($("#timeline-container").length) {
$("#timeline-container").html("");
}
tlCloser();
Object.keys(obj).forEach(function(key) {
var acct = obj[key];
var html = '<div class="box" id="timeline_' + key + '_box" tlid="' + key +
'"><div><span id="notice_' + key + '" class="notice"></span>' +
'<a onclick="notfToggle(' + acct.domain + ',' + key +
')" class="setting nex" title="このアカウントの通知"><i class="material-icons nex notf-icon_' +
key + '">notifications</i></a>' +
'<a onclick="removeColumn(' + key +
')" class="setting nex"><i class="material-icons nex" title="このカラムを削除">remove_circle</i></a>' +
'<a onclick="cardToggle(' + key +
')" class="setting nex"><i class="material-icons nex" title="リンクの解析を切り替え(OFFで制限を回避出来る場合があります)">link</i><span id="sta-card-' +
key + '">On</span></a>' +
'<div class="hide notf-indv-box" id="notf-box_' + key +
'"><div id="notifications_' + key +
'"></div></div></div><div id="timeline_' + key +
'" class="tl"></div></div>';
$("#timeline-container").append(html);
if (acct.data) {
var data = acct.data;
} else {
var data = "";
}
tl(acct.type, data, acct.domain, key);
cardCheck(key);
});
var width = localStorage.getItem("width");
if (width) {
$(".box").css("min-width", width + "px");
}
var box = localStorage.getItem("box");
if (box == "yes") {
$("#post-box").addClass("hidenbox");
$("#post-box").fadeOut();
$("#menu-btn").fadeIn();
}
var vis = localStorage.getItem("vis");
if (!vis) {
$("#vis").text("public");
} else {
if (vis == "memory") {
var memory = localStorage.getItem("vis-memory");
if (!memory) {
memory = "public";
}
$("#vis").text(memory);
} else {
$("#vis").text(vis);
}
}
}
//カラム追加
function addColumn() {
var acct = $("#add-acct-sel").val();
localStorage.setItem("last-use", acct);
var type = $("#type-sel").val();
var add = {
domain: acct,
type: type
};
var multi = localStorage.getItem("column");
var obj = JSON.parse(multi);
obj.push(add);
var json = JSON.stringify(obj);
localStorage.setItem("column", json);
parseColumn();
}
//カラム削除
function removeColumn(tlid) {
var multi = localStorage.getItem("column");
var obj = JSON.parse(multi);
//聞く
if (confirm("このコラムを削除します")) {
localStorage.removeItem("card_" + tlid);
obj.splice(tlid, 1);
var json = JSON.stringify(obj);
localStorage.setItem("column", json);
parseColumn();
}
}

36
js/ui/post-box.js Normal file
View File

@ -0,0 +1,36 @@
/*ささやきボックス(Cr民並感)*/
//もっとボタン
function more() {
$(".more-show").show();
$(".more-hide").hide();
$("#post-box").addClass("post-more");
}
//閉じるボタン
function less() {
$(".more-show").hide();
$(".more-hide").show();
$("#post-box").removeClass("post-more");
}
//✕隠す
function hide() {
$("#post-box").addClass("hidenbox");
$("#post-box").fadeOut();
$("#menu-btn").fadeIn();
}
//最小化時に展開
function show() {
$("#post-box").removeClass("hidenbox");
$("#post-box").fadeIn();
$("#menu-btn").fadeOut();
}
//横幅
function zoomBox() {
if ($("#post-box").hasClass("bigbox")) {
$("#post-box").css('width', '350px');
$("#post-box").removeClass("bigbox")
} else {
$("#post-box").css('width', '50vw');
$("#post-box").addClass("bigbox")
}
}

28
js/ui/scroll.js Normal file
View File

@ -0,0 +1,28 @@
//スクロールで続きを読む
function scrollevent() {
$(".box").scroll(function() {
scrollck();
});
}
scrollevent();
function scrollck() {
$(".box").each(function(i, elem) {
var tlid = $(this).attr('tlid');
//一番上ならためていた新しいトゥートを表示
if ($(this).scrollTop() == 0) {
var pool = localStorage.getItem("pool_" + tlid);
if (pool) {
$("#timeline_" + tlid).prepend(pool);
jQuery("time.timeago").timeago();
localStorage.removeItem("pool_" + tlid);
}
}
//続きを読むトリガー
var scrt = $(this).find(".tl").height() - 1000;
var scr = $(this).scrollTop();
if (scr > scrt) {
moreload('', tlid);
}
});
}

136
js/ui/settings.js Normal file
View File

@ -0,0 +1,136 @@
//設定(setting.html)で読む
//設定ボタン押した。
function settings() {
var dd = $("[name=time]:checked").val();
if (dd != localStorage.getItem("datetype")) {
Materialize.toast("時間設定を" + dd + "に設定しました。", 3000);
}
localStorage.setItem("datetype", dd);
var cd = $("[name=theme]:checked").val();
if (cd != localStorage.getItem("theme")) {
Materialize.toast("テーマ設定を" + cd + "に設定しました。", 3000);
}
//テーマはこの場で設定
themes(cd);
localStorage.setItem("theme", cd);
var nd = $("[name=nsfw]:checked").val();
if (nd != localStorage.getItem("nsfw")) {
Materialize.toast("画像表示設定を" + nd + "に設定しました。", 3000);
}
localStorage.setItem("nsfw", nd);
var cwd = $("[name=cw]:checked").val();
if (cwd != localStorage.getItem("cw")) {
Materialize.toast("テキスト表示設定を" + cwd + "に設定しました。", 3000);
}
localStorage.setItem("cw", cwd);
var cwtd = $("#cw-text").val();
if (cwtd != localStorage.getItem("cw-text")) {
Materialize.toast("デフォルトの警告文を「" + cwtd + "」に設定しました。", 3000);
}
localStorage.setItem("cw-text", cwtd);
var visd = $("[name=vis]:checked").val();
if (visd != localStorage.getItem("vis")) {
Materialize.toast("デフォルトの公開設定を" + visd + "に設定しました。", 3000);
}
localStorage.setItem("vis", visd);
var popd = $("#popup").val();
if (popd > 0 && popd != localStorage.getItem("popup")) {
Materialize.toast("ポップアップお知らせを" + popd + "秒に設定しました。", 3000);
} else if (popd != localStorage.getItem("popup")) {
Materialize.toast("ポップアップお知らせをオフに設定しました。", 3000);
}
localStorage.setItem("popup", popd);
var boxd = $("[name=box]:checked").val();
if (boxd != localStorage.getItem("box")) {
Materialize.toast("デフォルトでボックスを隠すかを" + boxd + "に設定しました。", 3000);
}
localStorage.setItem("box", boxd);
var sentd = $("#sentence").val();
if (sentd != localStorage.getItem("sentence")) {
Materialize.toast("指定行超過折りたたみを" + sentd + "行に設定しました。", 3000);
}
localStorage.setItem("sentence", sentd);
var widthd = $("#width").val();
if (widthd != localStorage.getItem("width")) {
Materialize.toast("横幅最低を" + widthd + "pxに設定しました。", 3000);
}
localStorage.setItem("width", widthd);
var imgd = $("[name=img]:checked").val();
if (imgd != localStorage.getItem("img")) {
Materialize.toast("画像投稿後の設定を" + imgd + "に設定しました。", 3000);
}
localStorage.setItem("img", imgd);
}
//読み込み時の設定ロード
function load() {
var prof = localStorage.getItem("prof");
$("#my-prof").attr("src", prof);
var datetype = localStorage.getItem("datetype");
if (!datetype) {
var datetype = "absolute";
}
$("#" + datetype).prop("checked", true);
var theme = localStorage.getItem("theme");
if (!theme) {
var theme = "white";
}
$("#" + theme).prop("checked", true);
var nsfw = localStorage.getItem("nsfw");
if (!nsfw) {
var nsfw = "yes";
}
$("#n_" + nsfw).prop("checked", true);
var cw = localStorage.getItem("cw");
if (!cw) {
var cw = "yes";
}
$("#c_" + cw).prop("checked", true);
var popup = localStorage.getItem("popup");
if (!popup) {
var popup = "0";
}
$("#popup").val(popup);
var box = localStorage.getItem("box");
if (!box) {
var box = "no";
}
$("#b_" + box).prop("checked", true);
var sent = localStorage.getItem("sentence");
if (!sent) {
var sent = "500";
}
$("#sentence").val(sent);
var width = localStorage.getItem("width");
if (!width) {
var width = "300";
}
$("#width").val(width);
var cwt = localStorage.getItem("cw-text");
if (!cwt) {
var cwt = "";
}
$("#cw-text").val(cwt);
var vis = localStorage.getItem("vis");
if (!vis) {
var vis = "public";
}
$("#" + vis).prop("checked", true);
var img = localStorage.getItem("img");
if (!img) {
var img = "no-act";
}
$("#i_" + img).prop("checked", true);
}
//最初に読む
load();

12
js/ui/theme.js Normal file
View File

@ -0,0 +1,12 @@
//テーマ適用
function themes(theme) {
if (!theme) {
var theme = localStorage.getItem("theme");
}
if (theme == "black") {
$("html").addClass("blacktheme");
} else {
$("html").removeClass("blacktheme");
}
}
themes();

8
js/ui/tips.js Normal file
View File

@ -0,0 +1,8 @@
//左下のメッセージ
function todo(mes){
$('#message').text(mes);
$('#message').fadeIn();
}
function todc(){
$('#message').fadeOut();
}

322
js/userdata/his-data.js Normal file
View File

@ -0,0 +1,322 @@
//ユーザーデータ表示
//タイムライン
function utl(user, more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (user == "--now") {
var user = $('#his-data').attr("user-id");
}
if (more) {
var sid = $("#his-tl .cvo").last().attr("toot-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/accounts/" + user + "/statuses" +
plus
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse(json, '', acct_id);
var height = $("#his-data-content").height() - 245;
$(".tab-content").css('height', height);
if (more) {
$("#his-tl-contents").append(templete);
} else {
$("#his-tl-contents").html(templete);
}
jQuery("time.timeago").timeago();
});
}
//フォローリスト
function flw(user, more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (user == "--now") {
var user = $('#his-data').attr("user-id");
}
if (more) {
var sid = $("#his-follow-list .cvo").last().attr("user-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/accounts/" + user + "/following" +
plus
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = userparse(json);
if (more) {
$("#his-follow-list-contents").append(templete);
} else {
$("#his-follow-list-contents").html(templete);
}
});
}
//フォロワーリスト
function fer(user, more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (user == "--now") {
var user = $('#his-data').attr("user-id");
}
if (more) {
var sid = $("#his-follower-list .cvo").last().attr("user-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/accounts/" + user + "/followers" +
plus;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = userparse(json);
if (more) {
$("#his-follower-list-contents").append(templete);
} else {
$("#his-follower-list-contents").html(templete);
}
});
}
//以下自分のみ
//お気に入り一覧
function showFav(more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (more) {
var sid = $("#his-fav-list .cvo").last().attr("toot-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/favourites" + plus
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = parse(json);
if (more) {
$("#his-fav-list-contents").append(templete);
} else {
$("#his-fav-list-contents").html(templete);
}
jQuery("time.timeago").timeago();
});
}
//ミュートリスト
function showMut(more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (more) {
var sid = $("#his-muting-list .cvo").last().attr("user-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/mutes" + plus
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = userparse(json);
if (more) {
$("#his-muting-list-contents").append(templete);
} else {
$("#his-muting-list-contents").html(templete);
}
});
}
//ブロックリスト
function showBlo(more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (more) {
var sid = $("#his-blocking-list .cvo").last().attr("user-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/blocks" + plus
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = userparse(json);
if (more) {
$("#his-blocking-list-contents").append(templete);
} else {
$("#his-blocking-list-contents").html(templete);
}
});
}
//フォロリクリスト
function showReq(more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (more) {
var sid = $("#his-request-list .cvo").last().attr("user-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/follow_requests" + plus
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = userparse(json, 'true');
if (more) {
$("#his-request-list-contents").append(templete);
} else {
$("#his-request-list-contents").html(templete);
}
});
}
//ドメインブロックリスト
function showDom(more, acct_id) {
if (!acct_id) {
var acct_id = $('#his-data').attr("use-acct");
}
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
if (more) {
var sid = $("#his-domain-list .cvo").last().attr("user-id");
var plus = "?max_id=" + sid;
} else {
var plus = "";
}
var start = "https://" + domain + "/api/v1/domain_blocks" + plus
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
//body: JSON.stringify({})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var templete = "";
Object.keys(json).forEach(function(key) {
var domain = json[key];
templete = templete + domain +
'<i class="material-icons gray pointer" onclick="domainblock(\'' +
domain + '\',\'DELETE\')">cancel</i>' +
'<div class="divider"></div>';
});
if (more) {
$("#his-domain-list-contents").append(templete);
} else {
$("#his-domain-list-contents").html(templete);
}
});
}
//プロフ編集
function profeditShow(json) {
$("#his-name-val").val(json.display_name);
var des = json.note;
des = des.replace(/<br \/>/g, "\n");
des = des.replace("<p>", "");
des = des.replace("</p>", "");
$("#his-des-val").val(des);
}

72
js/userdata/prof-edit.js Normal file
View File

@ -0,0 +1,72 @@
//プロフ編集
//文字系
function profedit() {
var acct_id = $('#his-data').attr("use-acct");
todo("Updating...");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/update_credentials";
var name = $("#his-name-val").val();
var des = $("#his-des-val").val();
fetch(start, {
method: 'PATCH',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
body: JSON.stringify({
display_name: name,
note: des
})
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
getdata();
todc();
});
}
//画像系
function imgChange(imgfile, target) {
var acct_id = $('#his-data').attr("use-acct");
todo("アップロードしています")
if (!imgfile.files.length) {
console.log("No Img");
return;
}
var file = imgfile.files[0];
var fr = new FileReader();
fr.onload = function(evt) {
var b64 = this.result;
var blob = toBlob(b64, 'image/png');
var fd = new FormData();
fd.append(target, blob);
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/update_credentials";
fetch(start, {
method: 'PATCH',
headers: {
'Authorization': 'Bearer ' + at
},
body: fd
}).then(function(response) {
console.log(response)
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
console.log(json);
getdata();
todc();
});
}
$("#prof-change").html($("#prof-change").html());
$("#header-change").html($("#header-change").html());
fr.readAsDataURL(file);
}

150
js/userdata/showOnTL.js Normal file
View File

@ -0,0 +1,150 @@
//ユーザーデータ表示
function udg(user, acct_id) {
if (!user) {
user = localStorage.getItem("user-id");
}
todo("User Data Loading...");
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/" + user;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
//moved設定時
if (json.moved) {
Materialize.toast(
'このアカウントは移行します<button class="btn-flat toast-action" onclick="udg(\"' +
json.moved + '\")">移行先を見る</button>', 4000)
} else {
$('#his-data').attr("user-id", user);
$('#his-data').attr("use-acct", acct_id);
$("#his-name").text(json.display_name);
$("#his-acct").text(json.acct);
$("#his-prof").attr("src", json.avatar);
$('#his-data').css('background-image', 'url(' + json.header + ')');
$("#his-sta").text(json.statuses_count);
$("#his-follow").text(json.following_count);
$("#his-follower").text(json.followers_count);
$("#his-des").html(json.note);
$('#his-data').modal('open');
utl(json.id, '', acct_id);
flw(json.id, '', acct_id);
fer(json.id, '', acct_id);
$('ul.tabs').tabs();
$('#his-data').css('background-size', 'cover');
$("#his-since").text(crat(json.created_at));
}
//自分の時
if (json.acct == localStorage.getItem("user")) {
$("#his-follow-btn").hide();
$("#his-block-btn").hide();
$("#his-mute-btn").hide();
$("#his-notf-btn").hide();
$("#his-domain-btn").hide();
$("#my-data-nav").show();
$("#his-data-nav").hide();
$('ul.tabs').tabs('select_tab', 'his-tl');
showFav('', acct_id);
showBlo('', acct_id);
showMut('', acct_id);
showDom('', acct_id);
showReq('', acct_id);
profeditShow(json);
} else {
relations(user, acct_id);
}
todc();
});
}
//FF関係取得
function relations(user, acct_id) {
var domain = localStorage.getItem("domain_" + acct_id);
var at = localStorage.getItem(domain + "_at");
var start = "https://" + domain + "/api/v1/accounts/relationships?id=" + user;
fetch(start, {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + at
},
}).then(function(response) {
return response.json();
}).catch(function(error) {
todo(error);
console.error(error);
}).then(function(json) {
var json = json[0];
console.log(json);
if (json.following) {
//自分がフォローしている
$("#his-data").addClass("following");
$("#his-follow-btn").text("フォロー解除");
}
if (json.followed_by) {
//フォローされてる
$("#his-relation").text("フォローされています");
}
if (json.blocking) {
$("#his-data").addClass("blocking");
$("#his-block-btn").text("ブロック解除");
}
if (json.muting) {
$("#his-data").addClass("muting");
$("#his-mute-btn").text("ミュート解除");
}
if (json.muting_notifications) {
$("#his-data").addClass("mutingNotf");
$("#his-notf-btn").text("通知ミュート解除");
}
if (json.domain_blocking) {
$("#his-data").addClass("blockingDom");
$("#his-domain-btn").text("ドメインブロック解除");
}
});
}
//オールリセット
function hisclose() {
$('#his-data').modal('close');
$("#his-name").text("Loading");
$("#his-acct").text("");
$("#his-prof").attr("src", "./img/loading.svg");
$('#his-data').css('background-image', 'url(./img/loading.svg)');
$("#his-sta").text("");
$("#his-follow").text("");
$("#his-follower").text("");
$("#his-des").html("");
$('#his-data').css('background-size', 'cover');
$("#his-since").text("");
$("#his-data").removeClass("following");
$("#his-data").removeClass("muting");
$("#his-data").removeClass("blocking");
$("#his-data").removeClass("mutingNotf");
$("#his-data").removeClass("blockingDom");
$("#his-follow-btn").show();
$("#his-block-btn").show();
$("#his-mute-btn").show();
$("#his-notf-btn").show();
$("#his-domain-btn").show();
$("#his-follow-btn").text("フォロー");
$("#his-mute-btn").text("ミュート");
$("#his-block-btn").text("ブロック");
$("#his-notf-btn").text("通知ミュート");
$("#his-domain-btn").text("ドメインブロック");
$("#his-relation").text("");
$("#my-data-nav").hide();
$("#his-data-nav").show();
$(".cont-series").html("");
$("#domainblock").val("");
}

108
main.js Normal file
View File

@ -0,0 +1,108 @@
'use strict';
// Electronのモジュール
const electron = require("electron");
const fs = require("fs");
// アプリケーションをコントロールするモジュール
const app = electron.app;
// ウィンドウを作成するモジュール
const BrowserWindow = electron.BrowserWindow;
const {
download
} = require('electron-dl');
const openAboutWindow = require('about-window').default;
const join = require('path').join;
// メインウィンドウはGCされないようにグローバル宣言
let mainWindow;
var info_path = join(app.getPath("userData"), "window-size.json");
var window_size;
try {
window_size = JSON.parse(fs.readFileSync(info_path, 'utf8'));
} catch (e) {
window_size = {
width: 1000,
height: 750
}; // デフォルトバリュー
}
// 全てのウィンドウが閉じたら終了
app.on('window-all-closed', function() {
if (process.platform != 'darwin') {
app.quit();
}
});
function createWindow() {
// メイン画面の表示。ウィンドウの幅、高さを指定できる
mainWindow = new BrowserWindow(window_size);
electron.session.defaultSession.clearCache(() => {})
mainWindow.loadURL('file://' + __dirname + '/index.html');
// ウィンドウが閉じられたらアプリも終了
mainWindow.on('closed', function() {
mainWindow = null;
});
mainWindow.on('close', function() {
fs.writeFileSync(info_path, JSON.stringify(mainWindow.getBounds()));
});
}
// Electronの初期化完了後に実行
app.on('ready', createWindow);
var ipc = electron.ipcMain;
ipc.on('update', function(e, x, y) {
var window = new BrowserWindow({
width: 600,
height: 350,
"transparent": false, // ウィンドウの背景を透過
"frame": false, // 枠の無いウィンドウ
"resizable": false
});
window.loadURL('file://' + __dirname + '/update.html');
return "true"
})
ipc.on('nano', function(e, x, y) {
var window = new BrowserWindow({
width: 300,
height: 100,
"transparent": true, // ウィンドウの背景を透過
"frame": false, // 枠の無いウィンドウ
"resizable": false
});
window.loadURL('file://' + __dirname + '/nano.html');
window.setAlwaysOnTop(true);
window.setPosition(0, 0);
return "true"
})
ipc.on('download-btn', (e, args) => {
mainWindow.webContents.send('comp', "ダウンロードを開始します。");
const opts = {
openFolderWhenDone: true,
onProgress: function(e) {
mainWindow.webContents.send('prog', e);
},
saveAs: args
};
download(BrowserWindow.getFocusedWindow(),
'https://deskdownload.8i9.me/TheDesk-win32-x64.zip', opts)
.then(dl => {
mainWindow.webContents.send('comp', "ダウンロードが完了しました。");
app.quit();
})
.catch(console.error);
});
ipc.on('quit', (e, args) => {
app.quit();
});
ipc.on('about', (e, args) => {
openAboutWindow({
icon_path: join(__dirname, 'desk.png'),
copyright: 'Copyright (c) TheDesk on Mastodon 2018 & Cutls.com 2015 All Rights Reserved. CDN provided by AWS as 8i9.me belonging to Cutls.com.',
license: 'This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.',
description: 'ここに表示されているバージョンは内部バージョンで、一般的に使われている愛称とは異なります。',
bug_report_url: 'https://cutls.com/report',
css_path: join(__dirname, './css/about.css'),
adjust_window_size: true
});
});

5
node_modules/about-window/.npmignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
/typings
/.git
/example
npm-debug.log
node_modules

3
node_modules/about-window/.stylelintrc.json generated vendored Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "stylelint-config-standard"
}

19
node_modules/about-window/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2015 rhysd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.

100
node_modules/about-window/README.md generated vendored Normal file
View File

@ -0,0 +1,100 @@
'About This App' Window for [Electron](https://github.com/atom/electron) Apps
=============================================================================
[![npm version](https://badge.fury.io/js/about-window.svg)](https://www.npmjs.com/package/about-window)
[This package](https://www.npmjs.com/package/about-window) provides 'About This App' window for [Electron](https://github.com/atom/electron) applications.
- [x] Create 'About This App' window from given parameters
- [x] Icon path
- [x] Copy right
- [x] App name and Versions
- [x] Description
- [x] Gather package information from package.json
- [x] Automatically detect package.json
- [x] Adjust window size to its contents automatically
- [x] CSS customizability
You can install this module via [npm](https://www.npmjs.com/).
```sh
$ npm install about-window
```
Only one function is exported as default. Please see [TypeScript type definition](index.d.ts).
The function can be called from both main process and renderer process.
```typescript
export default function openAboutWindow(info: {
icon_path: string;
package_json_dir?: string;
bug_report_url?: string;
copyright?: string;
homepage?: string;
description?: string;
license?: string;
css_path?: string;
adjust_window_size?: boolean;
win_options?: BrowserWindowOptions;
}): BrowserWindow
```
Only `icon_path` property is required, others are optional.
I recommend to specify as below to extract information from package.json as much as possible.
Path to package.json is also automatically detected if possible.
```typescript
openAboutWindow({
icon_path: 'path/to/icon.png'
});
```
You can check [an example app](example) to know how to use this package.
```sh
$ git clone https://github.com/rhysd/about-window.git
$ cd about-window/example
$ npm install
$ npm start
# Or for debug
$ npm run debug
```
### Parameter's properties of `openAboutWindow()`
| Name | Description | Type |
|------|-------------|------|
| `icon_path` | Path to icon file of the application. The path is passed to `src` property of `<img>` element. **Required** | string |
| `package_json_dir` | Path to directory which contains package.json. If not specified, it will try to detect a path to package.json. If also failed, it gives up and show less information in 'About This App' window. **Optional** | string |
| `bug_report_url` | URL to bug report page. If not specified, 'bugs' entry in package.json is used. **Optional** | string |
| `copyright` | Copyright notice shown in window. If not specified, it is replaced with license description generated by 'license' entry of package.json. **Optional** | string |
| `homepage` | URL of application's web page. If not specified, 'homepage' entry of package.json is used instead. **Optional** | string |
| `description` | Description of the application. If not specified, 'description' entry of package.json is used instead. **Optional** | string |
| `license` | License of the application. If not specified, 'license' entry of package.json is used instead. This property is used when `copyright` is not specified. **Optional** | string |
| `win_options` | Options of 'About This App' window. It is merged into default options. **Optional** | [BrowserWindow options object](https://github.com/atom/electron/blob/master/docs/api/browser-window.md#new-browserwindowoptions) |
| `css_path` | Path to user-defined CSS file. It will be inserted to DOM of the window. **Optional** | string |
| `adjust_window_size` | Adjust the window size to its content not to show scroll bar. **Optional** | boolean |
| `open_devtools` | For debug purpose, Chrome DevTools will start when the window is opened **Optional** | boolean |
| `use_inner_html` | If `true`, set the value with `.innerHTML` on copyright, license and description Default is `false` **Optional** | boolean |
**Note:** If you set `use_inner_html` to `true`, please ensure that contents don't contain any untrusted external input
in order to avoid XSS. Be careful.
## Screen Shots
### Linux
![Linux screenshot](https://raw.githubusercontent.com/rhysd/ss/master/about-window/about-window-linux.png)
### OS X
![OS X screenshot](https://raw.githubusercontent.com/rhysd/ss/master/about-window/about-window-os-x.png)
### Windows
![Windows screenshot](https://raw.githubusercontent.com/rhysd/ss/master/about-window/about-window-windows.jpg)
## License
[MIT License](/LICENSE.txt).

27
node_modules/about-window/about.html generated vendored Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
<title>About This App</title>
<link rel="stylesheet" href="./styles/ui.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons|Open+Sans:300" rel="stylesheet">
</head>
<body>
<div class="logo">
<img id="app-icon" alt="App icon" height="200">
</div>
<h2 class="title"></h2>
<span class="description"></span>
<div class="copyright"></div>
<table class="versions"></table>
<footer class="footer">
<div class="link bug-report-link"></div>
</footer>
<!-- https://github.com/electron/electron/issues/2863 -->
<script>var exports = exports || {};</script>
<script src="./src/renderer.js"></script>
</body>
</html>

18
node_modules/about-window/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,18 @@
/// <reference types="electron" />
export interface AboutWindowInfo {
icon_path: string;
package_json_dir?: string;
bug_report_url?: string;
copyright?: string;
homepage?: string;
description?: string;
license?: string;
win_options?: Electron.BrowserWindowConstructorOptions;
css_path?: string;
adjust_window_size?: boolean;
open_devtools?: boolean;
use_inner_html?: boolean;
}
export default function openAboutWindow(into: AboutWindowInfo): Electron.BrowserWindow;

105
node_modules/about-window/package.json generated vendored Normal file
View File

@ -0,0 +1,105 @@
{
"_args": [
[
{
"raw": "about-window",
"scope": null,
"escapedName": "about-window",
"name": "about-window",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"C:\\Users\\ryuki\\TheDesk"
]
],
"_from": "about-window@latest",
"_id": "about-window@1.8.0",
"_inCache": true,
"_location": "/about-window",
"_nodeVersion": "6.10.3",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/about-window-1.8.0.tgz_1506494385445_0.4268775100354105"
},
"_npmUser": {
"name": "rhysd",
"email": "lin90162@yahoo.co.jp"
},
"_npmVersion": "3.10.10",
"_phantomChildren": {},
"_requested": {
"raw": "about-window",
"scope": null,
"escapedName": "about-window",
"name": "about-window",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/about-window/-/about-window-1.8.0.tgz",
"_shasum": "3e183cfaef4342e1fea6c442f4e43f682e9da580",
"_shrinkwrap": null,
"_spec": "about-window",
"_where": "C:\\Users\\ryuki\\TheDesk",
"author": {
"name": "rhysd",
"email": "lin90162@yahoo.co.jp"
},
"bugs": {
"url": "https://github.com/rhysd/electron-about-window/issues"
},
"dependencies": {},
"description": "'About App' window for Electron application",
"devDependencies": {
"@types/node": "^8.0.24",
"electron": "^1.7.5",
"stylelint": "^8.0.0",
"stylelint-config-standard": "^17.0.0",
"tslint": "^5.6.0",
"typescript": "^2.4.2"
},
"directories": {},
"dist": {
"shasum": "3e183cfaef4342e1fea6c442f4e43f682e9da580",
"tarball": "https://registry.npmjs.org/about-window/-/about-window-1.8.0.tgz"
},
"gitHead": "c2dac96372fcde38f2f842c00a34f024d0bdf4c1",
"homepage": "https://github.com/rhysd/electron-about-window#readme",
"keywords": [
"Electron",
"electron-component",
"about",
"window"
],
"license": "MIT",
"main": "src/index.js",
"maintainers": [
{
"name": "rhysd",
"email": "lin90162@yahoo.co.jp"
}
],
"name": "about-window",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/rhysd/electron-about-window.git"
},
"scripts": {
"build": "tsc -p src/",
"debug": "electron ./example",
"dep": "npm install",
"example": "NODE_ENV=production electron ./example",
"lint": "npm run tslint && npm run stylelint",
"preversion": "npm run lint && npm run build",
"start": "npm run dep && npm run build && npm run example",
"stylelint": "stylelint styles/*.css",
"tslint": "tslint -p ./src --type-check"
},
"version": "1.8.0"
}

115
node_modules/about-window/src/index.js generated vendored Normal file
View File

@ -0,0 +1,115 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
const fs_1 = require("fs");
const path = require("path");
let window = null;
function loadPackageJson(pkg_path) {
try {
return require(pkg_path);
}
catch (e) {
return null;
}
}
function detectPackageJson(specified_dir) {
if (specified_dir) {
const pkg = loadPackageJson(path.join(specified_dir, 'package.json'));
if (pkg !== null) {
return pkg;
}
else {
console.warn('about-window: package.json is not found in specified directory path: ' + specified_dir);
}
}
const app_name = electron_1.app.getName();
for (const mod_path of module.paths) {
if (!path.isAbsolute(mod_path)) {
continue;
}
const p = path.join(mod_path, '..', 'package.json');
try {
const stats = fs_1.statSync(p);
if (stats.isFile()) {
const pkg = loadPackageJson(p);
if (pkg !== null && pkg.productName === app_name) {
return pkg;
}
}
}
catch (e) {
}
}
return null;
}
function injectInfoFromPackageJson(info) {
const pkg = detectPackageJson(info.package_json_dir);
if (pkg === null) {
return info;
}
if (!info.description) {
info.description = pkg.description;
}
if (!info.license && pkg.license) {
const l = pkg.license;
info.license = typeof l === 'string' ? l : l.type;
}
if (!info.homepage) {
info.homepage = pkg.homepage;
}
if (!info.bug_report_url && typeof (pkg.bugs) === 'object') {
info.bug_report_url = pkg.bugs.url;
}
if (info.use_inner_html === undefined) {
info.use_inner_html = false;
}
return info;
}
function openAboutWindow(info) {
if (window !== null) {
window.focus();
return window;
}
const index_html = 'file://' + path.join(__dirname, '..', 'about.html');
const options = Object.assign({
width: 400,
height: 400,
useContentSize: true,
titleBarStyle: 'hidden-inset',
show: !info.adjust_window_size,
icon: info.icon_path,
}, info.win_options || {});
window = new (electron_1.BrowserWindow || electron_1.remote.BrowserWindow)(options);
window.once('closed', () => {
window = null;
});
window.loadURL(index_html);
window.webContents.on('will-navigate', (e, url) => {
e.preventDefault();
electron_1.shell.openExternal(url);
});
window.webContents.on('new-window', (e, url) => {
e.preventDefault();
electron_1.shell.openExternal(url);
});
window.webContents.once('dom-ready', () => {
delete info.win_options;
window.webContents.send('about-window:info', info);
if (info.open_devtools) {
if (process.versions.electron >= '1.4') {
window.webContents.openDevTools({ mode: 'detach' });
}
else {
window.webContents.openDevTools();
}
}
});
window.once('ready-to-show', () => {
window.show();
});
window.setMenu(null);
info = injectInfoFromPackageJson(info);
return window;
}
exports.default = openAboutWindow;
//# sourceMappingURL=index.js.map

1
node_modules/about-window/src/index.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;AAAA,uCAA2D;AAC3D,2BAA4B;AAC5B,6BAA6B;AAE7B,IAAI,MAAM,GAA2B,IAAI,CAAC;AAE1C,yBAAyB,QAAgB;IACrC,IAAI,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACT,MAAM,CAAC,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,2BAA2B,aAAqB;IAC5C,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QAChB,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;QACtE,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,CAAC;QACf,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,OAAO,CAAC,IAAI,CAAC,uEAAuE,GAAG,aAAa,CAAC,CAAC;QAC1G,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,cAAG,CAAC,OAAO,EAAE,CAAC;IAE/B,GAAG,CAAC,CAAC,MAAM,QAAQ,IAAK,MAAc,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC7B,QAAQ,CAAC;QACb,CAAC;QAED,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QACpD,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,aAAQ,CAAC,CAAC,CAAC,CAAC;YAC1B,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACjB,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;gBAC/B,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;oBAC/C,MAAM,CAAC,GAAG,CAAC;gBACf,CAAC;YACL,CAAC;QACL,CAAC;QAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEb,CAAC;IACL,CAAC;IAGD,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,mCAAmC,IAAqB;IACpD,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACrD,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC;QAEf,MAAM,CAAC,IAAI,CAAC;IAChB,CAAC;IAED,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IACvC,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IACjC,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;IACvC,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,yBAAwC,IAAqB;IACzD,EAAE,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;QAClB,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,MAAM,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;IAExE,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CACzB;QACI,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,GAAG;QACX,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,cAAc;QAC7B,IAAI,EAAE,CAAC,IAAI,CAAC,kBAAkB;QAC9B,IAAI,EAAE,IAAI,CAAC,SAAS;KACvB,EACD,IAAI,CAAC,WAAW,IAAI,EAAE,CACzB,CAAC;IAEF,MAAM,GAAG,IAAI,CAAC,wBAAa,IAAI,iBAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC;IAE9D,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;QACvB,MAAM,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE3B,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAC9C,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,gBAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAC3C,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,gBAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;QACtC,OAAO,IAAI,CAAC,WAAW,CAAC;QACxB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;QACnD,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;YACrB,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC;gBACrC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAC,CAAC,CAAC;YACtD,CAAC;YAAC,IAAI,CAAC,CAAC;gBACJ,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;YACtC,CAAC;QACL,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,IAAI,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAErB,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAEvC,MAAM,CAAC,MAAM,CAAC;AAClB,CAAC;AAzDD,kCAyDC"}

134
node_modules/about-window/src/index.ts generated vendored Normal file
View File

@ -0,0 +1,134 @@
import {app, BrowserWindow, remote, shell} from 'electron';
import {statSync} from 'fs';
import * as path from 'path';
let window: Electron.BrowserWindow = null;
function loadPackageJson(pkg_path: string): PackageJson {
try {
return require(pkg_path);
} catch (e) {
return null;
}
}
function detectPackageJson(specified_dir: string) {
if (specified_dir) {
const pkg = loadPackageJson(path.join(specified_dir, 'package.json'));
if (pkg !== null) {
return pkg;
} else {
console.warn('about-window: package.json is not found in specified directory path: ' + specified_dir);
}
}
const app_name = app.getName();
for (const mod_path of (module as any).paths) {
if (!path.isAbsolute(mod_path)) {
continue;
}
const p = path.join(mod_path, '..', 'package.json');
try {
const stats = statSync(p);
if (stats.isFile()) {
const pkg = loadPackageJson(p);
if (pkg !== null && pkg.productName === app_name) {
return pkg;
}
}
} catch (e) {
// File not found. Ignored.
}
}
// Note: Not found.
return null;
}
function injectInfoFromPackageJson(info: AboutWindowInfo) {
const pkg = detectPackageJson(info.package_json_dir);
if (pkg === null) {
// Note: Give up.
return info;
}
if (!info.description) {
info.description = pkg.description;
}
if (!info.license && pkg.license) {
const l = pkg.license;
info.license = typeof l === 'string' ? l : l.type;
}
if (!info.homepage) {
info.homepage = pkg.homepage;
}
if (!info.bug_report_url && typeof (pkg.bugs) === 'object') {
info.bug_report_url = pkg.bugs.url;
}
if (info.use_inner_html === undefined) {
info.use_inner_html = false;
}
return info;
}
export default function openAboutWindow(info: AboutWindowInfo) {
if (window !== null) {
window.focus();
return window;
}
const index_html = 'file://' + path.join(__dirname, '..', 'about.html');
const options = Object.assign(
{
width: 400,
height: 400,
useContentSize: true,
titleBarStyle: 'hidden-inset',
show: !info.adjust_window_size,
icon: info.icon_path,
},
info.win_options || {},
);
window = new (BrowserWindow || remote.BrowserWindow)(options);
window.once('closed', () => {
window = null;
});
window.loadURL(index_html);
window.webContents.on('will-navigate', (e, url) => {
e.preventDefault();
shell.openExternal(url);
});
window.webContents.on('new-window', (e, url) => {
e.preventDefault();
shell.openExternal(url);
});
window.webContents.once('dom-ready', () => {
delete info.win_options;
window.webContents.send('about-window:info', info);
if (info.open_devtools) {
if (process.versions.electron >= '1.4') {
window.webContents.openDevTools({mode: 'detach'});
} else {
window.webContents.openDevTools();
}
}
});
window.once('ready-to-show', () => {
window.show();
});
window.setMenu(null);
info = injectInfoFromPackageJson(info);
return window;
}

37
node_modules/about-window/src/lib.d.ts generated vendored Normal file
View File

@ -0,0 +1,37 @@
/// <reference types="electron" />
interface LicenseEntry {
type: string;
url: string;
}
interface PackageJson {
productName?: string;
description?: string;
homepage?: string;
license?: string | LicenseEntry;
bugs?: {
url: string;
};
}
interface AboutWindowInfo {
icon_path: string;
copyright?: string;
homepage?: string;
description?: string;
package_json_dir?: string;
license?: string;
bug_report_url?: string;
css_path?: string;
adjust_window_size?: boolean;
win_options?: Electron.BrowserWindowConstructorOptions;
open_devtools?: boolean;
use_inner_html?: boolean;
}
declare namespace NodeJS {
interface ProcessVersions {
[name: string]: string;
}
}

65
node_modules/about-window/src/renderer.js generated vendored Normal file
View File

@ -0,0 +1,65 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
electron_1.ipcRenderer.on('about-window:info', (_, info) => {
const app_name = electron_1.remote.app.getName();
const open_home = () => electron_1.shell.openExternal(info.homepage);
const content = info.use_inner_html ? 'innerHTML' : 'innerText';
document.title = `About ${app_name}`;
const title_elem = document.querySelector('.title');
title_elem.innerText = `${app_name} ${electron_1.remote.app.getVersion()}`;
title_elem.addEventListener('click', open_home);
if (info.homepage) {
document
.querySelector('.logo')
.addEventListener('click', open_home);
}
const copyright_elem = document.querySelector('.copyright');
if (info.copyright) {
copyright_elem[content] = info.copyright;
}
else if (info.license) {
copyright_elem[content] = `Distributed under ${info.license} license.`;
}
const icon_elem = document.getElementById('app-icon');
icon_elem.src = info.icon_path;
if (info.description) {
const desc_elem = document.querySelector('.description');
desc_elem[content] = info.description;
}
if (info.bug_report_url) {
const bug_report = document.querySelector('.bug-report-link');
bug_report.innerText = 'found bug?';
bug_report.addEventListener('click', e => {
e.preventDefault();
electron_1.shell.openExternal(info.bug_report_url);
});
}
if (info.css_path) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = info.css_path;
document.head.appendChild(link);
}
if (info.adjust_window_size) {
const height = document.body.scrollHeight;
const width = document.body.scrollWidth;
const win = electron_1.remote.getCurrentWindow();
if (height > 0 && width > 0) {
win.setContentSize(width, height + 40);
}
}
});
const versions = document.querySelector('.versions');
const vs = process.versions;
for (const name of ['electron', 'chrome', 'node', 'v8']) {
const tr = document.createElement('tr');
const name_td = document.createElement('td');
name_td.innerText = name;
tr.appendChild(name_td);
const version_td = document.createElement('td');
version_td.innerText = ' : ' + vs[name];
tr.appendChild(version_td);
versions.appendChild(tr);
}
//# sourceMappingURL=renderer.js.map

1
node_modules/about-window/src/renderer.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["renderer.ts"],"names":[],"mappings":";;AAAA,uCAAoD;AAEpD,sBAAW,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,CAAM,EAAE,IAAqB,EAAE,EAAE;IAClE,MAAM,QAAQ,GAAG,iBAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACtC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,gBAAK,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;IAChE,QAAQ,CAAC,KAAK,GAAG,SAAS,QAAQ,EAAE,CAAC;IAErC,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAuB,CAAC;IAC1E,UAAU,CAAC,SAAS,GAAG,GAAG,QAAQ,IAAI,iBAAM,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC;IAChE,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEhD,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChB,QAAQ;aACH,aAAa,CAAC,OAAO,CAAC;aACtB,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,cAAc,GAAG,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAQ,CAAC;IACnE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QACjB,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;IAC7C,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtB,cAAc,CAAC,OAAO,CAAC,GAAG,qBAAqB,IAAI,CAAC,OAAO,WAAW,CAAC;IAC3E,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAqB,CAAC;IAC1E,SAAS,CAAC,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;IAE/B,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QACnB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,cAAc,CAAQ,CAAC;QAChE,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;IAC1C,CAAC;IAED,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;QACtB,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,kBAAkB,CAAmB,CAAC;QAChF,UAAU,CAAC,SAAS,GAAG,YAAY,CAAC;QACpC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE;YACrC,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,gBAAK,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACP,CAAC;IAED,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC1B,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC;QACxC,MAAM,GAAG,GAAG,iBAAM,CAAC,gBAAgB,EAAE,CAAC;QACtC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;YAG1B,GAAG,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;QAC3C,CAAC;IACL,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;AACrD,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;AAC5B,GAAG,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IACzB,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACxB,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,CAAC,SAAS,GAAG,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACxC,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC"}

73
node_modules/about-window/src/renderer.ts generated vendored Normal file
View File

@ -0,0 +1,73 @@
import {ipcRenderer, remote, shell} from 'electron';
ipcRenderer.on('about-window:info', (_: any, info: AboutWindowInfo) => {
const app_name = remote.app.getName();
const open_home = () => shell.openExternal(info.homepage);
const content = info.use_inner_html ? 'innerHTML' : 'innerText';
document.title = `About ${app_name}`;
const title_elem = document.querySelector('.title') as HTMLHeadingElement;
title_elem.innerText = `${app_name} ${remote.app.getVersion()}`;
title_elem.addEventListener('click', open_home);
if (info.homepage) {
document
.querySelector('.logo')
.addEventListener('click', open_home);
}
const copyright_elem = document.querySelector('.copyright') as any;
if (info.copyright) {
copyright_elem[content] = info.copyright;
} else if (info.license) {
copyright_elem[content] = `Distributed under ${info.license} license.`;
}
const icon_elem = document.getElementById('app-icon') as HTMLImageElement;
icon_elem.src = info.icon_path;
if (info.description) {
const desc_elem = document.querySelector('.description') as any;
desc_elem[content] = info.description;
}
if (info.bug_report_url) {
const bug_report = document.querySelector('.bug-report-link') as HTMLDivElement;
bug_report.innerText = 'found bug?';
bug_report.addEventListener('click', e => {
e.preventDefault();
shell.openExternal(info.bug_report_url);
});
}
if (info.css_path) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = info.css_path;
document.head.appendChild(link);
}
if (info.adjust_window_size) {
const height = document.body.scrollHeight;
const width = document.body.scrollWidth;
const win = remote.getCurrentWindow();
if (height > 0 && width > 0) {
// Note:
// Add 30px(= about 2em) to add padding in window
win.setContentSize(width, height + 40);
}
}
});
const versions = document.querySelector('.versions');
const vs = process.versions;
for (const name of ['electron', 'chrome', 'node', 'v8']) {
const tr = document.createElement('tr');
const name_td = document.createElement('td');
name_td.innerText = name;
tr.appendChild(name_td);
const version_td = document.createElement('td');
version_td.innerText = ' : ' + vs[name];
tr.appendChild(version_td);
versions.appendChild(tr);
}

20
node_modules/about-window/src/tsconfig.json generated vendored Normal file
View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"removeComments": true,
"preserveConstEnums": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noEmitOnError": true,
"strictNullChecks": false,
"target": "es2015",
"sourceMap": true
},
"include": [
"**/*.ts"
]
}

64
node_modules/about-window/styles/ui.css generated vendored Normal file
View File

@ -0,0 +1,64 @@
body,
html {
width: 100%;
height: 100%;
-webkit-user-select: none;
user-select: none;
-webkit-app-region: drag;
}
body {
margin: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #333;
background-color: #eee;
font-size: 12px;
font-family: 'Helvetica', 'Arial', 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', 'メイリオ', Meiryo, ' Pゴシック', 'MS PGothic', sans-serif;
}
.logo {
width: 200px;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.title,
.copyright,
.description {
margin: 0.2em;
}
.title {
cursor: pointer;
}
.description {
margin-bottom: 1em;
text-align: center;
}
.versions {
border-collapse: collapse;
margin-top: 1em;
}
.copyright,
.versions {
color: #999;
}
.link {
cursor: pointer;
color: #80a0c2;
}
.bug-report-link {
-webkit-app-region: no-drag;
position: absolute;
right: 0.5em;
bottom: 0.5em;
}

127
node_modules/about-window/tslint.json generated vendored Normal file
View File

@ -0,0 +1,127 @@
{
"extends": ["tslint:recommended"],
"rules": {
"align": [
true,
"parameters",
"statements"
],
"ban": false,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": false,
"indent": [
true,
"spaces"
],
"interface-name": false,
"jsdoc-format": true,
"label-position": true,
"max-line-length": false,
"member-access": false,
"member-ordering": [
true,
"public-before-private",
"static-before-instance",
"variables-before-functions"
],
"no-any": false,
"no-arg": true,
"no-bitwise": false,
"no-conditional-assignment": true,
"no-consecutive-blank-lines": false,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-constructor-vars": false,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-inferrable-types": false,
"no-internal-module": true,
"no-require-imports": false,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-switch-case-fall-through": false,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-unsafe-finally": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"no-var-requires": true,
"object-literal-sort-keys": false,
"object-literal-key-quotes": [
true,
"as-needed"
],
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"quotemark": [
true,
"single",
"avoid-escape",
"jsx-double"
],
"radix": true,
"semicolon": true,
"switch-default": true,
"trailing-comma": [
true,
{
"multiline": "always",
"singleline": "never"
}
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef": [
false
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"use-strict": false,
"variable-name": [
false,
"check-format",
"allow-leading-underscore",
"ban-keywords"
],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"no-namespace": false,
"arrow-parens": false
}
}

134
node_modules/electron-dl/index.js generated vendored Normal file
View File

@ -0,0 +1,134 @@
'use strict';
const path = require('path');
const electron = require('electron');
const unusedFilename = require('unused-filename');
const pupa = require('pupa');
const extName = require('ext-name');
const app = electron.app;
const shell = electron.shell;
function getFilenameFromMime(name, mime) {
const exts = extName.mime(mime);
if (exts.length !== 1) {
return name;
}
return `${name}.${exts[0].ext}`;
}
function registerListener(session, opts = {}, cb = () => {}) {
const downloadItems = new Set();
let receivedBytes = 0;
let completedBytes = 0;
let totalBytes = 0;
const activeDownloadItems = () => downloadItems.size;
const progressDownloadItems = () => receivedBytes / totalBytes;
const listener = (e, item, webContents) => {
downloadItems.add(item);
totalBytes += item.getTotalBytes();
let hostWebContents = webContents;
if (webContents.getType() === 'webview') {
hostWebContents = webContents.hostWebContents;
}
const win = electron.BrowserWindow.fromWebContents(hostWebContents);
const dir = opts.directory || app.getPath('downloads');
let filePath;
if (opts.filename) {
filePath = path.join(dir, opts.filename);
} else {
const filename = item.getFilename();
const name = path.extname(filename) ? filename : getFilenameFromMime(filename, item.getMimeType());
filePath = unusedFilename.sync(path.join(dir, name));
}
const errorMessage = opts.errorMessage || 'The download of {filename} was interrupted';
const errorTitle = opts.errorTitle || 'Download Error';
if (!opts.saveAs) {
item.setSavePath(filePath);
}
item.on('updated', () => {
receivedBytes = [...downloadItems].reduce((receivedBytes, item) => {
receivedBytes += item.getReceivedBytes();
return receivedBytes;
}, completedBytes);
if (['darwin', 'linux'].includes(process.platform)) {
app.setBadgeCount(activeDownloadItems());
}
if (!win.isDestroyed()) {
win.setProgressBar(progressDownloadItems());
}
if (typeof opts.onProgress === 'function') {
opts.onProgress(progressDownloadItems());
}
});
item.on('done', (e, state) => {
completedBytes += item.getTotalBytes();
downloadItems.delete(item);
if (['darwin', 'linux'].includes(process.platform)) {
app.setBadgeCount(activeDownloadItems());
}
if (!win.isDestroyed() && !activeDownloadItems()) {
win.setProgressBar(-1);
receivedBytes = 0;
completedBytes = 0;
totalBytes = 0;
}
if (state === 'interrupted') {
const message = pupa(errorMessage, {filename: item.getFilename()});
electron.dialog.showErrorBox(errorTitle, message);
cb(new Error(message));
} else if (state === 'completed') {
if (process.platform === 'darwin') {
app.dock.downloadFinished(filePath);
}
if (opts.openFolderWhenDone) {
shell.showItemInFolder(filePath);
}
if (opts.unregisterWhenDone) {
session.removeListener('will-download', listener);
}
cb(null, item);
}
});
};
session.on('will-download', listener);
}
module.exports = (opts = {}) => {
app.on('session-created', session => {
registerListener(session, opts);
});
};
module.exports.download = (win, url, opts) => new Promise((resolve, reject) => {
opts = Object.assign({}, opts, {unregisterWhenDone: true});
registerListener(win.webContents.session, opts, (err, item) => {
if (err) {
reject(err);
} else {
resolve(item);
}
});
win.webContents.downloadURL(url);
});

9
node_modules/electron-dl/license generated vendored Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

116
node_modules/electron-dl/package.json generated vendored Normal file
View File

@ -0,0 +1,116 @@
{
"_args": [
[
{
"raw": "electron-dl",
"scope": null,
"escapedName": "electron-dl",
"name": "electron-dl",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"C:\\Users\\ryuki\\TheDesk"
]
],
"_from": "electron-dl@latest",
"_id": "electron-dl@1.10.0",
"_inCache": true,
"_location": "/electron-dl",
"_nodeVersion": "4.8.3",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/electron-dl-1.10.0.tgz_1502139802256_0.5021310658194125"
},
"_npmUser": {
"name": "sindresorhus",
"email": "sindresorhus@gmail.com"
},
"_npmVersion": "2.15.11",
"_phantomChildren": {},
"_requested": {
"raw": "electron-dl",
"scope": null,
"escapedName": "electron-dl",
"name": "electron-dl",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.10.0.tgz",
"_shasum": "f94416064056fc6f2a86ae498614c93526890af9",
"_shrinkwrap": null,
"_spec": "electron-dl",
"_where": "C:\\Users\\ryuki\\TheDesk",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/electron-dl/issues"
},
"dependencies": {
"ext-name": "^5.0.0",
"pupa": "^1.0.0",
"unused-filename": "^1.0.0"
},
"description": "Simplified file downloads for your Electron app",
"devDependencies": {
"ava": "^0.21.0",
"cp-file": "^4.2.0",
"electron": "^1.3.3",
"minimist": "^1.2.0",
"node-static": "^0.7.9",
"pify": "^3.0.0",
"spectron": "^3.7.2",
"uuid": "^3.1.0",
"xo": "*"
},
"directories": {},
"dist": {
"shasum": "f94416064056fc6f2a86ae498614c93526890af9",
"tarball": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.10.0.tgz"
},
"files": [
"index.js"
],
"gitHead": "b47d7e9ee5e8c89b08ed86e9e395aa052e39f4bf",
"homepage": "https://github.com/sindresorhus/electron-dl#readme",
"keywords": [
"electron",
"app",
"file",
"download",
"downloader",
"progress"
],
"license": "MIT",
"maintainers": [
{
"name": "sindresorhus",
"email": "sindresorhus@gmail.com"
}
],
"name": "electron-dl",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/electron-dl.git"
},
"scripts": {
"start": "electron run.js",
"test": "xo && ava"
},
"version": "1.10.0",
"xo": {
"envs": [
"node",
"browser"
]
}
}

155
node_modules/electron-dl/readme.md generated vendored Normal file
View File

@ -0,0 +1,155 @@
# electron-dl [![Build Status](https://travis-ci.org/sindresorhus/electron-dl.svg?branch=master)](https://travis-ci.org/sindresorhus/electron-dl)
> Simplified file downloads for your [Electron](http://electron.atom.io) app
## Why?
- One function call instead of having to manually implement a lot of [boilerplate](index.js).
- Saves the file to the users Downloads directory instead of prompting.
- Bounces the Downloads directory in the dock when done. *(macOS)*
- Handles multiple downloads.
- Shows badge count *(macOS & Linux only)* and download progress. Example on macOS:
<img src="screenshot.png" width="82">
## Install
```
$ npm install electron-dl
```
## Usage
### Register it for all windows
This is probably what you want for your app.
```js
const {app, BrowserWindow} = require('electron');
require('electron-dl')();
let win;
app.on('ready', () => {
win = new BrowserWindow();
});
```
### Use it manually
This can be useful if you need download functionality in a reusable module.
```js
const {app, BrowserWindow, ipcMain} = require('electron');
const {download} = require('electron-dl');
ipcMain.on('download-btn', (e, args) => {
download(BrowserWindow.getFocusedWindow(), args.url)
.then(dl => console.log(dl.getSavePath()))
.catch(console.error);
});
```
## API
### electronDl([options])
### electronDl.download(window, url, [options]): Promise<[DownloadItem](https://github.com/electron/electron/blob/master/docs/api/download-item.md)>
### window
Type: `BrowserWindow`
Window to register the behavior on.
### url
Type: `string`
URL to download.
### options
#### saveAs
Type: `boolean`<br>
Default: `false`
Show a `Save As…` dialog instead of downloading immediately.
Note: Only use this option when strictly necessary. Downloading directly without a prompt is a much better user experience.
#### directory
Type: `string`<br>
Default: [User's downloads directory](http://electron.atom.io/docs/api/app/#appgetpathname)
Directory to save the file in.
#### filename
Type: `string`<br>
Default: [`downloadItem.getFilename()`](https://electron.atom.io/docs/api/download-item/#downloaditemgetfilename)
Name of the saved file.
This option only makes sense for `electronDl.download()`.
#### errorTitle
Type: `string`<br>
Default: `Download Error`
Title of the error dialog. Can be customized for localization.
#### errorMessage
Type: `string`<br>
Default: `The download of {filename} was interrupted`
Message of the error dialog. `{filename}` is replaced with the name of the actual file. Can be customized for localization.
#### onProgress
Type: `Function`
Optional callback that receives a number between `0` and `1` representing the progress of the current download.
#### openFolderWhenDone
Type: `boolean`<br>
Default: `false`
Reveal the downloaded file in the system file manager, and if possible, select the file.
## Development
After making changes, run the automated tests:
```
$ npm test
```
And before submitting a pull request, run the manual tests to manually verify that everything works:
```
npm start
```
## Related
- [electron-debug](https://github.com/sindresorhus/electron-debug) - Adds useful debug features to your Electron app
- [electron-context-menu](https://github.com/sindresorhus/electron-context-menu) - Context menu for your Electron app
- [electron-store](https://github.com/sindresorhus/electron-store) - Save and load data like user preferences, app state, cache, etc
- [electron-unhandled](https://github.com/sindresorhus/electron-unhandled) - Catch unhandled errors and promise rejections in your Electron app
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)

18
node_modules/ext-list/index.js generated vendored Normal file
View File

@ -0,0 +1,18 @@
'use strict';
var mimeDb = require('mime-db');
module.exports = function () {
var ret = {};
Object.keys(mimeDb).forEach(function (x) {
var val = mimeDb[x];
if (val.extensions && val.extensions.length > 0) {
val.extensions.forEach(function (y) {
ret[y] = x;
});
}
});
return ret;
};

21
node_modules/ext-list/license generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

100
node_modules/ext-list/package.json generated vendored Normal file
View File

@ -0,0 +1,100 @@
{
"_args": [
[
{
"raw": "ext-list@^2.0.0",
"scope": null,
"escapedName": "ext-list",
"name": "ext-list",
"rawSpec": "^2.0.0",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"C:\\Users\\ryuki\\TheDesk\\node_modules\\ext-name"
]
],
"_from": "ext-list@>=2.0.0 <3.0.0",
"_id": "ext-list@2.2.2",
"_inCache": true,
"_location": "/ext-list",
"_nodeVersion": "8.0.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/ext-list-2.2.2.tgz_1496309328028_0.20976057252846658"
},
"_npmUser": {
"name": "kevva",
"email": "kevinmartensson@gmail.com"
},
"_npmVersion": "5.0.0",
"_phantomChildren": {},
"_requested": {
"raw": "ext-list@^2.0.0",
"scope": null,
"escapedName": "ext-list",
"name": "ext-list",
"rawSpec": "^2.0.0",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/ext-name"
],
"_resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
"_shasum": "0b98e64ed82f5acf0f2931babf69212ef52ddd37",
"_shrinkwrap": null,
"_spec": "ext-list@^2.0.0",
"_where": "C:\\Users\\ryuki\\TheDesk\\node_modules\\ext-name",
"author": {
"name": "Kevin Mårtensson",
"email": "kevinmartensson@gmail.com",
"url": "https://github.com/kevva"
},
"bugs": {
"url": "https://github.com/kevva/ext-list/issues"
},
"dependencies": {
"mime-db": "^1.28.0"
},
"description": "List of known file extensions and their MIME types",
"devDependencies": {
"ava": "*",
"xo": "*"
},
"directories": {},
"dist": {
"integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
"shasum": "0b98e64ed82f5acf0f2931babf69212ef52ddd37",
"tarball": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz"
},
"engines": {
"node": ">=0.10.0"
},
"files": [
"index.js"
],
"gitHead": "cef670e7ccc4a8c239b8d58526556b6ec23d1e96",
"homepage": "https://github.com/kevva/ext-list#readme",
"keywords": [
"ext",
"mime"
],
"license": "MIT",
"maintainers": [
{
"name": "kevva",
"email": "kevinmartensson@gmail.com"
}
],
"name": "ext-list",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/kevva/ext-list.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "2.2.2"
}

25
node_modules/ext-list/readme.md generated vendored Normal file
View File

@ -0,0 +1,25 @@
# ext-list [![Build Status](http://img.shields.io/travis/kevva/ext-list.svg?style=flat)](https://travis-ci.org/kevva/ext-list)
> Return a list of known [file extensions](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types) and their MIME types
## Install
```
$ npm install --save ext-list
```
## Usage
```js
const extList = require('ext-list');
extList();
//=> {'123': 'application/vnd.lotus-1-2-3', ez: 'application/andrew-inset', aw: 'application/applixware', ...}
```
## License
MIT © [Kevin Mårtensson](https://github.com/kevva)

31
node_modules/ext-name/index.js generated vendored Normal file
View File

@ -0,0 +1,31 @@
'use strict';
const extList = require('ext-list');
const sortKeysLength = require('sort-keys-length');
module.exports = str => {
const obj = sortKeysLength.desc(extList());
const exts = Object.keys(obj).filter(x => str.endsWith(x));
if (exts.length === 0) {
return [];
}
return exts.map(x => ({
ext: x,
mime: obj[x]
}));
};
module.exports.mime = str => {
const obj = sortKeysLength.desc(extList());
const exts = Object.keys(obj).filter(x => obj[x] === str);
if (exts.length === 0) {
return [];
}
return exts.map(x => ({
ext: x,
mime: obj[x]
}));
};

21
node_modules/ext-name/license generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

102
node_modules/ext-name/package.json generated vendored Normal file
View File

@ -0,0 +1,102 @@
{
"_args": [
[
{
"raw": "ext-name@^5.0.0",
"scope": null,
"escapedName": "ext-name",
"name": "ext-name",
"rawSpec": "^5.0.0",
"spec": ">=5.0.0 <6.0.0",
"type": "range"
},
"C:\\Users\\ryuki\\TheDesk\\node_modules\\electron-dl"
]
],
"_from": "ext-name@>=5.0.0 <6.0.0",
"_id": "ext-name@5.0.0",
"_inCache": true,
"_location": "/ext-name",
"_nodeVersion": "8.0.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/ext-name-5.0.0.tgz_1496851886409_0.42046912061050534"
},
"_npmUser": {
"name": "kevva",
"email": "kevinmartensson@gmail.com"
},
"_npmVersion": "5.0.3",
"_phantomChildren": {},
"_requested": {
"raw": "ext-name@^5.0.0",
"scope": null,
"escapedName": "ext-name",
"name": "ext-name",
"rawSpec": "^5.0.0",
"spec": ">=5.0.0 <6.0.0",
"type": "range"
},
"_requiredBy": [
"/electron-dl"
],
"_resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz",
"_shasum": "70781981d183ee15d13993c8822045c506c8f0a6",
"_shrinkwrap": null,
"_spec": "ext-name@^5.0.0",
"_where": "C:\\Users\\ryuki\\TheDesk\\node_modules\\electron-dl",
"author": {
"name": "Kevin Mårtensson",
"email": "kevinmartensson@gmail.com",
"url": "https://github.com/kevva"
},
"bugs": {
"url": "https://github.com/kevva/ext-name/issues"
},
"dependencies": {
"ext-list": "^2.0.0",
"sort-keys-length": "^1.0.0"
},
"description": "Get the file extension and MIME type from a file",
"devDependencies": {
"ava": "*",
"xo": "*"
},
"directories": {},
"dist": {
"integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
"shasum": "70781981d183ee15d13993c8822045c506c8f0a6",
"tarball": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"gitHead": "4d84e68c9876d1d0933bd832f60d84ed1eeac9da",
"homepage": "https://github.com/kevva/ext-name#readme",
"keywords": [
"ext",
"extname",
"mime"
],
"license": "MIT",
"maintainers": [
{
"name": "kevva",
"email": "kevinmartensson@gmail.com"
}
],
"name": "ext-name",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/kevva/ext-name.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "5.0.0"
}

Some files were not shown because too many files have changed in this diff Show More