Category Archives: Dev

Orbital Feed Reader 0.1.8 Codenamed “BEAUTY TREATMENT” is out!

IMG_1185

The most common feedback I’ve heard from folks on Orbital is that it’s not very good looking.  It does the job, but it isn’t a pleasure to look at.

I assume these people are all supermodels, so it looks like Orbital is doing great among the high fashion set.

I got out my scissors, called in the wardrobe department, applied polish and buffed with a chamois. This is the new smooth look, designed to blend in with the new admin themes of WordPress.

Hey, good lookin’!

 

Beauty comes in all thicknesses

Along the way, I’ve added some features – now it is responsive, cleaner and is even usable on my Galaxy S5. Check out this hot resizing action!

Future attractions and graceful aging

Coming soon are some cool things. First, I’m working on version 0.1.9, code named Born Free. It will deal with the how to leave Orbital and how to get into Orbital. I’d never want to trap you!

Second, WordPress is going to upgrade to version 4.0 soon. I’ll be getting Orbital ready for that, and the new REST API should make it easy to build a better mobile experience for Orbital.

Press for Orbital

Two new reviews for Orbital bring a smile to my face!
WordPress Plugins A-Z gave Orbital a 4/5 rating:

This is a great feed reader especially if you are doing research for a post or if you are like many people out there who write additional articles based on what they read. This make it easy to get a pull quote from an article and drop it right into a post. While the layout and functionality is a little raw in its appearance it seems to work very well and to give it a good go I added it to my secret blog site as a place to test some ranting on article and stories. And it seems to work quite well..

That’s great feedback and I feel like I do need to work on the style and appearance – it’s tough and I need help.

Jeff Chandler over at WPTavern also reviewed Orbital, comparing it to Feedly and Google Reader. It’s a lukewarm review – he doesn’t like the interface and feels like Feedly plus PressThis is find for him. Still, he’s offered to help me by looking at revamps of the interface.

Koans for Programmers

I just stumbled on The Codeless Code, a collection of fables and Koans for programmers. It’s brilliant, if a terrible rabbit hole of procrastination – I’ve just burned a few hours clicking through random stories. Here’s a good one to get the flavor, Case 41 is called Garbage:

Java master Suku was investigating the software of a distant temple. On her monitor large swaths of text glowed not black but green, indicating that reams of code had been commented out.

“Curious,” said Suku. “I have opened a fine clock, and discovered orange rinds and fish bones.”

The head monk explained that the inactive code was no longer necessary, yet he had ordered his clan to leave it in place: for if it someday became desirable to restore the logic then the code could simply be uncommented, rather than wastefully written from scratch.

“Understandable,” nodded Suku.

The next day the monks assembled again for the Java master’s inspection. With concern they reported that the head monk could not be found. Suku gestured up into the rafters where the missing monk dangled from a strong rope, by the neck. A foul odor wafted downwards.

“Your head monk’s services are no longer necessary,” said Suku. “Yet let his corpse moulder above you from this day forward. After all, his methods may someday become desirable again, and it would be wasteful to train another monk from scratch.”

In her final report, Suku noted a swift change in the clan’s coding practices, and credited the good example set by the deceased head monk. We should consider his reinstatement, she wrote.

A Vim macro is just a series of characters.

I just learned something that gave me a EUREKA moment. The text you type in vim is also potentially instructions to vim and the instructions are just text. You can record a macro, a series of keystrokes that you play back, in Vim by typing:

  1. q
  2. a letter to record your keystrokes into – let’s use r
  3. then doing your keystrokes
  4. then type q again to stop recording.

So qr6jf|c3w|width=autoESC9jf|c3w|width=80%ESCq

  • record a macro r
  • go down 6 lines
  • move forward to a pipe character “|”
  • Change the next 3 words to say |width=auto then escape edit mode
  • go down 9 lines
  • move forward to a pipe character “|”
  • change the next 3 words to |width=80% then escape edit mode
  • stop recording the macro

To apply that macro or play it back: type @r. Vim will play all those keystrokes back from where you are in a document. That’s really useful when you want to automate something repetitive.

I changed my mind in how I wanted something to look in a wiki at work. 80 pages needed to be changed in a dumb way and I thought it might take longer to explain to people that it needed to be done than to just do it myself. I started by copying each page to vim to edit, running a macro of keystrokes to make the change, then pasting the result back.

Then I hit a couple of pages that were slightly off. They broke the macro, which was long and complicated. I read up on how to edit a macro so I didn’t have to reenter it.

That’s when I found out that the “r” that we stored that macro in is just a register, just like you might yank into. In vim you copy/paste by yanking into a register with a y and pasting with a p:

  • fyt; – store in register f the yanking of everything on this line til a semicolon
  • fp – take what is in register f and put it where the cursor is.

I typed “rp and saw my macro contents there on a line. I edited the macro to account for these new differences and then did tD to delete the entire line and store it in register t. Then I went to the top of the document by typing gg and applied my macro t by typing @t and it just worked!

