ContextMenu.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. <template>
  2. <div class="modal-stack">
  3. <b-modal ref="ctxModal"
  4. id="ctx-modal"
  5. hide-header
  6. hide-footer
  7. centered
  8. rounded
  9. size="sm"
  10. body-class="list-group-flush p-0 rounded">
  11. <div class="list-group text-center">
  12. <!-- <div v-if="status && status.account.id != profile.id && ctxMenuRelationship && ctxMenuRelationship.following" class="list-group-item rounded cursor-pointer font-weight-bold text-danger" @click="ctxMenuUnfollow()">Unfollow</div>
  13. <div v-if="status && status.account.id != profile.id && ctxMenuRelationship && !ctxMenuRelationship.following" class="list-group-item rounded cursor-pointer font-weight-bold text-primary" @click="ctxMenuFollow()">Follow</div> -->
  14. <div v-if="status.visibility !== 'archived'" class="list-group-item rounded cursor-pointer" @click="ctxMenuGoToPost()">View Post</div>
  15. <div v-if="status.visibility !== 'archived'" class="list-group-item rounded cursor-pointer" @click="ctxMenuGoToProfile()">View Profile</div>
  16. <!-- <div v-if="status && status.local == true && !status.in_reply_to_id" class="list-group-item rounded cursor-pointer" @click="ctxMenuEmbed()">Embed</div>
  17. <div class="list-group-item rounded cursor-pointer" @click="ctxMenuCopyLink()">Copy Link</div> -->
  18. <div v-if="status.visibility !== 'archived'" class="list-group-item rounded cursor-pointer" @click="ctxMenuShare()">Share</div>
  19. <div v-if="status && profile && profile.is_admin == true && status.visibility !== 'archived'" class="list-group-item rounded cursor-pointer" @click="ctxModMenuShow()">Moderation Tools</div>
  20. <div v-if="status && status.account.id != profile.id" class="list-group-item rounded cursor-pointer text-danger" @click="ctxMenuReportPost()">Report</div>
  21. <div v-if="status && profile.id == status.account.id && status.visibility !== 'archived'" class="list-group-item rounded cursor-pointer text-danger" @click="archivePost(status)">Archive</div>
  22. <div v-if="status && profile.id == status.account.id && status.visibility == 'archived'" class="list-group-item rounded cursor-pointer text-danger" @click="unarchivePost(status)">Unarchive</div>
  23. <div v-if="status && (profile.is_admin || profile.id == status.account.id) && status.visibility !== 'archived'" class="list-group-item rounded cursor-pointer text-danger" @click="deletePost(status)">Delete</div>
  24. <div class="list-group-item rounded cursor-pointer text-lighter" @click="closeCtxMenu()">Cancel</div>
  25. </div>
  26. </b-modal>
  27. <b-modal ref="ctxModModal"
  28. id="ctx-mod-modal"
  29. hide-header
  30. hide-footer
  31. centered
  32. rounded
  33. size="sm"
  34. body-class="list-group-flush p-0 rounded">
  35. <div class="list-group text-center">
  36. <p class="py-2 px-3 mb-0">
  37. <div class="text-center font-weight-bold text-danger">Moderation Tools</div>
  38. <div class="small text-center text-muted">Select one of the following options</div>
  39. </p>
  40. <div class="list-group-item rounded cursor-pointer" @click="moderatePost(status, 'unlist')">Unlist from Timelines</div>
  41. <div v-if="status.sensitive" class="list-group-item rounded cursor-pointer" @click="moderatePost(status, 'remcw')">Remove Content Warning</div>
  42. <div v-else class="list-group-item rounded cursor-pointer" @click="moderatePost(status, 'addcw')">Add Content Warning</div>
  43. <div class="list-group-item rounded cursor-pointer" @click="moderatePost(status, 'spammer')">
  44. Mark as Spammer<br />
  45. <span class="small">Unlist + CW existing and future posts</span>
  46. </div>
  47. <!-- <div class="list-group-item rounded cursor-pointer" @click="ctxModOtherMenuShow()">Other</div> -->
  48. <div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxModMenuClose()">Cancel</div>
  49. </div>
  50. </b-modal>
  51. <b-modal ref="ctxModOtherModal"
  52. id="ctx-mod-other-modal"
  53. hide-header
  54. hide-footer
  55. centered
  56. rounded
  57. size="sm"
  58. body-class="list-group-flush p-0 rounded">
  59. <div class="list-group text-center">
  60. <p class="py-2 px-3 mb-0">
  61. <div class="text-center font-weight-bold text-danger">Moderation Tools</div>
  62. <div class="small text-center text-muted">Select one of the following options</div>
  63. </p>
  64. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="confirmModal()">Unlist Posts</div>
  65. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="confirmModal()">Moderation Log</div>
  66. <div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxModOtherMenuClose()">Cancel</div>
  67. </div>
  68. </b-modal>
  69. <b-modal ref="ctxShareModal"
  70. id="ctx-share-modal"
  71. title="Share"
  72. hide-footer
  73. hide-header
  74. centered
  75. rounded
  76. size="sm"
  77. body-class="list-group-flush p-0 rounded text-center">
  78. <div class="list-group-item rounded cursor-pointer" @click="shareStatus(status, $event)">{{status.reblogged ? 'Unshare' : 'Share'}} to Followers</div>
  79. <div class="list-group-item rounded cursor-pointer" @click="ctxMenuCopyLink()">Copy Link</div>
  80. <div v-if="status && status.local == true && !status.in_reply_to_id" class="list-group-item rounded cursor-pointer" @click="ctxMenuEmbed()">Embed</div>
  81. <!-- <div class="list-group-item rounded cursor-pointer border-top-0">Email</div>
  82. <div class="list-group-item rounded cursor-pointer">Facebook</div>
  83. <div class="list-group-item rounded cursor-pointer">Mastodon</div>
  84. <div class="list-group-item rounded cursor-pointer">Pinterest</div>
  85. <div class="list-group-item rounded cursor-pointer">Pixelfed</div>
  86. <div class="list-group-item rounded cursor-pointer">Twitter</div>
  87. <div class="list-group-item rounded cursor-pointer">VK</div> -->
  88. <div class="list-group-item rounded cursor-pointer text-lighter" @click="closeCtxShareMenu()">Cancel</div>
  89. </b-modal>
  90. <b-modal ref="ctxEmbedModal"
  91. id="ctx-embed-modal"
  92. hide-header
  93. hide-footer
  94. centered
  95. rounded
  96. size="md"
  97. body-class="p-2 rounded">
  98. <div>
  99. <div class="form-group">
  100. <textarea class="form-control disabled text-monospace" rows="8" style="overflow-y:hidden;border: 1px solid #efefef; font-size: 12px; line-height: 18px; margin: 0 0 7px;resize:none;" v-model="ctxEmbedPayload" disabled=""></textarea>
  101. </div>
  102. <div class="form-group pl-2 d-flex justify-content-center">
  103. <div class="form-check mr-3">
  104. <input class="form-check-input" type="checkbox" v-model="ctxEmbedShowCaption" :disabled="ctxEmbedCompactMode == true">
  105. <label class="form-check-label font-weight-light">
  106. Show Caption
  107. </label>
  108. </div>
  109. <div class="form-check mr-3">
  110. <input class="form-check-input" type="checkbox" v-model="ctxEmbedShowLikes" :disabled="ctxEmbedCompactMode == true">
  111. <label class="form-check-label font-weight-light">
  112. Show Likes
  113. </label>
  114. </div>
  115. <div class="form-check">
  116. <input class="form-check-input" type="checkbox" v-model="ctxEmbedCompactMode">
  117. <label class="form-check-label font-weight-light">
  118. Compact Mode
  119. </label>
  120. </div>
  121. </div>
  122. <hr>
  123. <button :class="copiedEmbed ? 'btn btn-primary btn-block btn-sm py-1 font-weight-bold disabed': 'btn btn-primary btn-block btn-sm py-1 font-weight-bold'" @click="ctxCopyEmbed" :disabled="copiedEmbed">{{copiedEmbed ? 'Embed Code Copied!' : 'Copy Embed Code'}}</button>
  124. <p class="mb-0 px-2 small text-muted">By using this embed, you agree to our <a href="/site/terms">Terms of Use</a></p>
  125. </div>
  126. </b-modal>
  127. <b-modal ref="ctxReport"
  128. id="ctx-report"
  129. hide-header
  130. hide-footer
  131. centered
  132. rounded
  133. size="sm"
  134. body-class="list-group-flush p-0 rounded">
  135. <p class="py-2 px-3 mb-0">
  136. <div class="text-center font-weight-bold text-danger">Report</div>
  137. <div class="small text-center text-muted">Select one of the following options</div>
  138. </p>
  139. <div class="list-group text-center">
  140. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('spam')">Spam</div>
  141. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('sensitive')">Sensitive Content</div>
  142. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('abusive')">Abusive or Harmful</div>
  143. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="openCtxReportOtherMenu()">Other</div>
  144. <!-- <div class="list-group-item rounded cursor-pointer" @click="ctxReportMenuGoBack()">Go Back</div> -->
  145. <div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxReportMenuGoBack()">Cancel</div>
  146. </div>
  147. </b-modal>
  148. <b-modal ref="ctxReportOther"
  149. id="ctx-report-other"
  150. hide-header
  151. hide-footer
  152. centered
  153. rounded
  154. size="sm"
  155. body-class="list-group-flush p-0 rounded">
  156. <p class="py-2 px-3 mb-0">
  157. <div class="text-center font-weight-bold text-danger">Report</div>
  158. <div class="small text-center text-muted">Select one of the following options</div>
  159. </p>
  160. <div class="list-group text-center">
  161. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('underage')">Underage Account</div>
  162. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('copyright')">Copyright Infringement</div>
  163. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('impersonation')">Impersonation</div>
  164. <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('scam')">Scam or Fraud</div>
  165. <!-- <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('terrorism')">Terrorism Related</div> -->
  166. <!-- <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('other')">Other or Not listed</div> -->
  167. <!-- <div class="list-group-item rounded cursor-pointer" @click="ctxReportOtherMenuGoBack()">Go Back</div> -->
  168. <div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxReportOtherMenuGoBack()">Cancel</div>
  169. </div>
  170. </b-modal>
  171. <b-modal ref="ctxConfirm"
  172. id="ctx-confirm"
  173. hide-header
  174. hide-footer
  175. centered
  176. rounded
  177. size="sm"
  178. body-class="list-group-flush p-0 rounded">
  179. <div class="d-flex align-items-center justify-content-center py-3">
  180. <div>{{ this.confirmModalTitle }}</div>
  181. </div>
  182. <div class="d-flex border-top btn-group btn-group-block rounded-0" role="group">
  183. <button type="button" class="btn btn-outline-lighter border-left-0 border-top-0 border-bottom-0 border-right py-2" style="color: rgb(0,122,255) !important;" @click.prevent="confirmModalCancel()">Cancel</button>
  184. <button type="button" class="btn btn-outline-lighter border-0" style="color: rgb(0,122,255) !important;" @click.prevent="confirmModalConfirm()">Confirm</button>
  185. </div>
  186. </b-modal>
  187. </div>
  188. </template>
  189. <script type="text/javascript">
  190. export default {
  191. props: [
  192. 'status',
  193. 'profile'
  194. ],
  195. data() {
  196. return {
  197. ctxMenuStatus: false,
  198. ctxMenuRelationship: false,
  199. ctxEmbedPayload: false,
  200. copiedEmbed: false,
  201. replySending: false,
  202. ctxEmbedShowCaption: true,
  203. ctxEmbedShowLikes: false,
  204. ctxEmbedCompactMode: false,
  205. confirmModalTitle: 'Are you sure?',
  206. confirmModalIdentifer: null,
  207. confirmModalType: false,
  208. }
  209. },
  210. watch: {
  211. ctxEmbedShowCaption: function (n,o) {
  212. if(n == true) {
  213. this.ctxEmbedCompactMode = false;
  214. }
  215. let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
  216. this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
  217. },
  218. ctxEmbedShowLikes: function (n,o) {
  219. if(n == true) {
  220. this.ctxEmbedCompactMode = false;
  221. }
  222. let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
  223. this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
  224. },
  225. ctxEmbedCompactMode: function (n,o) {
  226. if(n == true) {
  227. this.ctxEmbedShowCaption = false;
  228. this.ctxEmbedShowLikes = false;
  229. }
  230. let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
  231. this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
  232. }
  233. },
  234. methods: {
  235. open() {
  236. this.ctxMenu();
  237. },
  238. ctxMenu() {
  239. this.ctxMenuStatus = this.status;
  240. this.ctxEmbedPayload = window.App.util.embed.post(this.status.url);
  241. if(this.status.account.id == this.profile.id) {
  242. this.ctxMenuRelationship = false;
  243. this.$refs.ctxModal.show();
  244. } else {
  245. axios.get('/api/pixelfed/v1/accounts/relationships', {
  246. params: {
  247. 'id[]': this.status.account.id
  248. }
  249. }).then(res => {
  250. this.ctxMenuRelationship = res.data[0];
  251. this.$refs.ctxModal.show();
  252. });
  253. }
  254. },
  255. closeCtxMenu() {
  256. this.copiedEmbed = false;
  257. this.ctxMenuStatus = false;
  258. this.ctxMenuRelationship = false;
  259. this.$refs.ctxModal.hide();
  260. this.$refs.ctxReport.hide();
  261. this.$refs.ctxReportOther.hide();
  262. this.closeModals();
  263. },
  264. ctxMenuCopyLink() {
  265. let status = this.ctxMenuStatus;
  266. navigator.clipboard.writeText(status.url);
  267. this.closeModals();
  268. return;
  269. },
  270. ctxMenuGoToPost() {
  271. let status = this.ctxMenuStatus;
  272. window.location.href = this.statusUrl(status);
  273. this.closeCtxMenu();
  274. return;
  275. },
  276. ctxMenuGoToProfile() {
  277. let status = this.ctxMenuStatus;
  278. window.location.href = this.profileUrl(status);
  279. this.closeCtxMenu();
  280. return;
  281. },
  282. ctxMenuFollow() {
  283. let id = this.ctxMenuStatus.account.id;
  284. axios.post('/i/follow', {
  285. item: id
  286. }).then(res => {
  287. let username = this.ctxMenuStatus.account.acct;
  288. this.closeCtxMenu();
  289. setTimeout(function() {
  290. swal('Follow successful!', 'You are now following ' + username, 'success');
  291. }, 500);
  292. });
  293. },
  294. ctxMenuUnfollow() {
  295. let id = this.ctxMenuStatus.account.id;
  296. axios.post('/i/follow', {
  297. item: id
  298. }).then(res => {
  299. let username = this.ctxMenuStatus.account.acct;
  300. if(this.scope == 'home') {
  301. this.feed = this.feed.filter(s => {
  302. return s.account.id != this.ctxMenuStatus.account.id;
  303. });
  304. }
  305. this.closeCtxMenu();
  306. setTimeout(function() {
  307. swal('Unfollow successful!', 'You are no longer following ' + username, 'success');
  308. }, 500);
  309. });
  310. },
  311. ctxMenuReportPost() {
  312. this.$refs.ctxModal.hide();
  313. this.$refs.ctxReport.show();
  314. return;
  315. },
  316. ctxMenuEmbed() {
  317. this.closeModals();
  318. this.$refs.ctxEmbedModal.show();
  319. },
  320. ctxMenuShare() {
  321. this.$refs.ctxModal.hide();
  322. this.$refs.ctxShareModal.show();
  323. },
  324. closeCtxShareMenu() {
  325. this.$refs.ctxShareModal.hide();
  326. this.$refs.ctxModal.show();
  327. },
  328. ctxCopyEmbed() {
  329. navigator.clipboard.writeText(this.ctxEmbedPayload);
  330. this.ctxEmbedShowCaption = true;
  331. this.ctxEmbedShowLikes = false;
  332. this.ctxEmbedCompactMode = false;
  333. this.$refs.ctxEmbedModal.hide();
  334. },
  335. ctxModMenuShow() {
  336. this.$refs.ctxModal.hide();
  337. this.$refs.ctxModModal.show();
  338. },
  339. ctxModOtherMenuShow() {
  340. this.$refs.ctxModal.hide();
  341. this.$refs.ctxModModal.hide();
  342. this.$refs.ctxModOtherModal.show();
  343. },
  344. ctxModMenu() {
  345. this.$refs.ctxModal.hide();
  346. },
  347. ctxModMenuClose() {
  348. this.closeModals();
  349. },
  350. ctxModOtherMenuClose() {
  351. this.closeModals();
  352. this.$refs.ctxModModal.show();
  353. },
  354. formatCount(count) {
  355. return App.util.format.count(count);
  356. },
  357. openCtxReportOtherMenu() {
  358. let s = this.ctxMenuStatus;
  359. this.closeCtxMenu();
  360. this.ctxMenuStatus = s;
  361. this.$refs.ctxReportOther.show();
  362. },
  363. ctxReportMenuGoBack() {
  364. this.$refs.ctxReportOther.hide();
  365. this.$refs.ctxReport.hide();
  366. this.$refs.ctxModal.show();
  367. },
  368. ctxReportOtherMenuGoBack() {
  369. this.$refs.ctxReportOther.hide();
  370. this.$refs.ctxModal.hide();
  371. this.$refs.ctxReport.show();
  372. },
  373. sendReport(type) {
  374. let id = this.ctxMenuStatus.id;
  375. swal({
  376. 'title': 'Confirm Report',
  377. 'text': 'Are you sure you want to report this post?',
  378. 'icon': 'warning',
  379. 'buttons': true,
  380. 'dangerMode': true
  381. }).then((res) => {
  382. if(res) {
  383. axios.post('/i/report/', {
  384. 'report': type,
  385. 'type': 'post',
  386. 'id': id,
  387. }).then(res => {
  388. this.closeCtxMenu();
  389. swal('Report Sent!', 'We have successfully received your report.', 'success');
  390. }).catch(err => {
  391. swal('Oops!', 'There was an issue reporting this post.', 'error');
  392. })
  393. } else {
  394. this.closeCtxMenu();
  395. }
  396. });
  397. },
  398. closeModals() {
  399. this.$refs.ctxModal.hide();
  400. this.$refs.ctxModModal.hide();
  401. this.$refs.ctxModOtherModal.hide();
  402. this.$refs.ctxShareModal.hide();
  403. this.$refs.ctxEmbedModal.hide();
  404. this.$refs.ctxReport.hide();
  405. this.$refs.ctxReportOther.hide();
  406. this.$refs.ctxConfirm.hide();
  407. },
  408. openCtxStatusModal() {
  409. this.closeModals();
  410. this.$refs.ctxStatusModal.show();
  411. },
  412. openConfirmModal() {
  413. this.closeModals();
  414. this.$refs.ctxConfirm.show();
  415. },
  416. closeConfirmModal() {
  417. this.closeModals();
  418. this.confirmModalTitle = 'Are you sure?';
  419. this.confirmModalType = false;
  420. this.confirmModalIdentifer = null;
  421. },
  422. confirmModalConfirm() {
  423. switch(this.confirmModalType) {
  424. case 'post.delete':
  425. axios.post('/i/delete', {
  426. type: 'status',
  427. item: this.confirmModalIdentifer
  428. }).then(res => {
  429. this.feed = this.feed.filter(s => {
  430. return s.id != this.confirmModalIdentifer;
  431. });
  432. this.closeConfirmModal();
  433. }).catch(err => {
  434. this.closeConfirmModal();
  435. swal('Error', 'Something went wrong. Please try again later.', 'error');
  436. });
  437. break;
  438. }
  439. this.closeConfirmModal();
  440. },
  441. confirmModalCancel() {
  442. this.closeConfirmModal();
  443. },
  444. moderatePost(status, action, $event) {
  445. let username = status.account.username;
  446. let pid = status.id;
  447. let msg = '';
  448. let self = this;
  449. switch(action) {
  450. case 'addcw':
  451. msg = 'Are you sure you want to add a content warning to this post?';
  452. swal({
  453. title: 'Confirm',
  454. text: msg,
  455. icon: 'warning',
  456. buttons: true,
  457. dangerMode: true
  458. }).then(res => {
  459. if(res) {
  460. axios.post('/api/v2/moderator/action', {
  461. action: action,
  462. item_id: status.id,
  463. item_type: 'status'
  464. }).then(res => {
  465. swal('Success', 'Successfully added content warning', 'success');
  466. status.sensitive = true;
  467. self.closeModals();
  468. self.ctxModMenuClose();
  469. }).catch(err => {
  470. swal(
  471. 'Error',
  472. 'Something went wrong, please try again later.',
  473. 'error'
  474. );
  475. self.closeModals();
  476. self.ctxModMenuClose();
  477. });
  478. }
  479. });
  480. break;
  481. case 'remcw':
  482. msg = 'Are you sure you want to remove the content warning on this post?';
  483. swal({
  484. title: 'Confirm',
  485. text: msg,
  486. icon: 'warning',
  487. buttons: true,
  488. dangerMode: true
  489. }).then(res => {
  490. if(res) {
  491. axios.post('/api/v2/moderator/action', {
  492. action: action,
  493. item_id: status.id,
  494. item_type: 'status'
  495. }).then(res => {
  496. swal('Success', 'Successfully added content warning', 'success');
  497. status.sensitive = false;
  498. self.closeModals();
  499. self.ctxModMenuClose();
  500. }).catch(err => {
  501. swal(
  502. 'Error',
  503. 'Something went wrong, please try again later.',
  504. 'error'
  505. );
  506. self.closeModals();
  507. self.ctxModMenuClose();
  508. });
  509. }
  510. });
  511. break;
  512. case 'unlist':
  513. msg = 'Are you sure you want to unlist this post?';
  514. swal({
  515. title: 'Confirm',
  516. text: msg,
  517. icon: 'warning',
  518. buttons: true,
  519. dangerMode: true
  520. }).then(res => {
  521. if(res) {
  522. axios.post('/api/v2/moderator/action', {
  523. action: action,
  524. item_id: status.id,
  525. item_type: 'status'
  526. }).then(res => {
  527. this.feed = this.feed.filter(f => {
  528. return f.id != status.id;
  529. });
  530. swal('Success', 'Successfully unlisted post', 'success');
  531. self.closeModals();
  532. self.ctxModMenuClose();
  533. }).catch(err => {
  534. self.closeModals();
  535. self.ctxModMenuClose();
  536. swal(
  537. 'Error',
  538. 'Something went wrong, please try again later.',
  539. 'error'
  540. );
  541. });
  542. }
  543. });
  544. break;
  545. case 'spammer':
  546. msg = 'Are you sure you want to mark this user as a spammer? All existing and future posts will be unlisted on timelines and a content warning will be applied.';
  547. swal({
  548. title: 'Confirm',
  549. text: msg,
  550. icon: 'warning',
  551. buttons: true,
  552. dangerMode: true
  553. }).then(res => {
  554. if(res) {
  555. axios.post('/api/v2/moderator/action', {
  556. action: action,
  557. item_id: status.id,
  558. item_type: 'status'
  559. }).then(res => {
  560. swal('Success', 'Successfully marked account as spammer', 'success');
  561. self.closeModals();
  562. self.ctxModMenuClose();
  563. }).catch(err => {
  564. self.closeModals();
  565. self.ctxModMenuClose();
  566. swal(
  567. 'Error',
  568. 'Something went wrong, please try again later.',
  569. 'error'
  570. );
  571. });
  572. }
  573. });
  574. break;
  575. }
  576. },
  577. shareStatus(status, $event) {
  578. if($('body').hasClass('loggedIn') == false) {
  579. return;
  580. }
  581. this.closeModals();
  582. axios.post('/i/share', {
  583. item: status.id
  584. }).then(res => {
  585. status.reblogs_count = res.data.count;
  586. status.reblogged = !status.reblogged;
  587. if(status.reblogged) {
  588. swal('Success', 'You shared this post', 'success');
  589. } else {
  590. swal('Success', 'You unshared this post', 'success');
  591. }
  592. }).catch(err => {
  593. swal('Error', 'Something went wrong, please try again later.', 'error');
  594. });
  595. },
  596. statusUrl(status) {
  597. if(status.account.local == true) {
  598. return status.url;
  599. }
  600. return '/i/web/post/_/' + status.account.id + '/' + status.id;
  601. },
  602. profileUrl(status) {
  603. if(status.account.local == true) {
  604. return status.account.url;
  605. }
  606. return '/i/web/profile/_/' + status.account.id;
  607. },
  608. deletePost(status) {
  609. if($('body').hasClass('loggedIn') == false || this.ownerOrAdmin(status) == false) {
  610. return;
  611. }
  612. if(window.confirm('Are you sure you want to delete this post?') == false) {
  613. return;
  614. }
  615. axios.post('/i/delete', {
  616. type: 'status',
  617. item: status.id
  618. }).then(res => {
  619. this.$emit('status-delete', status.id);
  620. this.closeModals();
  621. }).catch(err => {
  622. swal('Error', 'Something went wrong. Please try again later.', 'error');
  623. });
  624. },
  625. owner(status) {
  626. return this.profile.id === status.account.id;
  627. },
  628. admin() {
  629. return this.profile.is_admin == true;
  630. },
  631. ownerOrAdmin(status) {
  632. return this.owner(status) || this.admin();
  633. },
  634. archivePost(status) {
  635. if(window.confirm('Are you sure you want to archive this post?') == false) {
  636. return;
  637. }
  638. axios.post('/api/pixelfed/v2/status/' + status.id + '/archive')
  639. .then(res => {
  640. this.$emit('status-delete', status.id);
  641. this.closeModals();
  642. });
  643. },
  644. unarchivePost(status) {
  645. if(window.confirm('Are you sure you want to unarchive this post?') == false) {
  646. return;
  647. }
  648. axios.post('/api/pixelfed/v2/status/' + status.id + '/unarchive')
  649. .then(res => {
  650. this.closeModals();
  651. });
  652. }
  653. }
  654. }
  655. </script>