From 4ea10a24f2a84039b9bf32ff1e9acd2f54e3b8b7 Mon Sep 17 00:00:00 2001 From: Christian Bager Bach Houmann Date: Sat, 3 Apr 2021 20:18:22 +0100 Subject: [PATCH] Improvements to Post Tweet Mode (#5) --- README.md | 18 +++--- manifest.json | 2 +- package.json | 2 +- src/Modals/PostTweetModal.ts | 115 ++++++++++++++++++++++++----------- 4 files changed, 90 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index d012c05..efa870c 100644 --- a/README.md +++ b/README.md @@ -41,16 +41,18 @@ You'll see an indicator which tells you if you're connected or not. ## Post Tweet Mode Using the `Post Tweet` command, a new modal will open. There, you can craft threads - or single tweets. You can select both text or threads before using the command and it'll automatically port it into the modal. If the selected text is longer than 280 characters, it'll break it into a thread for you. -You can paste text into the modal. If that text is longer than 280 characters, it'll also break it into multiple tweets. The tweets are added below the one you're pasting to. +You can paste text into the modal. If that text is longer than 280 characters, it'll also break it into multiple tweets. ### Post Tweet Mode Shortcuts -- Backspace to delete empty tweet -- Enter to make new tweet if max length -- Alt + Enter to make new tweet -- Ctrl + Enter to insert a tweet below -- Shift + Enter to insert a new tweet above -- Ctrl + ArrowUp to focus tweet above -- Ctrl + ArrowDown to focus tweet below +- `Backspace` to delete empty tweet +- `Enter` to make new tweet if max length +- `Alt + Enter` to make new tweet +- `Ctrl + Enter` to insert a tweet below +- `Shift + Enter` to insert a new tweet above +- `Ctrl + ArrowUp` to focus tweet above +- `Ctrl + ArrowDown` to focus tweet below +- `Ctrl + Shift + ArrowUp` to move tweet up +- `Ctrl + Shift + ArrowDown` to move tweet down ## Quick-posts Single tweets are simple. Just select some text and use the `Post Selected as Tweet` command. diff --git a/manifest.json b/manifest.json index 54715d1..9a0f947 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "notetweet", "name": "NoteTweetšŸ¦", - "version": "0.3.0", + "version": "0.3.1", "minAppVersion": "0.9.12", "description": "This plugin allows you to post tweets directly from Obsidian.", "author": "Christian B. B. Houmann", diff --git a/package.json b/package.json index 2bcc2dc..34802d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notetweet", - "version": "0.3.0", + "version": "0.3.1", "description": "Post tweets from Obsidian", "main": "src/main.js", "scripts": { diff --git a/src/Modals/PostTweetModal.ts b/src/Modals/PostTweetModal.ts index 8c12ec5..7b6ef2f 100644 --- a/src/Modals/PostTweetModal.ts +++ b/src/Modals/PostTweetModal.ts @@ -78,15 +78,20 @@ export class PostTweetModal extends Modal { // Separate lines by linebreaks. Add lines together, separated by linebreak, if they can fit within a tweet. // Repeat this until all separated lines are joined into tweets with proper sizes. private textInputHandler(str: string) { - let chunks: string[] = str.split("\n").map(txt => txt.trim()); + let chunks: string[] = str.split("\n"); let i = 0, joinedTextChunks: string[] = []; chunks.forEach((chunk, j) => { if (joinedTextChunks[i] == null) joinedTextChunks[i] = ""; if (joinedTextChunks[i].length + chunk.length <= this.MAX_TWEET_LENGTH - 1) { - joinedTextChunks[i] = joinedTextChunks[i] + chunk.trim(); + joinedTextChunks[i] = joinedTextChunks[i] + chunk; joinedTextChunks[i] += (j == chunks.length - 1) ? "" : "\n"; } else { - joinedTextChunks[++i] = chunk; + if (chunk.length > this.MAX_TWEET_LENGTH) { + let x = chunk.split(/[.?!]\s/).join("\n"); + this.textInputHandler(x).forEach(split => joinedTextChunks[++i] = split); + } else { + joinedTextChunks[++i] = chunk; + } } }) return joinedTextChunks; @@ -131,7 +136,8 @@ export class PostTweetModal extends Modal { let pasted: string = event.clipboardData.getData("text"); if (pasted.length + textarea.textLength > this.MAX_TWEET_LENGTH) { event.preventDefault(); - this.insertTweetBelow(textarea, textZone, pasted); + let splicedPaste = this.textInputHandler(pasted); + this.createTweetsWithInput(splicedPaste, textarea, textZone); } }; } @@ -173,16 +179,34 @@ export class PostTweetModal extends Modal { this.insertTweetBelow(textarea, textZone); } - if (key.code == "ArrowUp" && key.ctrlKey) { + if (key.code == "ArrowUp" && key.ctrlKey && !key.shiftKey) { let currentTweetIndex = this.textAreas.findIndex(tweet => tweet.value == textarea.value); if (currentTweetIndex > 0) this.textAreas[currentTweetIndex - 1].focus() } - if (key.code == "ArrowDown" && key.ctrlKey) { + if (key.code == "ArrowDown" && key.ctrlKey && !key.shiftKey) { let currentTweetIndex = this.textAreas.findIndex(tweet => tweet.value == textarea.value); if (currentTweetIndex < this.textAreas.length - 1) - this.textAreas[currentTweetIndex + 1].focus() + this.textAreas[currentTweetIndex + 1].focus(); + } + + if (key.code == "ArrowDown" && key.ctrlKey && key.shiftKey) { + let tweetIndex = this.textAreas.findIndex(ta => ta.value == textarea.value); + if (tweetIndex != this.textAreas.length - 1) { + key.preventDefault(); + this.switchTweets(textarea, this.textAreas[tweetIndex + 1]); + this.textAreas[tweetIndex + 1].focus(); + } + } + + if (key.code == "ArrowUp" && key.ctrlKey && key.shiftKey) { + let tweetIndex = this.textAreas.findIndex(ta => ta.value == textarea.value); + if (tweetIndex != 0) { + key.preventDefault(); + this.switchTweets(textarea, this.textAreas[tweetIndex - 1]); + this.textAreas[tweetIndex - 1].focus(); + } } textarea.style.height = "auto"; @@ -190,6 +214,14 @@ export class PostTweetModal extends Modal { }; } + private switchTweets(textarea1: HTMLTextAreaElement, textarea2: HTMLTextAreaElement) { + let temp: string = textarea1.value; + textarea1.value = textarea2.value; + textarea2.value = temp; + textarea1.dispatchEvent(new InputEvent('input')); + textarea2.dispatchEvent(new InputEvent('input')); + } + private deleteTweet(textarea: HTMLTextAreaElement, textZone: HTMLDivElement, lengthCheckerEl: HTMLElement) { let i = this.textAreas.findIndex(ele => ele === textarea); this.textAreas.remove(textarea); @@ -227,8 +259,8 @@ export class PostTweetModal extends Modal { return async () => { let threadContent = this.textAreas.map(textarea => textarea.value); - if (threadContent.find(txt => txt.length > this.MAX_TWEET_LENGTH)) { - new Notice("At least one of your tweets is too long."); + if (threadContent.find(txt => txt.length > this.MAX_TWEET_LENGTH || txt == "") != null) { + new Notice("At least one of your tweets is too long or empty."); return; } @@ -248,54 +280,63 @@ export class PostTweetModal extends Modal { let insertAboveIndex = this.textAreas.findIndex(area => area.value == textarea.value); try { - this.createTextarea(textZone); + let insertedTweet = this.createTextarea(textZone); + this.shiftTweetsDownFromIndex(insertAboveIndex); + + return {tweet: insertedTweet, index: insertAboveIndex} } catch (e) { new Notice(e); return; } - - // Shift all elements below down - for (let i = this.textAreas.length - 1; i > insertAboveIndex; i--){ - this.textAreas[i].value = this.textAreas[i - 1].value; - this.textAreas[i].dispatchEvent(new InputEvent('input')); - } - - this.textAreas[insertAboveIndex].value = ""; - this.textAreas[insertAboveIndex].focus(); } - private insertTweetBelow(textarea: HTMLTextAreaElement, textZone: HTMLDivElement, insertText?: string) { + private insertTweetBelow(textarea: HTMLTextAreaElement, textZone: HTMLDivElement) { let insertBelowIndex = this.textAreas.findIndex(area => area.value == textarea.value); - let insertedIndex = insertBelowIndex + 1; + let fromIndex = insertBelowIndex + 1; try { - this.createTextarea(textZone); + let insertedTextarea = this.createTextarea(textZone); + this.shiftTweetsDownFromIndex(fromIndex); + + return insertedTextarea; } catch (e) { new Notice(e); - return; } + } - // Shift all elements below down - for (let i = this.textAreas.length - 1; i > insertedIndex; i--){ + private shiftTweetsDownFromIndex(insertedIndex: number) { + for (let i = this.textAreas.length - 1; i > insertedIndex; i--) { this.textAreas[i].value = this.textAreas[i - 1].value; this.textAreas[i].dispatchEvent(new InputEvent('input')); } - if (insertText != null) { - if (insertText.length > this.MAX_TWEET_LENGTH) { - let sliced = this.textInputHandler(insertText); - this.textAreas[insertedIndex].value = sliced[0]; - this.insertTweetBelow(this.textAreas[insertedIndex - 1], textZone, sliced.slice(1).join()); - } - if (insertText.length <= this.MAX_TWEET_LENGTH) - this.textAreas[insertedIndex].value = insertText; + this.textAreas[insertedIndex].value = ""; + this.textAreas[insertedIndex].focus(); + } + +/* private insertTweetBelowWithText(textarea: HTMLTextAreaElement, textZone: HTMLDivElement, insertText: string){ + // Insert tweet, assign to var. Pass that var in again. + // It'll be reverse order if I don't insert below each one. For inserting above, you can just insert as you normally would. + if (insertText.length > this.MAX_TWEET_LENGTH) { + let sliced = this.textInputHandler(insertText); // First, make sure the text is sized correctly. + let tweet: HTMLTextAreaElement = textarea; + + let tweetIndex = this.insertTweetBelow(tweet, textZone); + tweet = this.textAreas[tweetIndex]; + this.insertTweetBelowWithText(tweet, textZone, sliced.slice(1).join()); + + // sliced.forEach(chunk => { + // console.log("!!!!") + // let x = this.insertTweetBelow(tweet, textZone); + // tweet = x.insertedTweet; + // tweet.value = chunk; + // }); } else { - this.textAreas[insertedIndex].value = ""; + let {insertedTweet, insertedIndex} = this.insertTweetBelow(textarea, textZone); + this.textAreas[insertedIndex].value = insertText; } - - this.textAreas[insertedIndex].focus(); - } + }*/ } \ No newline at end of file