Introduction to Obsidian-Inputs

Obsidian-Inputs is a lightweight, efficient plugin designed to offer a simple inline-code pattern for creating input and button components in ObsidianMD's preview mode. These components dynamically modify markdown files, ensuring long-term readability even if Obsidian or other plugins fail.

Existing Obsidian plugins for creating input components are often unstable and slow due to their reliance on complex libraries. This affects your experience and productivity within ObsidianMD, leading to frustration and inefficiency.

Key Features

  • Quick Loading: Average loading time of ~10ms.
  • Markdown Compatibility: Updates are made directly within markdown files, not external settings.
  • User-Friendly Syntax: Simple and easy-to-read syntax, avoiding complex bidirectional elements. like :(.
  • No External Libraries: Uses Obsidian's API and simple HTML elements for seamless integration.

Plugin Capabilities

  • Input/Button Creation: Create text inputs, text areas, radio inputs, and buttons easily.
  • Markdown Modification: Effortlessly update headers, dataview-inline fields, and frontmatter fields.
  • File Operations: Automatically create, modify, rename, or remove files.
  • Macro Creation: Automate steps and reference previous results or files.

Input Sources

Retrieve options from Dataview queries or input them manually.

Context Modification

  • File Operations: Create, modify, rename, or remove files.
  • Header Manipulation: Manage headers within files.
  • Front Matter Management: Create, update, and modify front matter fields.
  • Inline Field Interaction (Dataview): Interact with inline fields.
  • Pattern: Use input patterns to append, prepend, or replace values dynamically.

Planned Enhancements

  • Additional features and capabilities will be introduced in future releases.

Terminology

  • Page/File: Used interchangeably.
  • Notation/Pattern: Refers to plugin syntax written on the page.
  • Components: All UI elements created by the plugin, including inputs and buttons.

For detailed syntax information, refer to the Syntax Documentation. Screenshots

Screenshoots:

![[Pasted image 20240328003625.png]]

Syntax for creating input components follows the convention:

<"id"?> <"type"> <":name"> "|" <"expression"> <", opts"> <">target">

"type"

החלק הזה אחראי על הקומפוננטה שתתרנדר בview. שתי האופציות שכרגע נתמכות הן text: שמייצר text input, the experstion in this case run after the user unfocus the input button: שמייצר button, the expertion in this case run when user click on the input

צריך לרשום את זה כך text: or button:

":name"

free text that be the name of the button or the placeholder in the input must be end with |

"expression"

Expressions undergo evaluation in three steps and can incorporate data from the current or other pages or the last updated file, such as frontmatter fields, dataview inline fields. They can load files as templates or execute JavaScript files or interact with global api.

Step 1: Utilize pre-processing string template on the expression to replace all placeholders in the format {{path.of.data}} or &path.to.data with corresponding data from frontmatter, inline fields, or file properties.

  • If the property exist on frontmatter and elso on dataview-inline-field the priority is by the target type. if target type is frontmatter priority is to read from frontmatter and if it inline-field priority is inline-field
  • If the data to inject is a tFile, it's replaced by an Obsidian link (by setting, default: wiki link).
  • The last ten files touched by the plugin are referred to as page0 to page9. you can refer them and there variable like {{ page0.book-name }}
  • while the last ten files created by the plugin are called new0 to new9 {{ new2.book-name }}
  • you can refer any file and read it data by using [[file-name]] syntax {{ [[harry potter]].book-name }}
  • Current file is refer by using the name activeFile, most time it can omit, because default context always being to current active file.

Step 2: After Step 1, the evaluated expression undergoes content testing.

If the expression matches the pattern import [[file name]]:

  • If the file name ends with .md, its content is loaded and processed using the templater, with the result sent to the target.
  • If the file name ends with .js, it's imported as a JavaScript module, enabling the use of all Obsidian-Inputs API functions. The export default value is sent to the target. If it's undefined, the target part is not executed.
  • If an error occurs during templater or JavaScript module import, it's displayed in the developer console.

Step 3: If the expression doesn't match the import pattern, it's evaluated as a JavaScript expression, and the return value is sent to the target.

Step 4: If the expression throws an error, it's considered plaintext and sent to the target as is. and that is you way to write arbitrary text to the target

"> target"

After the > symbol, the target part specifies the area to be modified by the expression value. It is constructed with the following sub-pattern:

<"file"?><"(::|#|:)path"?><" method">

by combine file path the plugin define the type of the entity that should be modified, target type can be file, header, dataview inline field, frontmatter or yaml, pattern himself

  • <"file"?> Optional,Specifies the name of the file or page to be modified.

    • If no file is provided, it refers to the current active file.
    • If the file does not exist, it is created. Otherwise, it is modified.
    • If no next part path is omitted, targetType is the file himself.
  • <"(::|#|:)path">

    • ::path: Specifies the targetType as an inline field in the target file.

      • In the case of multiple fields by the same name the closer one to the pattern will be chosen
    • :path - Specifies the targetType as YAML in the front matter of the target file.

    • #path - Specifies the targetType as a header in the target file.

    • if no file or path provide the targetType is pattern which use the current input-pattern as context

  • <" method"> followed by space there is the method that can be one of the next actions. the meaning of the action change a little by the targetType

    • append
      • for inline field and yaml it convert the value to array (if is not) and append the new value to end of the array.
      • for header it append the value after the last line of the header content (the not empty line before the next header )
      • for file it append the value to bottom of the file
      • for pattern it add the value after the input-pattern
    • replace
      • for inline field and yaml it replace the curent value (or array) with the new value
      • for header it repace the whol header content with new value
      • for file It replaced the whole file with the new value
      • for pattern It replaced the whole input pattern with the new value so it actually deleted it
        • caution: if there is a two or more pattern that look the same it replaced the first one. To avoid that use the ID section .etc -identify- text:activity| {{input}}> #Activity
    • prepend
      • same as append Just add the new value to the start of everything
    • create
      • for file it created the file. If the file exist it create a new one with increment free number after the name
    • clear
      • for header, file, inline field and yaml it clear the current value or content and ignore the new value
      • for pattern it clear the text before input-pattern until first inline field in that line. another run of that target clear the value of the inline field, another run remove all text until start of the line
    • remove: Deletes the specified target entirely.
      • For header, it removes the entire header and its content.
      • For file, it deletes the file entirely.
      • For inline field and yaml, it removes the current value or content entirely.
      • For pattern, it removes the entire input pattern.
    • rename
      • For file, new value become the new path of target file.
        • if file not exist nothing happen
        • If path is exist it generate a new path by incrementing index ex. file 0, file 1, etc
        • new path is coenacted to exist path of the target file
        • but is legit to be started the path with:
          • \ for make the path start from root valut folder
          • .. go one folder back relative target file
          • . stay in the same place of target file. ( default )
      • For other targets such as inline field, yaml, or header, the rename method is not applicable yet

If you're interested in testing the Obsidian-Inputs plugin before it's published in the plugin community, follow these steps:

  • Download the plugin files from the repository or source provided by the developer.
  • Open ObsidianMD and navigate to the Settings pane.
  • Click on the "Community plugins" tab.
  • Locate the "Developers" section and click on the "Load plugin" button.
  • Select the downloaded plugin files from your local directory.
  • Once loaded, the plugin will appear in the list of installed plugins.
  • Enable the plugin by toggling the switch next to its name.
  • Test the plugin's functionality within ObsidianMD to provide feedback and report any issues to the developer.

Please note that as this plugin is still in the testing phase and not yet published in the plugin community, it may have limited features and could encounter bugs or errors. Your feedback as a tester is invaluable in helping improve the plugin before its official release.

If you encounter any issues during the testing process, provide detailed feedback to the developer to assist in troubleshooting and improvement efforts. You can also collaborate with other testers and developers in the ObsidianMD community forums or Discord channels to share experiences and insights.

Input Notation Syntax:

Syntax for creating input components follows the convention:

<"-id-"?> <"type"> <":name"> "|" <"expression"> <", opts"> <">target">

-id-?: Optional identifier for the Component element, aiding in recognition for refocusing or pattern replacement.

type: Specifies the type of the input element, such as text, textarea, or button, followed by a colon :. can be:

  • text: simple text input. it run the expression when it unfocus and value is not empty
  • button: simple button. it run the expression when click on it
  • textarea: text area input that fill the screen

:name: Label of button or placeholder for inputs. indicating the purpose of the input field.

now |: Pipe symbol separating the introduction part and the actual expiration/target notation.

expression: Expression generating the value to be injected into the target. It could be a string with placeholder, a JS expression, a JS file to import and run or md template file. examples: - placeholder: I read today the book &book-name or I read today the book {{book-name}} can result to I read today the book Harry Potter if somewhere is the page [book-name::Harry Potter] exist - JS expression: number + 1 if somewhere is the page [number::2] exist the result to target will be 3 - **JS import:**import [[create-book.js]]that import and runcreate-book.jsif it exists in the vault - **md import:**import [[create-book.md]] that read and run throw templatercreate-book.mdif it exists in the vault and return the result see detail [here](../) , opts`: comma separated values for created radio button or dataview query for create autocomplete input, start with comma

>target: Specifies where and how the value of the expression part is stored or processed. including the target file or context and the method of saving or updating the target. Target own mini pattern <filename><type><path> <method> (#|::|:)

Examples :

Example 1: Create a text input element:
text: Enter your name| {{input}} >::name

value will saved in inline-field called name in the same file. If the field doesn't exist, it's created.

Example 2: Create a text area with autocomplete:
text:select game| {{input}}, = #games >:games append

Creates an input element that autocompletes from a Dataview query of files tagged with #games, appending the value the end of front matter games:: key as an array.

Example 3: Create a radio input element
text: Select color| red, blue, green| = #colors >:selectedColor

Example 4: Creates a button element that increments the inline field number:
button:click me| (number || 0)+1 >::number

Example 5: Create a button to delete a specific header:
button: Delete section| >::file#Section Name remove

Example 6: same, just clear the header content:
button: Delete section| >::file#Section Name clear

Example 7: mood tracking text:Mood| - (@time) {{input}} [reasone], ☺️,😑,🥰,😎,🤩,🤔,🫥,😮,😏,🤑 >#Activities