Improving Web Selection Capture for Obsidian with “Browser Actions”

The image depicts a vivid and colorful illustration of two computer monitors facing each other, displaying lines of code. The monitors are surrounded by abstract bursts of color and energy, suggesting a sense of motion and digital activity. In the foreground, there is a keyboard along with some colored markers. In the background, various geometric shapes and graphs are visible, contributing to a theme of technology and data analysis. The overall design has a parchment-like texture, framing the futuristic elements and enhancing the artistic representation of computing.

In my arti­cle First Steps with “Brows­er Actions”, I pre­sent­ed exam­ples of how to use Car­lo Zottmann’s new app Brows­er Actions. One exam­ple was a short­cut to cap­ture a selec­tion in a brows­er win­dow and dis­play it in Obsid­i­an as a quote call­out.

In my next arti­cle Form Base Entry for Obsid­i­an, I dis­cuss how to use an HTML page with a form to cap­ture data for an Obsid­i­an note. This arti­cle serves as a con­cept car to illus­trate the idea of com­bin­ing Apple Short­cuts, HTML form-based data input, and Obsid­i­an in a work­flow.

I often use the short­cut to cap­ture selec­tions from web­pages. What I always missed is the abil­i­ty to add tags and my own notes. In this arti­cle, I com­bine the two short­cuts and present a use­ful solu­tion to cap­ture selec­tions while also adding my own notes and tags.

The flow

The image is a flowchart showing the process of how information is transferred from a web browser to the Obsidian application. The workflow starts in the browser, where snippets and shortcuts are launched. There are decisions that depend on whether input arguments are provided. If no arguments are provided, information such as the URL, page title and text choices are retrieved and entered into a form. The user adds notes and tags and then clicks “Submit” to send the snippet to Obsidian. Finally, the snippet is displayed on a snippet page. The diagram uses text and graphical elements to illustrate this process.

Translated with DeepL.com (free version)

With a selec­tion in a brows­er win­dow, the short­cut must be exe­cut­ed. Since the short­cut is called with­out any para­me­ters, the “No” path of the con­di­tion­al state­ment will be exe­cut­ed.

An action from the Brows­er Action app then cap­tures all rel­e­vant attrib­ut­es of the active brows­er win­dow. How­ev­er, in our con­text, we are only inter­est­ed in the fol­low­ing:

  • The pageURL
  • The pageTi­tle
  • The active selec­tion (for­mat­ted as Mark­down)

Now, the short­cut uses anoth­er action to open a pre­de­fined HTML form in a new tab. This form includes fields for the pageURLpageTi­tle, and a field for the cap­tured selec­tion in Mark­down.

When this page is active, the attrib­ut­es will be insert­ed into the cor­re­spond­ing fields by anoth­er action from the Brows­er Action app.

Now the user can:

  • Pre­view the selec­tion
  • Review the oth­er data
  • Add an extra note and some tags

After click­ing the sub­mit but­ton, the snip­pet will be built, and with help of “Actions for Obsid­i­an,” the snip­pet will be added to the spe­cial page in Obsid­i­an.

The HTML-Form

Let’s start with the html form page. On top there is a field, that shows the mark­down of the selec­tion as pre­view.

Below this there is two groups, left for an addi­tion­al note from the user and right for the tags input. Because most time, I use only a few pre­de­fined tags, these are ren­dered here as check­box­es. Nev­er­the­less for addi­tion­al tags there is an input field as well.

The note can be mul­ti­line, and it’s pos­si­ble to use any Mark­down sup­port­ed in call­outs. Tags can be entered into the input as com­ma-sep­a­rat­ed val­ues, with­out the #. These will be added by the JavaScript.

Next there are the fields for the mark­down of the selec­tion and the pageURL and pageTi­tle. These fields are actu­al­ly meant only as tem­po­rary stor­age so that they are not lost for the next call of the short­cut. There­fore, I intend­ed to hide them behind a col­lapsi­ble area or make them com­plete­ly invis­i­ble. How­ev­er, the cur­rent beta ver­sion (2024.0.5) seems to have issues with both options. I think this will be fixed soon. Until then, these fields will be vis­i­ble so that the user can make changes if nec­es­sary.

