├── qotd.png
├── styles.css
├── .editorconfig
├── .gitignore
├── versions.json
├── manifest.json
├── tsconfig.json
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── package.json
├── LICENSE
├── README.md
├── CODE_OF_CONDUCT.md
└── src
├── settingsTab.ts
└── main.ts
/qotd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twentytwokhz/quote-of-the-day/HEAD/qotd.png
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | .settings_area {
2 | margin-left: 5px;
3 | margin-right: 5px;
4 | font-size: 14px;
5 | width: 100%;
6 | }
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | insert_final_newline = true
7 | indent_style = tab
8 | indent_size = 4
9 | tab_width = 4
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Intellij
2 | *.iml
3 | .idea
4 |
5 | # npm
6 | node_modules
7 | package-lock.json
8 |
9 | # build
10 | main.js
11 | *.js.map
12 |
13 | # obsidian
14 | data.json
15 |
--------------------------------------------------------------------------------
/versions.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.2": "0.9.12",
3 | "1.1.1": "0.9.12",
4 | "1.1.0": "0.9.12",
5 | "1.0.5": "0.9.12",
6 | "1.0.4": "0.9.12",
7 | "1.0.3": "0.9.12",
8 | "1.0.2": "0.9.12",
9 | "1.0.1": "0.9.12",
10 | "1.0.0": "0.9.12",
11 | "0.1.1": "0.9.12",
12 | "0.1.0": "0.9.12"
13 | }
14 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "quote-of-the-day",
3 | "name": "Quote of the Day",
4 | "version": "1.1.2",
5 | "minAppVersion": "0.12.0",
6 | "description": "Inserts random quotes in the editor",
7 | "author": "Florin Bobis",
8 | "authorUrl": "https://florin.page",
9 | "isDesktopOnly": false
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "inlineSourceMap": true,
5 | "inlineSources": true,
6 | "module": "ESNext",
7 | "target": "ES6",
8 | "allowJs": true,
9 | "noImplicitAny": true,
10 | "moduleResolution": "node",
11 | "importHelpers": true,
12 | "lib": [
13 | "dom",
14 | "es5",
15 | "scripthost",
16 | "es2015"
17 | ]
18 | },
19 | "include": [
20 | "**/*.ts"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG]"
5 | labels: bug
6 | assignees: twentytwokhz
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[FEATURE]"
5 | labels: enhancement
6 | assignees: twentytwokhz
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "quote-of-the-day",
3 | "version": "1.1.1",
4 | "description": "Inserts random quotes in the editor",
5 | "main": "main.js",
6 | "scripts": {
7 | "dev": "esbuild src/main.ts --bundle --external:obsidian --outdir=. --target=es2016 --format=cjs --sourcemap=inline --watch",
8 | "build": "esbuild src/main.ts --bundle --external:obsidian --outdir=. --target=es2016 --format=cjs"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "MIT",
13 | "devDependencies": {
14 | "@types/node": "^16.11.1",
15 | "esbuild": "0.13.8",
16 | "obsidian": "^0.16.0",
17 | "tslib": "2.3.1",
18 | "typescript": "4.4.4"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Florin Bobiș
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Quote of the Day
7 |
8 |
9 | An Obsidian plugin to insert random quotes as Markdown.
10 |
11 |
12 | Report a Bug
13 | ·
14 | Request a Feature
15 |
16 |
17 |
18 | 
19 | 
20 | 
21 |
22 | 
23 | 
24 |
25 |
26 |
27 | ## About The Project
28 |
29 | This plugin allows you to insert a famous quote in Markdown format. It is relying on the [Quotable](https://github.com/lukePeavey/quotable) API.
30 |
31 | Courtesy to [Luke Peavey](https://github.com/lukePeavey) for providing this beautiful API for free. Thank you!
32 |
33 | ## Installing
34 |
35 | Find this plugin in the listing of community plugins in Obsidian and add it to your application.
36 |
37 | Or, if you'd like to install it manually, clone this repository to the `.obsidian/plugins/` directory in your vault, navigate to your newly cloned folder, run `npm i` or `yarn` to install dependencies, and run `npm run build` or `yarn build` to compile the plugin.
38 |
39 |
40 |
41 | The default hotkeys are:
42 |
43 | | Hotkey | Action |
44 | | --------------------------------------------------- | -------------------------------------------- |
45 | | Ctrl/Cmd + Alt + Q | **Insert Random Quote of the Day** |
46 | | Ctrl/Cmd + Alt + T | **Insert Tag-based Random Quote of the Day** |
47 |
48 | **Templates** are supported by using the `{{qotd}}`
49 |
50 | ## Options
51 |
52 | The following setting are available:
53 |
54 | | Setting | Description |
55 | | ---------------- | -------------------------------------------------------------- |
56 | | Quote Format | Format in which to display the quote |
57 | | Quote Tag Format | Format in which to display the tags in the footer of the quote |
58 | | Show Tags | Toggle display of tags in the footer of the quote |
59 |
60 |
61 |
62 | ## Contributing
63 |
64 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
65 |
66 | ## License
67 |
68 | This project is licensed under the MIT License - see the [`LICENSE`](LICENSE) file for details
69 |
70 |
71 |
72 | ## Contact
73 |
74 | Florin Bobis - [@twentytwokhz](https://github.com/twentytwokhz) - florinbobis@gmail.com
75 |
76 | Project Link: [https://github.com/twentytwokhz/quote-of-the-day](https://github.com/twentytwokhz/quote-of-the-day)
77 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | .
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/src/settingsTab.ts:
--------------------------------------------------------------------------------
1 | import { App, Notice, PluginSettingTab, Setting } from "obsidian";
2 | import QuoteOfTheDay from "./main";
3 |
4 | export default class QotDSettingsTab extends PluginSettingTab {
5 | plugin: QuoteOfTheDay;
6 |
7 | constructor(app: App, plugin: QuoteOfTheDay) {
8 | super(app, plugin);
9 | this.plugin = plugin;
10 | }
11 |
12 | display(): void {
13 | let { containerEl } = this;
14 |
15 | containerEl.empty();
16 |
17 | containerEl.createEl("h2", { text: "Quote of the Day Settings" });
18 |
19 | new Setting(containerEl)
20 | .setName("Quote Format")
21 | .setDesc("Format the way the quote is displayed")
22 | .addTextArea((text) => {
23 | text.setPlaceholder("Quote format")
24 | .setValue(this.plugin.settings.quoteFormat)
25 | .onChange(async (value) => {
26 | console.log("New Quote format: " + value);
27 | //add quote format validation
28 | let valid =
29 | value.contains("{author}") &&
30 | value.contains("{content}");
31 | if (!valid) {
32 | new Notice(
33 | "Invalid format! Missing {author} or {content} field"
34 | );
35 | return;
36 | }
37 | this.plugin.settings.quoteFormat = value;
38 | await this.plugin.saveSettings();
39 | });
40 | text.inputEl.setAttr("rows", 4);
41 | text.inputEl.addClass("settings_area");
42 | });
43 |
44 | new Setting(containerEl)
45 | .setName("Quote Tag Format")
46 | .setDesc("Format the way the quote tags are displayed")
47 | .addTextArea((text) => {
48 | text.setPlaceholder("Quote tag format")
49 | .setValue(this.plugin.settings.quoteTagFormat)
50 | .onChange(async (value) => {
51 | console.log("New Quote tag format: " + value);
52 | //add tag format validation
53 | let valid = value.contains("{tags}");
54 | if (!valid) {
55 | new Notice("Invalid format! Missing {tags} field");
56 | return;
57 | }
58 | this.plugin.settings.quoteTagFormat = value;
59 | await this.plugin.saveSettings();
60 | });
61 | text.inputEl.setAttr("rows", 4);
62 | text.inputEl.addClass("settings_area");
63 | });
64 |
65 | new Setting(containerEl)
66 | .setName("Quote Template Placeholder")
67 | .setDesc(
68 | "Format the way the quote placeholder is used when creating a note from template"
69 | )
70 | .addText((text) => {
71 | text.setPlaceholder("Quote Template Placeholder")
72 | .setValue(this.plugin.settings.quoteTemplatePlaceholder)
73 | .onChange(async (value) => {
74 | console.log("New Quote template placeholder: " + value);
75 | this.plugin.settings.quoteTemplatePlaceholder = value;
76 | await this.plugin.saveSettings();
77 | });
78 | });
79 |
80 | new Setting(containerEl)
81 | .setName("Filtered Quote Template Placeholder")
82 | .setDesc(
83 | "Format the way the filtered quote placeholder is used when creating a note from template"
84 | )
85 | .addText((text) => {
86 | text.setPlaceholder("Filtered Quote Template Placeholder")
87 | .setValue(this.plugin.settings.filteredQuoteTemplatePlaceholder)
88 | .onChange(async (value) => {
89 | console.log("New Filtered Quote template placeholder: " + value);
90 | this.plugin.settings.filteredQuoteTemplatePlaceholder = value;
91 | await this.plugin.saveSettings();
92 | });
93 | });
94 |
95 | new Setting(containerEl)
96 | .setName("Show Quote Tags")
97 | .setDesc("Display the quote tags")
98 | .addToggle((toggle) =>
99 | toggle
100 | .setValue(this.plugin.settings.showTags)
101 | .onChange(async (value) => {
102 | console.log("New Show tags: " + value);
103 | this.plugin.settings.showTags = value;
104 | await this.plugin.saveSettings();
105 | })
106 | );
107 |
108 | new Setting(containerEl)
109 | .setName("Show Quote Tags Hashtag")
110 | .setDesc("Display the quote tags with # symbol")
111 | .addToggle((toggle) =>
112 | toggle
113 | .setValue(this.plugin.settings.showTagHash)
114 | .onChange(async (value) => {
115 | //console.log("New Show tags: " + value);
116 | this.plugin.settings.showTagHash = value;
117 | await this.plugin.saveSettings();
118 | })
119 | );
120 |
121 | new Setting(containerEl)
122 | .setName("Quote Placeholder Interval")
123 | .setDesc(
124 | "Interval to check for quote placeholder presence and quote generation"
125 | )
126 | .addSlider((toggle) =>
127 | toggle
128 | .setLimits(5, 60, 1)
129 | .setValue(this.plugin.settings.placeholderInterval)
130 | .onChange(async (value) => {
131 | console.log("New placeholderInterval: " + value);
132 | this.plugin.settings.placeholderInterval = value;
133 | await this.plugin.saveSettings();
134 | })
135 | .setDynamicTooltip()
136 | );
137 |
138 | const { moment } = window;
139 | const filters = filtersList;
140 |
141 | let dd = new Setting(this.containerEl)
142 | .setName("Quote of the Day Filters")
143 | .setDesc("Current filter: " + this.plugin.getFilters(" , "))
144 | .addDropdown((dropdown) => {
145 | dropdown.addOption("None", "None");
146 | filters.forEach((filter, i) => {
147 | dropdown.addOption(filters[i], filter);
148 | });
149 | //dropdown.setValue(this.plugin.settings.filter2);
150 | dropdown.onChange((val) => {
151 | if (val == "None") {
152 | this.plugin.settings.filter = ["None"];
153 | }
154 | else
155 | {
156 | if (this.plugin.settings.filter.includes(val)) {
157 | this.plugin.settings.filter =
158 | this.plugin.settings.filter.filter((i) => i !== val);
159 | } else {
160 | this.plugin.settings.filter.push(val);
161 | }
162 | }
163 |
164 | console.log(this.plugin.settings.filter);
165 | dd.setDesc("Current filter: " + this.plugin.getFilters(" , "))
166 | this.plugin.saveSettings();
167 | });
168 | dropdown.selectEl.setAttr("multiple", null);
169 | });
170 | }
171 | }
172 |
173 | const filtersList = [
174 | "Age",
175 | "Athletics",
176 | "Business",
177 | "Change",
178 | "Character",
179 | "Competition",
180 | "Conservative",
181 | "Courage",
182 | "Creativity",
183 | "Education",
184 | "Ethics",
185 | "Failure",
186 | "Faith",
187 | "Family",
188 | "Famous Quotes",
189 | "Film",
190 | "Freedom",
191 | "Friendship",
192 | "Future",
193 | "Generosity",
194 | "Genius",
195 | "Gratitude",
196 | "Happiness",
197 | "Health",
198 | "History",
199 | "Honor",
200 | "Humor",
201 | "Humorous",
202 | "Imagination",
203 | "Inspirational",
204 | "Knowledge",
205 | "Leadership",
206 | "Life",
207 | "Literature",
208 | "Love",
209 | "Mathematics",
210 | "Motivational",
211 | "Nature",
212 | "Opportunity",
213 | "Pain",
214 | "Perseverance",
215 | "Philosophy",
216 | "Politics",
217 | "Power Quotes",
218 | "Proverb",
219 | "Religion",
220 | "Sadness",
221 | "Science",
222 | "Self",
223 | "Self Help",
224 | "Social Justice",
225 | "Society",
226 | "Spirituality",
227 | "Sports",
228 | "Stupidity",
229 | "Success",
230 | "Technology",
231 | "Time",
232 | "Tolerance",
233 | "Truth",
234 | "Virtue",
235 | "War",
236 | "Weakness",
237 | "Wellness",
238 | "Wisdom",
239 | "Work"
240 | ]
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { Editor, MarkdownView, Notice, Plugin } from "obsidian";
2 | import QotDSettingsTab from "./settingsTab";
3 |
4 | interface QotDSettings {
5 | quoteFormat: string;
6 | quoteTagFormat: string;
7 | quoteTemplatePlaceholder: string;
8 | filteredQuoteTemplatePlaceholder: string;
9 | filter: Array;
10 | showTags: boolean;
11 | showTagHash: boolean;
12 | placeholderInterval: number;
13 | }
14 |
15 | interface QuoteOfDay {
16 | quoteText: string;
17 | author: string;
18 | categories: string;
19 | }
20 |
21 | const QUOTE_API_URL = "https://florinbobis-quotes-net.hf.space/quotes";
22 | const MAX_TAG_CHARS = 25;
23 |
24 | const DEFAULT_SETTINGS: QotDSettings = {
25 | quoteFormat: `>[!quote] Quote of the Day
26 | > {content}
27 | > — {author}✍️`,
28 | quoteTagFormat: `> ---
29 | > {tags}
30 | `,
31 | quoteTemplatePlaceholder: "{{qotd}}",
32 | filteredQuoteTemplatePlaceholder: "{{fqotd}}",
33 | showTags: false,
34 | showTagHash: true,
35 | placeholderInterval: 5,
36 | filter: [],
37 | };
38 |
39 | export default class QuoteOfTheDay extends Plugin {
40 | settings: QotDSettings;
41 | started: boolean;
42 |
43 | getMarkdownFromQuote = (qod: QuoteOfDay) => {
44 | let text = this.settings.quoteFormat
45 | .replace("{content}", qod.quoteText)
46 | .replace("{author}", qod.author);
47 | if (this.settings.showTags) {
48 | let tagSymb = "";
49 | if (this.settings.showTagHash)
50 | {
51 | tagSymb = "#"
52 | }
53 | let tags = "";
54 | if (qod.categories) {
55 | tags = qod.categories.split(",").map((t) => `${tagSymb}${t}`).join(", ");
56 | }
57 |
58 | let quoteTags = this.settings.quoteTagFormat.replace(
59 | "{tags}",
60 | tags
61 | );
62 | text = text + "\n" + quoteTags;
63 | }
64 | return text;
65 | };
66 |
67 | sleep = (delay: number) => {
68 | return new Promise((resolve) => setTimeout(resolve, delay));
69 | };
70 |
71 | updateQuotePlaceholder = async () => {
72 | //replace with what is needed
73 | if (this.started) {
74 | return;
75 | }
76 | this.started = true;
77 | const file = this.app.workspace.getActiveFile();
78 | let t = await this.app.vault.read(file);
79 | if (t.includes(this.settings.quoteTemplatePlaceholder)) {
80 | while (t.search(this.settings.quoteTemplatePlaceholder) !== -1) {
81 | await this.sleep(500);
82 | let qod = await this.getRandomQuote();
83 | let quote = this.getMarkdownFromQuote(qod);
84 | t = t.replace(this.settings.quoteTemplatePlaceholder, quote);
85 | }
86 | this.app.vault.modify(file, t);
87 | }
88 | if (t.includes(this.settings.filteredQuoteTemplatePlaceholder)) {
89 | while (t.search(this.settings.filteredQuoteTemplatePlaceholder) !== -1) {
90 | await this.sleep(500);
91 | let qod = await this.getFilteredQuote();
92 | let quote = this.getMarkdownFromQuote(qod);
93 | t = t.replace(this.settings.filteredQuoteTemplatePlaceholder, quote);
94 | }
95 | this.app.vault.modify(file, t);
96 | }
97 | this.started = false;
98 | };
99 |
100 | getRandomQuote = async () => {
101 | let qod: QuoteOfDay = {
102 | quoteText: "Oops, I did it again 🙊",
103 | author: "Britney Error 😢",
104 | categories: "error",
105 | };
106 | try {
107 | let response = await fetch(`${QUOTE_API_URL}/random?dataset=quotable`);
108 | let result = await response.json();
109 | if (!result.statusCode) {
110 | qod = result;
111 | }
112 | } catch (err) {
113 | console.log(err);
114 | new Notice(err.message);
115 | }
116 | return qod;
117 | };
118 |
119 | getFilteredQuote = async () => {
120 | let qod: QuoteOfDay = {
121 | quoteText: "Oops, I did it again 🙊",
122 | author: "Britney Error 😢",
123 | categories: "error",
124 | };
125 | try {
126 | let filters = this.getFilters("|");
127 | let response = await fetch(`${QUOTE_API_URL}/random?dataset=quotable&tags=${filters}`);
128 | let result = await response.json();
129 | if (!result.statusCode) {
130 | qod = result;
131 | }
132 | } catch (err) {
133 | console.log(err);
134 | new Notice(err.message);
135 | }
136 | return qod;
137 | };
138 |
139 | getFilters = (sep: string) => {
140 | let f = this.settings.filter.filter((i) => i !== "None");
141 | return f.join(sep);
142 | }
143 |
144 | async onload() {
145 | console.log("Loading Quote of the Day plugin...");
146 | await this.loadSettings();
147 |
148 | // highlight-start
149 | this.registerInterval(
150 | window.setInterval(
151 | () => this.updateQuotePlaceholder(),
152 | this.settings.placeholderInterval * 1000
153 | )
154 | );
155 |
156 | // This adds an editor command that can perform some operation on the current editor instance
157 | this.addCommand({
158 | id: "qotd-random",
159 | name: "Insert Random Quote of the Day",
160 | editorCallback: async (editor: Editor, view: MarkdownView) => {
161 | let qod = await this.getRandomQuote();
162 | editor.replaceSelection(this.getMarkdownFromQuote(qod));
163 | },
164 | });
165 |
166 | this.addCommand({
167 | id: "qotd-tag",
168 | name: "Insert Random Quote of the Day by selected tag",
169 | checkCallback: (checking: boolean) => {
170 | // Conditions to check
171 | let markdownView =
172 | this.app.workspace.getActiveViewOfType(MarkdownView);
173 | if (markdownView) {
174 | // If checking is true, we're simply "checking" if the command can be run.
175 | // If checking is false, then we want to actually perform the operation.
176 | if (!checking) {
177 | const sel = markdownView.editor.getSelection();
178 | const validSelection = sel && sel.length > 2;
179 | if (!validSelection) {
180 | return false;
181 | }
182 | }
183 |
184 | // This command will only show up in Command Palette when the check function returns true
185 | return true;
186 | }
187 |
188 | return true;
189 | },
190 | editorCallback: async (editor: Editor, view: MarkdownView) => {
191 | let qod: QuoteOfDay = {
192 | quoteText: "Oops, cannot find that tag 🙊",
193 | author: "Tag Error 😢",
194 | categories: "error",
195 | };
196 | try {
197 | const sel = editor.getSelection();
198 | const validSelection = sel && sel.length > 2;
199 | if (!validSelection) {
200 | //retrieve random quote
201 | throw new Error("Invalid tag");
202 | }
203 | const tag = sel.substr(0, MAX_TAG_CHARS).trim();
204 | let response = await fetch(
205 | `${QUOTE_API_URL}/random?tags=${tag}`
206 | );
207 | let result = await response.json();
208 | if (!result.statusCode) {
209 | qod = result;
210 | }
211 | } catch (err) {
212 | console.log(err);
213 | new Notice(err.message);
214 | }
215 | editor.replaceSelection(this.getMarkdownFromQuote(qod));
216 | },
217 | });
218 |
219 | // This adds a settings tab so the user can configure various aspects of the plugin
220 | this.addSettingTab(new QotDSettingsTab(this.app, this));
221 | }
222 |
223 | onunload() {}
224 |
225 | async loadSettings() {
226 | this.settings = Object.assign(
227 | {},
228 | DEFAULT_SETTINGS,
229 | await this.loadData()
230 | );
231 | }
232 |
233 | async saveSettings() {
234 | await this.saveData(this.settings);
235 | }
236 | }
237 |
--------------------------------------------------------------------------------