Day 38 – Evolution Of Advanced Hello World App

Building just a simple Hello World app in KRL is fairly simple. There are only so many ways to put a notify on the page. Kicking it up a notch and adding in a form and some persistance really opens up the doors to a lot of possibilities and different ways of doing it. I thought it might be interesting to document the evolution as I attempt to create a good advanced Hello World example app for Kynetx.

Version 0

ruleset a60x557 {
  meta {
    name "advanced-hello-world"
    description <<
      advanced-hello-world
    >>
    author "Mike Grace"
    logging on
  }

  rule plain_krl_way {
    select when pageview "example\.com"
    pre {
      form =<<
        <form id="my-form">
          Your Name: <input type="text" name="user-name"/>
          <input type="submit" value="Submit"/>
        </form>
      >>;
    }
    {
      notify("Remembering your name",form) with sticky = true;
      watch("#my-form", "submit");
    }
  }

  rule get_form {
    select when web submit "#my-form"
    pre {
      userName = event:param("user-name");
    }
    {
      notify("Thanks #{userName}!","") with sticky = true;
    }
  }
}
  • put form on page
  • watch form
  • respond to form submit with notify

This is super simple but falls short in several areas

  • nothing to let the user know that the server is currently working on processing the form submit
  • form can be submitted more than once
  • submitted name isn’t stored into persistance
  • interesting but not really useful in my opinion
  • this isn’t how I get data out of forms (will show later)

Action shots:

running app for first time on example.com

submitting form first time

submitting form as many times as I want

Version 1

ruleset a60x557 {
  meta {
    name "advanced-hello-world"
    description <<
      advanced-hello-world
    >>
    author "Mike Grace"
    logging on
  }

  rule what_should_i_do {
    select when pageview "example\.com"
    pre {
      userName = ent:userName || "";
      form =<<
        <form id="my-form">
          Your Name: <input type="text" name="user-name"/>
          <input type="submit" value="Submit"/>
        </form>
      >>;
    }
    if (userName eq "") then {
      notify("Remembering your name",form) with sticky = true;
      watch("#my-form", "submit");
    }
    notfired {
      raise explicit event user_name_known with userName = userName;
    }
  }

  rule user_name_known {
    select when explicit user_name_known
    pre {
      userName = event:param("userName");
    }
    {
      notify("#{userName} is 'da bomb!","") with sticky = true;
    }
  }

  rule get_form {
    select when web submit "#my-form"
    pre {
      userName = event:param("user-name");
    }
    {
      notify("Thanks #{userName}!","") with sticky = true;
    }
    fired {
      set ent:userName userName;
    }
  }

}
  • 14 get user’s name from persistance and set to blank string if not found
  • 22 if the user’s name is not found in persistance then put the form up and watch for the form submit
  • 26 if the user’s name was found in persistance then raise an explicit event to handle user’s name being found
  • 34 get user’s name from passed parameters is raised explicit event. Could have just pulled it from persistance but then you wouldn’t have gotten to see how to pass parameters in explicit events.
  • 50 set the user’s name into persistance when the rule runs responding to form submit event

This example is much better but still leaves a lot out.

  • no form validation
  • no way for user to change set user name once submitted
  • still no indication that form submission is ‘in progress’
  • still able to submit multiple times

Action shots:

running app on example.com for the first time

submitting form for the first time

submitting the form as many times as I want

After page reload and running app again

Version 2

ruleset a60x557 {
  meta {
    name "advanced-hello-world"
    description <<
      advanced-hello-world
    >>
    author "Mike Grace"
    logging on
  }

  global {
    css <<
      a {
        color: white;
      }
    >>;
  }

  rule what_should_i_do {
    select when pageview "example\.com"
    pre {
      userName = ent:userName || "";
      form =<<
        <form id="my-form">
          Your Name: <input type="text" name="user-name"/>
          <input type="submit" value="Submit"/>
        </form>
      >>;
      greeting =<<
        <p>#{userName} is 'da bomb!'</p>
        <p>Clear saved name by running the app on <a href="http://example.com/?clear">example.com/?clear</a></p>
      >>;
      content = (userName eq "") => form | greeting;
    }
    {
      notify("Hello World (advanced)", content) with sticky = true and opacity = 1;
      watch("#my-form", "submit");
    }
  }

  rule get_form {
    select when web submit "#my-form"
    pre {
      userName = event:param("user-name");
    }
    {
      notify("Thanks #{userName}!","") with sticky = true;
    }
    fired {
      set ent:userName userName;
    }
  }

  rule clearing {
    select when pageview "example\.com\/\?clear"
    notify("Cleared","");
    fired {
      clear ent:userName;
    }
  }

}
  • 12 set CSS so link on black background is visible
  • 29 setup greeting HTML at the same time as the form
  • 33 decide what to put on the page using condition expression
  • 54 clear saved name when user runs on specified clear page