At the very bot­tom is the sub­mit but­ton. After this but­ton is pressed, the con­tent of all fields is sent back to the short­cut as a JSON string. Since the short­cut is now called with an input, it will then process the oth­er part of the con­di­tion­al state­ments to build the snip­pet and place it on the Obsid­i­an note.

This image displays a user interface for a note-taking or information entry form. At the top, there is a section labeled “Preview of Selection” that shows a formatted preview of selected text, with hyperlinks and references highlighted in blue and purple. Below this is a “Notes” section, providing a text area for entering additional comments or observations. To the right of the Notes section is a “Tags” field, where tags can be entered directly or selected from predefined options like “Review,” “Obsidian,” “AppleShortcuts,” “macOS,” and “iPadOS.”

Further down, a larger text box labeled “Markdown” displays the selected text in markdown format, complete with syntax for links and other formatting elements. Next to this, there are fields for “URL” and “Page Title,” intended for entering or displaying the associated URL and the title of the page. At the bottom, a blue “Submit” button is centered, allowing users to save or submit the form data. This form is organized to capture structured information about a specific topic or webpage, with fields for tags, notes, and markdown-formatted text.

The HTML code is pret­ty straight­for­ward. In the head sec­tion, along with the CSS, there is a script that includes the markedjs/marked library for pars­ing Mark­down.

The HTML code in the body sec­tion man­ages the fields I described ear­li­er, as well as the sub­mit but­ton. As well as the JavaScript part with these two func­tions:

The updatePre­view() func­tion updates the pre­view when­ev­er the user types in the Mark­down textarea. It retrieves the Mark­down con­tent and updates the pre­view box using the Marked.js library to con­vert Mark­down to HTML.

The han­dle­Sub­mit() func­tion is called when the sub­mit but­ton is clicked. It col­lects val­ues from the notes, tags, Mark­down, URL, and title fields. The func­tion process­es the tags input by split­ting each entry (sep­a­rat­ed by a ,), adding a # in front of each tag, and sav­ing them into an array. In addi­tion, the script process­es all checked check­box­es, col­lect­ing the name of each check­box and adds a # before name.

All data is com­bined into an object, which is then con­vert­ed to a JSON string. Final­ly, it starts the short­cut using the spe­cif­ic URL scheme (shortcuts://run-shortcut) with the JSON string as input for fur­ther pro­cess­ing.

The han­dle­Sub­mit() func­tion is called when the sub­mit but­ton is clicked. It col­lects val­ues from the notes, tags, Mark­down, URL, and title fields. The func­tion process­es the tags input by split­ting each entry (sep­a­rat­ed by a ,), adding a # in front of each tag, and sav­ing them into an array. Addi­tion­al­ly, the script han­dles all the checked check­box­es, col­lect­ing the text (i.e., the name of each check­box) and adding a # in front of each tag as well.

This func­tion facil­i­tates easy mod­i­fi­ca­tion of check­box­es for tags. Just edit the text, add or delete check­box inputs.

Here is the whole HTML-file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Create Snippet with note and tags in Obsidian</title>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <style>
/* Base Body Style */
body {
    margin: 0;
    padding: 10px;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #f4f7f9;
    color: #333;
}

/* Container Styling */
.container {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    max-width: 1000px;
    margin: 0 auto;
}

/* Box Styling */
.box {
    background-color: #fff;
    border-radius: 8px;
    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);
    padding: 15px;
    border: 1px solid #ddd;
}

/* Preview Box Styling */
.preview-box {
    grid-column: 1 / 3;
    min-height: 200px;
    font-size: 0.9rem;
    overflow: auto;
}

.preview-box h2 {
    margin-top: 0;
    font-size: 1.2rem;
    color: #007acc;
}