How cool is that? There is no new scripting language to learn – all the text you delete and paste is potentially also instructions. This must be what lispers feel like all the time.

Now I wonder about trying to apply documents as instructions to edit themselves….

How (not) to do Tagging in Angular.js

I’ve been working on getting tagging working in Orbital Feed Reader. Tagging feeds was really brilliant in Google Reader and I want that in the feed reader I use. So I’m building it.

The Setup

You can store tagging in your database a few different ways, but here’s the way I chose:

                         +----------+
      +----------+       | feed_tag |
      | feeds    |       |----------|
      |----------|       |  tag_id  +---+
      |  id      +-------+  feed_id |   |   +--------+
      |  name    |       +----------+   |   | tags   |
      |  url     |                      |   |--------|
      |  unread  |                      +---+  id    |
      +----------+                          |  name  |
                                            |        |
                                            +--------+

You’ve got feeds and tags, those have an ID number. You’ve got a table linking those by ID number. Easy.

The Goal

I wanted to be able to toggle between either a simple list of feeds or a list of tags with feeds underneath.

<script type="text/ng-template"  id='feedline.html'>
  <div class="feed" id="feed-{{feed.feed_id}}" 
    ng-class="{'is-editable': editable, 'is-selected': feed.isSelected}" 
    ng-click="select(feed)"  >
      {{feed.feed_name}} 
      <span class="feedcounter">{{feed.unread_count}}</span>
      <a ng-show="editable" ng-click="editFeed(feed)">⚙</a>
  </div>
</script>
<ul id='feeds' ng-hide="showByTags" >
  <li ng-repeat="feed in feeds" ng-include="'feedline.html'" ></li>
</ul>
<ul id='tags' ng-show="showByTags">
  <li class="tag" ng-repeat="(tag, feeds) in tags" >
    <div id="{{tag}}" ng-click="select(tag)" 
      ng-class="{'is-selected':tag.isSelected}" >
      #{{tag}} 
      <span class="feedcounter">{{tagUnreadCount(tag)}}</span> 
    </div>
    <ul>
      <li ng-repeat="feed in feeds" ng-include="'feedline.html'"></li>
    </ul>
  </li>
</ul>

My first stab at doing this was very wrong and I wanted to share that so you don’t go down that dumb path on your project.

The Wrong way to do tagging

I decided I would pull the feeds in two different ways. I would pull feeds from the database as a normal list, but then I would also pull a list of tags with feeds underneath.
This was my first mistake. Hitting the DB twice for the same data means I’m doing lots of duplication and sending lots of information over the internet (slooooow) twice. It also means keeping lists in sync which is also a code smell that means you are probably not keeping things DRY.

So I pull feeds from the db once like this:

