· 7 min read coding javascript productivity

Move from Trello to Obsidian's kanban boards with this simple bookmarklet

...

I’ll try and make this short and sweet. I’m not trying to turn this into a recipe where you need to scroll through 20 screens of backstory just to figure out how much flour you need.

In fact. If you know what bookmarklets are, are using obsidian, and have some things stuck in Trello because it’s a pain to get stuff out, then just drag this link (Trello –> Obsidian) to your browser bookmarks and go to town. You’ll probably figure it out. If that’s not enough, jump to how to use it and ignore all the beautiful time I lost to padding out the rest of this post.

Otherwise, here’s 20 screens of backstory.

Why obsidian?

I’ve been an avid user of Obsidian (A second brain, for you, forever. As their tagline says.) for a couple years. There are few apps that have ever affected my productivity as much as obsidian has. I’m not going to go into detail about how it helps me to better organize and connect everything that I’ve ever written, or how it has created a better system for maintaining and helping me act on tasks and projects because there’s a lot of coverage on the internet for those sorts of things. In fact, here are a few:

What’s a boookmarklet, you ask?

Remember the time before Chrome Extensions existed? If you just asked me what a bookmarklet is, then you clearly don’t. I get it, I might be old.

Before browser extensions, the best we had were bookmarklets - bookmarks that contained a bunch of JavaScript code that could run on any page. They didn’t need to be installed, they didn’t ask for crazy permissions, and they didn’t run all the time collecting data on every page you visited.

They still don’t. And I think they still have a place in the modern web.

I vented about this a little bit recently when I wrote a bookmarklet for copying YouTube links with specific timecodes in markdown so I could use them in Obsidian.

The following chart shows Google search trends for “Bookmarklet” over the last 5 years and their down-trend following the launch of Chrome Extensions.

...
A chart showing search trends for "Bookmarklet" over time.
Source: Google Trends United States 01 Jan 04 - 01 Apr 23

What’s that bit of uptick at the end? Maybe we are on the verge of a resurgence and that people are starting to realize they don’t need a Pinterest Extension or a collection of useless tools mucking up their browser UI just to quickly add quirky DIY projects to your future dream home projects - especially with many extensions overstepping their usefulness.

Are bookmarklets safe? Specifically this one?

I’m glad you’re asking these questions. You should be. Again, smarter people something something:

As for what exactly this bookmarklet is doing, you’ll just have to look at the code to find out. Spoiler alert, its doesn’t do anything other than pull stuff off of the page and copy it into your clipboard. So yeah, it’s safe. The bookmarklet’s code is actually minified, so here’s the full source…

The code

I don’t feel like I need to explain code as long as it’s well commented. Contrary to what this article implies, I don’t write code - which you’ll clearly see if you actually look through this.

// The variable that will store all the text, starts with the kanban board settings
var obsidianText = "---\n\nkanban-plugin: basic\n\n---\n\n";

// Something to keep track of just to display when it's copied.
var numberOfLists;
var numberOfCards;

// Get all the lists in trello
var trelloLists = document.getElementsByClassName("js-list");
numberOfLists = trelloLists.length;

// Cycle through all the lists
for (l = 0; l < numberOfLists; l++){
  // Get the list name
  var trelloListHeader = trelloLists[l].getElementsByTagName("h2")[0].innerText;

  // Append the header to obsidianText in markdown
  obsidianText += "\n## " + trelloListHeader + "\n";

  // Get all the cards in each list
  var trelloItems = trelloLists[l].getElementsByClassName("list-card");
  numberOfCards = numberOfCards + trelloItems.length;

  // Cycle through all the cards in each list
  for (i = 0; i < trelloItems.length; i++){

    // Get the card title
    var trelloItemTitle = trelloItems[i].getElementsByClassName("list-card-title")[0].innerText;

    // Grab all of the labels if they have text specified. This does not get labels that are just colors.
    var trelloLabels = trelloItems[i].getElementsByTagName("button");

    // cycle though all of labels
    for (b=0; b<trelloLabels.length; b++){
      var ariaLabel = trelloLabels[b].getAttribute("aria-label"); // aria label is formatted as aria-label = "Color:red title: "Label_Text""
      var splitAriaValue = ariaLabel.split('title: ')[1]; // Split the string to just get the title, so 0 is trash 1 is the value of 'title' “Label_Text”"

      splitAriaValue = splitAriaValue.replace("“", "") // get rid of the smart quotes
      splitAriaValue = splitAriaValue.replace("”", "") // both of them

      // Append the label to item
      if (splitAriaValue != "none"){
        trelloItemTitle = trelloItemTitle + " #" + splitAriaValue;
      }
    }

    // Get the date. We can't get the time because trello doesn't display it in the list.
    var trelloDate = trelloItems[i].getElementsByClassName("js-due-date-text");
    if (trelloDate.length > 0){ // Only work on the ones that have a date.
      trelloDate = trelloDate[0].innerText;
      var trelloConvertedDate = new Date(trelloDate).toISOString().substring(0, 10);; // Convert it to an actual date so we can change the format
      // Append the date to item
      trelloItemTitle = trelloItemTitle + " @{" + trelloConvertedDate + "}";
    }

  // Append the item (with labels and date) to obsidianText in markdown
  obsidianText += "- [ ] " + trelloItemTitle + "\n";
  }
}