This is getting closer but still lacks

  • form validation or disallowing user to submit multiple times
  • when persistance is cleared the greeting is also displayed
  • no indication that form submission is ‘in progress’
  • still not the way I would do it

Action Shots:

running app first time

submitting name first time

submitting name many times

running app again after refresh of page

running app on designated clear page

Version 3

ruleset a60x557 {
  meta {
    name "advanced-hello-world"
    description <<
      advanced-hello-world
    >>
    author "Mike Grace"
    logging on
  }

  global {
    css <<
      .kGrowl-notification a {
        color: white;
      }

      #a60x557-working, #a60x557-notice {
        display: none;
      }
    >>;
  }

  rule what_should_i_do {
    select when pageview "example\.com(?!.+clear)"
    pre {
      userName = ent:userName || "";
      form =<<
        <p id="a60x557-notice">Your name input must be more than 2 characters</p>
        <p id="a60x557-form">Your Name: <input type="text" id="a60x557-user-name"/> <button id="a60x557-submit">Submit</button></p>
        <img id="a60x557-working" style="display: none" src="http://kynetx-apps.s3.amazonaws.com/advanced-hello-world/working.gif"/>
      >>;
      greeting =<<
        <p>#{userName} is 'da bomb!'</p>
        <p>Clear saved name by running the app on <a href="http://example.com/?clear">example.com/?clear</a></p>
      >>;
      content = (userName eq "") => form | greeting;
    }
    {
      notify("Hello World (advanced)", content) with sticky = true and opacity = 1;
      emit <|
        $K("#a60x557-submit").bind("click", function() {

          // get user name from input
          var userName = $K("#a60x557-user-name").val();

          // check input
          if (userName.length > 2) {
            // don't allow user to submit more than once
            $K(this).unbind("click");

            // get app object to raise web event
            app = KOBJ.get_application("a60x557");

            // raise web event to system with user name
            app.raise_event("user_name_submitted", {"user-name":userName});

            // show user 'in progress'
            $K("#a60x557-form,#a60x557-notice").remove();
            $K("#a60x557-working").show();
          } else {
            $K("#a60x557-notice").show()
          };
        });
      |>;
    }
  }

  rule get_form {
    select when web user_name_submitted
    pre {
      userName = event:param("user-name");
      reset =<<
        <p>Clear saved name by running the app on <a href="http://example.com/?clear">example.com/?clear</a></p>
      >>;
    }
    {
      emit <|
        // close previous notify
        $K(".kGrowl-notification .close").trigger("click");
      |>;
      notify("Thanks #{userName}!", reset) with sticky = true and opacity = 1;
    }
    fired {
      set ent:userName userName;
    }
  }

  rule clearing {
    select when pageview "example\.com\/\?clear"
    notify("The saved name has been cleared","");
    fired {
      clear ent:userName;
    }
  }

}
  • updated CSS to only change links inside the notify
  • 24 don’t show form/welcome back notify if on the clear page
  • 28 add notice to show if user input doesn’t match validation rule
  • 30 add working notification image to let user know app is ‘in progress’
  • 41 watch for user to submit form using jquery
  • 47 check user input against validation rule
  • 49 release click listener so form only gets submitted once
  • 52 get application JS object to raise web event
  • 55 raise web event with user’s name
  • 58 remove form stuff
  • 59 show working spinner image
  • 61 show notice if user’s input doesn’t pass input validation
  • 79 close previous notify once saved form returns

Now this advanced hello world example app

  • only allows the user to submit name once
  • allows user to clear set name
  • better CSS selectors
  • form validation
  • in progress visual
  • stores user’s name into persistance
  • this is how I would do it

Action shots:

running app first time

submitting name first time

name successfully saved

running app again after reload

running app on designated clear page

Get the bookmarklet to try it out yourself!

Gratuitous day 38 crazy face

Posted in Kynetx | Leave a comment

Day 37 – Interacting With Youtube Videos

Over a year ago, a friend of mine and I were dreaming up of ways to create a cool Kynetx getting started tutorial/demo. One of my ideas was to have a Kynetx app that took you through a few sites and showed stuff off while embedding a video on the page and syncing up the actions taken on the page with the video. Now that vision is a reality since YouTube has a JavaScript API available from their videos. I created a test app to test one aspect of the API and it’s shockingly simple. Continue reading

Posted in Kynetx | Leave a comment

Day 36 – Mime Type For Firefox Extension Auto Install On Download

My current favorite way to share my Kynetx apps is through Amazon’s S3. For Firefox to auto detect a Firefox extension and start the installation process, special Mime type headers need to be set. This can now be easily done with S3 through the AWS console or through a capable FTP client like cyberduck. Continue reading