/* Notes and Tags in Two Columns */
.notes-tags-box {
    grid-column: 1 / 3;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.note-field {
    
}

/* Tags Section */
.tag-input {
    width: 100%;
    padding: 8px;
    font-size: 0.9rem;
    border-radius: 4px;
    border: 1px solid #ccc;
    margin-top: 8px;
    margin-bottom: 15px; /* Added space below tag input field */
}

/* Checkbox Group - Inline with Wrap */
.checkbox-group {
    display: flex;
    flex-wrap: wrap;
    gap: 10px; /* Space between checkboxes */
}

.checkbox-group label {
    display: flex;
    align-items: center;
    margin-right: 10px;
}

/* Markdown and Meta Information Side by Side */
.markdown-meta-box {
    grid-column: 1 / 3;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

/* Input and Textarea Styling */
textarea, input[type="text"] {
    width: 100%;
    padding: 8px;
    font-size: 0.9rem;
    border-radius: 4px;
    border: 1px solid #ccc;
    box-sizing: border-box;
}

textarea {
    min-height: 100px;
    resize: vertical;
}

/* Submit Button Styling */
.submit-button {
    display: block;
    margin: 20px auto;
    padding: 12px 24px;
    font-size: 1rem;
    background-color: #007acc;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
}

.submit-button:hover {
    background-color: #005999;
}


/* Responsive Styles */
@media (max-width: 768px) {
    .container {
        grid-template-columns: 1fr;
    }

    .preview-box,
    .notes-tags-box,
    .markdown-meta-box {
        grid-column: 1 / 2;
    }

    .notes-tags-box, .markdown-meta-box {
        grid-template-columns: 1fr;
    }
}
</style>
</head>
<body>

    <div class="container">
        <!-- Preview Box (spans both columns) -->
        <div class="box preview-box" id="preview-container">
            <h2>Preview of Selection</h2> <!-- Headline stays outside of the rendered content area -->
            <div id="preview">
                <p>Markdown content will be previewed here.</p>
            </div>
        </div>

        <!-- Notes and Tags Side by Side -->
        <div class="notes-tags-box">
            <div class="box notes-section">
                <h3>Notes</h3>
                <textarea id="notes" class="note-field" placeholder="Enter your notes here..."></textarea>
            </div>

            <div class="box tags-section">
                <h3>Tags</h3>
                <input type="text" id="tags" class="tag-input" placeholder="Enter tags separated by commas">
                <div class="checkbox-group">
                    <label><input type="checkbox"> Review</label>
                    <label><input type="checkbox"> Obsidian</label>
                    <label><input type="checkbox"> AppleShortcuts</label>
                    <label><input type="checkbox"> macOS</label>
                    <label><input type="checkbox"> iPadOS</label>
                </div>
            </div>
        </div>

        <!-- Markdown and Meta Information Side by Side -->
        <div class="markdown-meta-box">
            <div class="box markdown-section">
                <h3>Markdown</h3>
                <textarea id="markdown" placeholder="Enter markdown content here..." oninput="updatePreview()"></textarea>
            </div>

            <div class="box meta-section">
                <h3>URL</h3>
                <input type="text" id="url" placeholder="Enter URL">
                <h3>Page Title</h3>
                <input type="text" id="title" placeholder="Enter page title">
            </div>
        </div>
    </div>


    <button class="submit-button" onclick="handleSubmit()">Submit</button>

    <script>
        function updatePreview() {
            const markdownContent = document.getElementById('markdown').value;
            const previewBox = document.getElementById('preview');
            previewBox.innerHTML = marked.parse(markdownContent);
        }

        function handleSubmit() {
            const notes = document.getElementById('notes').value;
            const tagsInput = document.getElementById('tags').value;
            const markdown = document.getElementById('markdown').value;
            const url = document.getElementById('url').value;
            const title = document.getElementById('title').value;

            const tagsArray = tagsInput.split(',')
            .map(tag => `#${tag.trim()}`)
            .filter(tag => tag.length > 1);

            const checkedTags = Array.from(document.querySelectorAll('.checkbox-group input[type="checkbox"]:checked'))
            .map(checkbox => `#${checkbox.parentElement.textContent.trim()}`);

            const tags = [...tagsArray, ...checkedTags];

            const data = {
                notes: notes,
                tags: tags,
                markdown: markdown,
                url: url,
                title: title
            };

            const jsonString = JSON.stringify(data);
            window.location.href = `shortcuts://run-shortcut?name=Snippets+&input=${encodeURIComponent(jsonString)}`;
        }
    </script>
</body>
</html>

The Snippet+

Before cre­at­ing the short­cut, let’s take a look at how a snip­pet will be struc­tured. The snip­pet con­sists of four dis­tinct sec­tions:

  1. Head­er: The head­er begins with the call­out indi­ca­tor > [!quote]. This is fol­lowed by the cur­rent date, the page title, and the page URL.
  2. Tags: The sec­ond sec­tion con­tains a line with tags that are rel­e­vant to the snip­pet.
  3. Selec­tion: The third sec­tion dis­plays the brows­er selec­tion for­mat­ted in Mark­down.
  4. Note: The note is ren­dered in ital­ics in the fourth sec­tion to dis­tin­guish it from the selec­tion sec­tion.

Here is an exam­ple in Mark­down for­mat, along with a screen cap­ture from Obsid­i­an:

> [!quote]  4.11.24 [Obsidian (software) - Wikipedia](https://en.wikipedia.org/wiki/Obsidian_(software))
>#definiton #Obsidian
> **Obsidian** is a [personal knowledge base](https://en.wikipedia.org/wiki/Personal_knowledge_base) and [note-taking](https://en.wikipedia.org/wiki/Note-taking) software application that operates on [Markdown](https://en.wikipedia.org/wiki/Markdown) files.[[3]]()[[4]]()[[5]]() It allows users to make [internal links](https://en.wikipedia.org/wiki/Internal_links) for notes and then to visualize the connections as a [graph](https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)).[[6]]()[[7]]() It is designed to help users organize and structure their thoughts and knowledge in a flexible, [non-linear](https://en.wikipedia.org/wiki/Nonlinear_system) way.[[8]]() The software is free for personal use, with commercial licenses available for pay.[[3]]()[[9]]()
> 
> *This is the first paragraph of the Obsidian article in wikipedia*
The image displays a section from a Wikipedia article about "Obsidian," a software application designed for personal knowledge management and note-taking. It mentions that Obsidian operates on Markdown files, allows users to create internal links for notes, and helps visualize connections as a graph. The text notes that it enables users to organize and structure their thoughts in a flexible, non-linear manner, and is free for personal use, with commercial licenses available. There are hashtags and citations included in the passage.

The Shortcut

The first block in most short­cuts defines the source of the “short­cut input.” For this short­cut we need a “Receive No input Nowhere” input block, because we don’t need any oth­er input source. This option can­not be select­ed direct­ly. The eas­i­est way to achieve this is to first drag the if action into the Short­cut edi­tor and then select “Short­cut Input” as the input para­me­ter. Then, the block with the source “Nowhere” will appear, where the first para­me­ter has to set to No.

With the already imple­ment­ed if/otherwise action in the edi­tor, the short­cut can now be defined. The “if” con­di­tion will be exe­cut­ed when the short­cut is called on a brows­er win­dow with a selec­tion, retriev­ing all the nec­es­sary data from the active brows­er tab. Con­verse­ly, the “oth­er­wise” con­di­tion will be processed when the short­cut is invoked via the sub­mit but­ton on the HTML form page, where it will build and cre­ate the snip­pet.

First, let’s exam­ine what hap­pens when the ‘if’ con­di­tion detects no input. In this case, the actions from the “Brows­er-Actions” app come into play. The attrib­ut­es of the active web­page are retrieved using the action “Get Details of the tab active tab of front­most win­dow in front­most brows­er.” A list of pos­si­ble result para­me­ters can be found in the doc­u­men­ta­tion.

In the final step, the HTML file will open in a new tab of the active brows­er, and the cor­re­spond­ing fields for the page URL, page title, and markup will be pop­u­lat­ed with the retrieved data. This is accom­plished using the action “Set form field with ‘id’ attribute of field name to val­ue para­me­ter in active tab of front­most win­dow in front­most brows­er” from the “Brows­er Actions” app.

Once the fields are filled with data, the user can add addi­tion­al notes and tags. Upon click­ing the “Sub­mit But­ton,” the “oth­er­wise” con­di­tion will be exe­cut­ed, as the short­cut is now called with input in the form of a JSON string.

The image contains a series of programming or scripting commands used to automate tasks in a web browser environment. It seems to involve selecting and manipulating elements within a web page:

The actions in the ”oth­er­wise” con­di­tion con­vert and pre­pare the JSON input to cre­ate the snip­pet, which is then includ­ed on the snip­pet page.

First, the tags are con­vert­ed into a string, sep­a­rat­ed by spaces. The result of the ”com­bine” action is assigned to the vari­able tags. To access the “val­ue” of a “key,” spec­i­fy the dic­tio­nary as the data source in the action. Then, in the selec­tion pop­up, enter the name of the key you want to retrieve in the input at the bot­tom, which in this case is “tabs.”

Adding the > char­ac­ter to the begin­ning of each line of the Mark­down from the retrieved selec­tion is a bit tricky. First, the entire text is con­vert­ed into a list, where each line rep­re­sents an item. Then, this list is iter­at­ed over in a loop, and the > char­ac­ter is prepend­ed to each item. The result, again a list, must be con­vert­ed back into a string, with each item sep­a­rat­ed by a line break. The result of this con­ver­sa­tion is assign to the vari­able mark­down. The same pro­ce­dure has to be done with the note pro­vid­ed by the user.

Now the snip­pet can be built in a text box as spec­i­fied above. This box then will be prepends to the Snip­pets+ Note (in my case in the vault “Obsid­i­an Notes” below the head­line ## Snippets+)

The “Stop and out­put” action is cre­at­ed auto­mat­i­cal­ly after the first run.

The image contains a series of programming or scripting commands used to automate tasks in a web browser environment. It seems to involve selecting and manipulating elements within a web page, specifically:

1. Receiving input and checking if a shortcut input exists.
2. Retrieving details from the active browsing tab.
3. Opening a file (a snippet) in a new tab.
4. Setting values for various form fields (like markdown content, URL, and title) based on the current selection and page context.
5. Clicking an element on the page identified by a CSS selector.

The commands suggest a focus on web automation, potentially for tools or scripts designed to assist with form filling or data retrieval in a browser.

Last Words

That’s all. Test this short­cut with the HTML form in every brows­er except Fire­fox and Arc. As I men­tioned in my pre­vi­ous arti­cle, I only add most of my short­cuts to the Find­ers Short­cuts menu, as this is the eas­i­est way for me to access them. If you assign oth­er meth­ods, such as key­board short­cuts, ensure that the “Short­cut Input” box remains set to “No” and “Nowhere.” Oth­er­wise, it might result in the wrong part of the con­di­tion­al state­ment being exe­cut­ed.

The capa­bil­i­ties in iOS and iPa­dOS are much more restrict­ed, which means that “Brows­er Actions” only runs on macOS. As a result, this short­cut is not use­ful for mobile usage. Due to this lim­i­ta­tion, I call the HTML file local­ly on my Mac­Book, but it’s also pos­si­ble to call it from a web serv­er.

The exam­ple pre­sent­ed is cer­tain­ly not per­fect. It is intend­ed only to inspire your own ideas on how these apps can be used. At the moment, I am using this short­cut exten­sive­ly. This often leads to new ideas on how this work­flow can be improved and enhanced.

Have fun, and spe­cial thanks to Car­lo for these two apps.

As always, please leave any feed­back, cor­rec­tions, or ideas in the com­ments.

One response to “Improving Web Selection Capture for Obsidian with “Browser Actions””

  1. I just received an email from Car­lo, who will take a look at the issue with the hid­den fields. He also sent me a workaround. Just adding this CSS to the style sec­tion:

    .hidden-input {
    position: absolute;
    left: -1000px;
    overflow: hidden;
    width: 1px;
    height: 1px;
    }

    Add the class to the
    Mark­down and Meta Infor­ma­tion Side by Side
    div class=“markdown-meta-box hid­den-input”

    Now the mark­down field and the pageURL and pageTi­tle fields ar hid­den.

Leave a Reply

Your email address will not be published. Required fields are marked *