// Append the final expected kanban settins
obsidianText += '\n\n%% kanban:settings\n```\n{"kanban-plugin":"basic"}\n```\n%%';

//Copy text to the clipboard
navigator.clipboard.writeText(obsidianText);


// Flash the time on the page in an overlay so that I know I clicked it.
var elemDiv = document.createElement('div');
elemDiv.innerHTML = "<h1 style='font-size:40px; color:white; text-align:center; margin-top:2em;'>" + "Copied " + numberOfLists + " Lists and " + numberOfCards + " cards. </h1>";
elemDiv.style.cssText = 'position:absolute;width:100%;height:100%;opacity:0.8;z-index:1000;background:#000;top:0';
document.body.appendChild(elemDiv);

// Have it fade out after a bit
setTimeout(function(){ elemDiv.style.display = "none"; }, 2000);

The minified code

var numberOfLists,numberOfCards,obsidianText="---\n\nkanban-plugin: basic\n\n---\n\n",trelloLists=document.getElementsByClassName("js-list");for(numberOfLists=trelloLists.length,l=0;l<numberOfLists;l++){var trelloListHeader=trelloLists[l].getElementsByTagName("h2")[0].innerText;obsidianText+="\n## "+trelloListHeader+"\n";var trelloItems=trelloLists[l].getElementsByClassName("list-card");for(numberOfCards+=trelloItems.length,i=0;i<trelloItems.length;i++){var trelloItemTitle=trelloItems[i].getElementsByClassName("list-card-title")[0].innerText,trelloLabels=trelloItems[i].getElementsByTagName("button");for(b=0;b<trelloLabels.length;b++){var ariaLabel=trelloLabels[b].getAttribute("aria-label"),splitAriaValue=ariaLabel.split("title: ")[1];"none"!=(splitAriaValue=(splitAriaValue=splitAriaValue.replace("“","")).replace("”",""))&&(trelloItemTitle=trelloItemTitle+" #"+splitAriaValue)}var trelloDate=trelloItems[i].getElementsByClassName("js-due-date-text");if(trelloDate.length>0){trelloDate=trelloDate[0].innerText;var trelloConvertedDate=new Date(trelloDate).toISOString().substring(0,10);trelloItemTitle=trelloItemTitle+" @{"+trelloConvertedDate+"}"}obsidianText+="- [ ] "+trelloItemTitle+"\n"}}obsidianText+=&#39;\n\n%% kanban:settings\n```\n{"kanban-plugin":"basic"}\n```\n%%&#39;,navigator.clipboard.writeText(obsidianText);var elemDiv=document.createElement("div");elemDiv.innerHTML="<h1 style=&#39;font-size:40px; color:white; text-align:center; margin-top:2em;&#39;>Copied "+numberOfLists+" Lists and "+numberOfCards+" cards. </h1>",elemDiv.style.cssText="position:absolute;width:100%;height:100%;opacity:0.8;z-index:1000;background:#000;top:0",document.body.appendChild(elemDiv),setTimeout((function(){elemDiv.style.display="none"}),2e3);

How to use it

Finally, we made it through all the backstory. As promised here’s what to do with this bookmarklet, if you couldn’t figure it out.

Trello –> Obsidian

  1. Drag the link above to your browser bookmarks. It’s a bookmark, but the url is actually just JavaScript. That JavaScript will run on any page when you click it.
  2. Rename it if you feel like it
  3. Go to a board in Trello and click the bookmark. It will tell you how many lists and cards, in total, that it copied. If something doesn’t happen… no idea.
  4. Open a new note in Obsidian and make sure to view the note in source mode. I can’t stress that enough. If you copy it in some other way, it’s bound to mangle the text you’re pasting in.
  5. Flip over to the Kanban View (open up your Command Pallet and Toggle Kanban View)
  6. Enjoy

If reading isn’t your style, here’s me giving a quick overview of how to use it:

Limitations and constraints

  • This bookmarklet won’t grab any description or any attached files that are in your Trello cards. Just the card name, the named labels and a due date.
  • If your Trello labels aren’t titled (they’re just a color) - this will ignore them. Go in and name all your labels if you want them to be brought over.
  • Obsidian’s kanban boards let you specify a time, Trello does not.

Thanks

If you made it here, as always, thanks for stopping by.