Posted in Kynetx | Leave a comment

Day 35 – Find And Replace Words In Twitter Tweet Stream

I recently built a Kynetx app to remove foul language from my Twitter tweet stream and thought it was interesting enough to share. The code is mostly JavaScript but there are a few concepts that are really good to know when building a Kynetx app that uses a lot of JavaScript. You can find the original app on my blog over at http://geek.michaelgrace.org/2011/01/foul-fowl-control-kynetx-app-for-twitter-com/ Continue reading

Posted in Kynetx | 1 Comment

Day 34 – Dynamically Picking From Hash

Sometimes I don’t want to statically pick from a dataset or a hash. Sometimes I want to dynamically pick from a hash or dataset based on a condition and I can do that by using a beesting in a pick statement. Continue reading

Posted in Kynetx | 1 Comment

Day 33 – First Time App Is Run For The Day

Sometimes you need to know the first time each individual user runs the app for the day. Sometimes you need to know the first time a user runs the app for the day. Well… here is one way to do both. Continue reading

Posted in Kynetx | 1 Comment

Day 32 – Old School Twitter Retweet

Modify the Twitter web interface to provide the old school “RT” functionality that many other Twitter clients provide. Continue reading

Posted in Kynetx | 1 Comment

Day 31 – Load Stuff Inline In Twitter Stream

Want to customize what can load inline on Twitter’s tweet stream interface? Here is how I built a Kynetx app to load XKCD comics inline when a user clicks on a tweet with a link to an XKCD comic. Continue reading

Posted in Kynetx | 4 Comments

Day 30 – Detecting Empty Pick

Many times I need to be able to know if my pick statement returns nothing or something so I can react differently. I finally figured out a good way to do this. Continue reading

Posted in Kynetx | Leave a comment

Day 29 – URL Encode Strings

For those late evenings when you just need a good cold URL encoded string…. Continue reading

Posted in Kynetx | 1 Comment

Day 28 – Updating User’s List When User Joins App

I’m building an app where I want users to be able to “join” the app. The plan is to eventually have this Kynetx app be a Kynetx powered Twilio app that users can sign up to get reminders based on their current status for the month. This example doesn’t cover users “leaving” the app. Continue reading

Posted in Kynetx | Leave a comment

Day 27 – Building Hashes Using Beestings

Wondering if I could build a Hash object using beestings I built this test Continue reading

Posted in Kynetx | Leave a comment

Day 26 – Modify Other Browser Extensions Behavior

I recently built a simple Kynetx app called Minimal One True Fan that modifies what the One True Fan App does on each web page. The code is fairly simple and consists mostly of JavaScript but it’s interesting enough that I thought it would be good to share it here for learning purposes.

The One True Fan app loads a bar that sits at the bottom of every page I visit.

I love the app and the bar but I wanted to be able to continue to use the app and not have the bar always at the bottom. I built this Kynetx app to modify the bar so after it loads, it turns into a simple checked in/not checked in icon. Continue reading

Posted in Kynetx | Leave a comment

Day 25 – Merging Two Hashes

Being able to pick information out of a hash is nice but what about when you need to update the hash or combine/merge it with another? Continue reading

Posted in Kynetx | Leave a comment

Day 24 – Selection Expression Filtering On Variable Value

Being able to write selection expressions that select on an event AND only when a variable’s value matches is really nice. The example app code is a progression of the app shown on day 23 Continue reading

Posted in Kynetx | Leave a comment

Day 23 – Decode Function – Convert JSON To Objects

Sometimes you just need to pass JavaScript Objects from the client to the server be it arrays or hashes. Continue reading

Posted in Kynetx | 1 Comment

Day 22 – Already In Friend List – Working With Arrays

In a recent app I was building, I was allowing the user to build a list of ‘friends’ on stackoverflow.com. A user can add friends by viewing their detail page and clicking a button. I wanted to display a different button if they were already in their friend list and this is how I did it. Continue reading

Posted in Kynetx | Leave a comment

Day 21 – Modifying Facebook Stream With Kynetx

At a recent family dinner on Christmas Eve, some of the family was joking about how they never understand my status updates on Twitter and Facebook, especially when it’s about programming or Kynetx. This discussion gave me the idea to create a Kynetx app for them that they could run that would modify my status updates to something other than what I had actually said. Continue reading

Posted in Kynetx | Leave a comment

Day 20 – Datasets and Datasources – Remembering Which To Use

I have always had a hard time remembering which to use when it comes time to query external data in my Kynetx apps. Continue reading

Posted in Kynetx | Leave a comment

Day 19 – Regular Expression Matching In KRL

Sometimes in apps you want to check to see if a string is found in some text and react accordingly. Continue reading

Posted in Kynetx | Leave a comment