SELECT
  feeds.id AS feed_id,
  COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
  feeds.feed_url,
  COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
  COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
  feeds.lASt_updated,
  feeds.lASt_error,
  u_feeds.private,
  SUM(IF(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count
FROM user_feeds AS u_feeds
INNER join feeds AS feeds
  ON u_feeds.feed_id = feeds.id
LEFT OUTER JOIN user_entries AS ue
  ON ue.feed_id=feeds.id
  AND u_feeds.owner = current_user_ID
GROUP BY feeds.id,
  feeds.feed_url,
  feeds.feed_name,
  feeds.icon_url,
  feeds.site_url,
  feeds.lASt_updated,
  feeds.lASt_error,
  u_feeds.private

And then pull feeds by tag like this:

SELECT
COALESCE(tags.name,'Untagged') AS tag,
COALESCE(tags.id, null) AS tag_id,
feeds.id AS feed_id,
COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
feeds.feed_url,
COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private,
SUM(IF(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count
FROM user_feed_tags AS uft
INNER JOIN tags AS tags
  ON tags.id = uft.tag_id
INNER JOIN user_feeds AS u_feeds
  ON uft.user_feed_id = u_feeds.id
INNER JOIN feeds AS feeds
  ON u_feeds.feed_id = feeds.id
LEFT OUTER JOIN user_entries AS ue
  ON ue.feed_id=feeds.id
WHERE u_feeds.owner = current_user_ID
GROUP BY
feeds.id,
feeds.feed_url,
feeds.feed_name,
feeds.icon_url,
feeds.site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private,
tags.name

UNION
SELECT
'Untagged' AS tag,
null AS tag_id,
feeds.id AS feed_id,
COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
feeds.feed_url,
COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private,
SUM(if(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count

FROM user_feeds AS u_feeds
LEFT OUTER JOIN user_feed_tags AS uft
  ON uft.user_feed_id = u_feeds.id
INNER JOIN feeds AS feeds
  ON u_feeds.feed_id = feeds.id
LEFT OUTER JOIN user_entries AS ue
  ON ue.feed_id=feeds.id
WHERE u_feeds.owner = current_user_ID
  AND ISNULL(uft.user_feed_id)
GROUP BY
feeds.id,
feeds.feed_url,
feeds.feed_name,
feeds.icon_url,
feeds.site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private

For feeds by tag I then would use underscore.js’s excellent _.groupBy() method. It’s easy to see tags in angular using groupBy and I thought it was good enough.

It worked! Sure, it was inefficient, but I’m pragmatic – I just wanted to get this done and out the door so I could use it. No point in prematurely optmizing, right?

Next step was making sure I could show the unread count per tag. And keep it all in sync between the tags and the feeds themselves. This is when I smelled my stinky code smells. Every time I marked an entry in a feed as read I would have to search it out multiple times on multiple lists. This means this information was stored in multiple places – and it’s always good to follow the DRY principle. Don’t Repeat Yourself.

The Right(er) way to do tagging

Let’s regroup and try this again. I want to have ONE place where I pull info from my DB about a feed, and I want to only update information in one place but display it in multiple ways.

I changed it so I pull a straight list of the feeds, but use the group_concat SQL function to also pull in all the tags associated with a feed.

SELECT 
  u_feeds.id AS feed_id,
  COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
  feeds.feed_url, 
  COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
  COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
  feeds.last_updated,
  feeds.last_error,
  u_feeds.private,
  SUM(IF(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count,
  GROUP_CONCAT(DISTINCT COALESCE(tags.name,'Untagged')) as tags
FROM $user_feeds AS u_feeds
INNER JOIN $feeds AS feeds
  ON u_feeds.feed_id = feeds.id
  AND u_feeds.owner =  $current_user->ID.
LEFT OUTER JOIN $user_entries AS ue
  ON ue.feed_id=feeds.id
LEFT OUTER JOIN $user_feed_tags uft
  ON uft.user_feed_id = u_feeds.id
LEFT OUTER JOIN $tags tags
  ON uft.tag_id = tags.id
GROUP BY 
  feed_id,
  feed_url,
  feed_name,
  icon_url,
  site_url,
  last_updated,
  last_error,
  private

When I want to show a list of feeds I can just go with the same solution I had before.
But when I want to group by tags I can apply a couple of interesting tricks to solve this for me.

    refresh : function refresh(callback){
  _isLoading = true;
  $http.get(opts.ajaxurl + '?action=orbital_get_feeds')
  .success( function( data ){
    //Here is our simple feed list
    _feeds= data;

    //Now lets get a list of all the unique tags in those feeds
    var taga = _.unique(_.pluck(_feeds, 'tags').join().split(","));

    //For each tag, lets build up a list of the feeds that have that tag
    _.each(taga, function(tag){
      _tags[tag] = _.filter(_feeds,function(feed){
                      return _.contains(feed.tags.split(","),tag);
                    });
    })
    _isLoading = false;
    //Should we do some extra work?
    if(callback){
      callback(_feeds);
    }
  });
},

What’s going on there?
I want to get an array of all my unique tags, so first thing I do, I use _.pluck() to give me an array of the tags element of each feed.
This gives me:

[
  ["art,gifs"],
  ["art"],
  ["Untagged"],
  ["gifs"],
  ["Untagged"],
  ["Untagged"],
]

Then I join() those together (the default join is with a comma):

"art,gifs,art,Untagged,gifs,Untagged,Untagged"

I split(“,”) that on commas:

["art","gifs","art","Untagged","gifs","Untagged","Untagged"]

And finally we just grab the _.unique() values:

["art","gifs","Untagged"]

So now we have a list of the tags for our feeds – how exciting! Let’s build a list of the feeds for each of these tags.
So, for _.each() tag in our list of tags we go back to our list of feeds and _.filter() it – we want only a feed where the feed.tags _.contains() the tag.

Why’s this so much better? Well – if we update the `unread_count` for a feed or change the name of a feed – it updates the underlying object. That means your change percolates up automatically through angular databinding to every part of your UI. No more keeping lots of lists in sync.

And now I’ve bored even myself to death with this so I guess that’s it.

Orbital Feed Reader 0.1.5 Codenamed “CHICKEN HAT” is out!

It’s been a busy couple of months for me. I’ve had my first user feedback on Orbital Feed Reader – a fella who’s trying to use it on GoDaddy’s Awful Hosting. I haven’t fixed all of his issues but I’m getting closer. Lil Peanut has been smiling, grabbing things, laughing, and peeing on me.

What’s in 0.1.5? Some bug fixes, some UI fixes and a way to change the SORT ORDER!

Feed Names

When you put in a feed to autodiscover it will show you the actual feed names instead of just the feed URL. This is important because it lets you choose among many feeds in a smarter way.
Feed Names on Orbital

Sort Order

Henry Vitoski pointed out that most people will want to use Orbital differently than I do. I’m a completist, I like to start at the bottom and read EVERY SINGLE THING. The rest of you apparently are more interested in seeing new things first and then delving into the past. Now there’s a way to change the sorting. It will remember whatever you choose.
See more details at the changelog page.