Facebook share buttons and history.pushState()

If you’ve ever tried to use Facebook social plugins‘ latest version in your website, you might have noticed how smooth and streamlined is now the embedding process.

Select a button type, include the SDK, copy-paste a snippet of code and… you’re done! You can also leave the data-href attribute blank, so the plugin will like/share the current page. Awesome!

At this point you might ask yourself, “Well, will this nice little button work with my super cool AJAX-powered app?”. The answer is not really.

The problem

Facebook social plugins won’t work properly when your application routing is based on Javascript’s history.pushState() API – this includes a large number of Rails applications that rely on Turbolinks for their navigation.

This is because the page metadata is parsed by Facebook SDK only when a full page load is triggered. So, if I navigate from example.com/page-one to example.com/page-two and try to click on my Facebook share button, it will prompt a share for /page-one.

The solution

How to solve this? It’s actually quite easy. A small snippet (here in CoffeeScript, but easily convertible in plain JavaScript) that will update our button and retrigger a parse will be enough:

updateFbButtonHref = (el) ->
  $fbButton = $(el).find('.fb-share-button')
  $fbButton.attr('data-href', window.location.href)

  FB.XFBML.parse()

Now, we can bind this function to the “page:load” event (in the case of a Turbolinks application), or generally after every pushState():


$(document).on 'page:load', ->
  updateFbButtonHref('.my-fb-button-container')

And we’re cool! Our button will now share the correct page.

Web Procedural Map Generation – Part 2

In my previous post I created a heightmap and I started looking for a map representation system different from the tilemap.

But a tilemap, composed of square tiles, probably is not the best tool for the job: it would require a lot of tiles to obtain a nice looking result and probably we would suffer from pixeling. A better approach is to use polygons with a larger number of sides such as hexagons.
Continue reading “Web Procedural Map Generation – Part 2”

Replicating the deprecated jQuery property .selector in CoffeeScript

Recently I found myself needing a way to get any (id or class) selector from any DOM element as a string in an easy way. 

After a quick search I discovered that jQuery had an handy .selector property that would have been a perfect fit for my needs.

Unluckily, it was deprecated in version 1.7.

image

I felt like the solution suggested by the guys at jQuery wasn’t flexible enough and not very user-friendly – passing the element selector as a parameter of the plugin method call is definitely not an elegant way to deal with the problem.

So I tried to write a simple function to solve it… in CoffeeScript!

The snippet

getSelector = (el) ->
  firstClass = $(el).attr('class')?.split(' ')[0]
  elId       = $(el).attr('id')

  if (elId isnt undefined) then "##{elId}" else ".#{firstClass}"

As you can see, it’s really easy to understand: it just checks if there’s an id attribute and returns it as a string. If it’s undefined, it returns the first class instead.

Here you can see it in action in a CodePen example.

I could write it in a single line without the two variables declaration, but I wanted to get the most out of the beautiful human-friendly CoffeeScript syntax, and I think it actually makes the snippet a lot more readable.

More jQuery pls

If you wanted to, you could also extend jQuery itself adding this little function as a method in a very easy way:

jQuery.fn.extend(
  getSelector: ->
    firstClass = $(this).attr('class')?.split(' ')[0]
    elId       = $(this).attr('id')

    if (elId isnt undefined) then "##{elId}" else ".#{firstClass}"
)

And then use it like that:


$ ->
  mySelector = $('div').getSelector()

Hope that helped you!

Web Procedural Map Generation – Part 1

Two weeks ago I started playing with map generation algorithms.

I wanted to come up with a map generator (and eventually a climatic environment simulator) using javascript coffeescript because it’s really easy to prototype something and my goal was to learn to do something, not to really do something (so, when talking of “map generation” there is really no need to add obstacles to the quest like OpenGL, strictly typed languages, and so on).
Continue reading “Web Procedural Map Generation – Part 1”

“Use Node.js FOR SPEED” — @RoflscaleTips

I obeyed, therefore I wrote an opal NPM package.

Now I can trash Rails and opal-rails and start working on Node only!

server = Server.new 3000
server.start do
  [200, {'Content-Type' => 'text/plain'}, ["Hello World!n"]]
end

For it I had to write the Server class:

class Server
  def initialize port
    @http = `require('http')`
    @port = port
  end

  def start &block
    %x{
      this.http.createServer(function(req, res) {
        var rackResponse = (block.call(block._s, req, res));
        res.end(rackResponse[2].join(' '));
      }).listen(this.port);
    }
  end
end

Put them in app.opal and then start the server:

$ npm install -g opal      # <<< install the NPM package first!
$ opal-node app

The running app

YAY! now I can roflSCALE all of my RAils apps!!1

Cross posted from Eliæ

Stop writing JavaScript and get back to Ruby!

Cross posted from: Eliæ

Remeber that feeling that you had after having tried CoffeeScript getting back to a project with plain JavaScript and felt so constricted?

Well, after re-writing a couple of coffee classes with OpalRuby I felt exactly that way, and with 14.9KB of footprint (min+gz, jQuery is 32KB) is a complete no brainer.

So let’s gobble up our first chunk of code, that will salute from the browser console:

puts 'hi buddies!'

You wonder how that gets translated?

Fear that it will look like this?

'egin',cb='bootstrap',u='clear.cache.gif',z='content',bc='end',lb='gecko',mb='g
cko1_8',yb='gwt.hybrid',xb='gwt/standard/standard.css',E='gwt:onLoadErrorFn',B=
'gwt:onPropertyErrorFn',y='gwt:property',Db='head',qb='hosted.html?hello',Cb='h
ref',kb='ie6',ab='iframe',t='img',bb="javascript:''",zb='link',pb='loadExternal
Refs',v='meta',eb='moduleRequested',ac='moduleStartup',jb='msie',w='name',gb='o
pera',db='position:absolute;width:0;height:0;border:none',Ab='rel',ib='safari',
rb='selectingPermutation',x='startup',m='hello',Bb='stylesheet',ob='unknown',fb
='user.agent',hb='webkit';var fc=window,k=document,ec=fc.__gwtStatsEvent?functi
on(a){return fc.__gwtStatsEvent(a)}:null,zc,pc,kc,jc=l,sc={},Cc=[],yc=[],ic=[],
vc,xc;ec&&ec({moduleName:m,subSystem:x,evtGroup:cb,millis:(new Date()).getTime(
),type:nb});if(!fc.__gwt_stylesLoaded){fc.__gwt_stylesLoaded={}}if(!fc.__gwt_sc
riptsLoaded){fc.__gwt_scriptsLoaded={}}function oc(){var b=false;try{b=fc.exter

Nope! it’s Chuck Testa

(function() {
  return this.$puts("hi buddies!")
}).call(Opal.top);

But it will be obviously a mess to integrate it with existing javascript!!1

Let’s how to add #next and #prev to the Element class:

class Element
  def next(selector = '')
    element = nil
    `element = jQuery(this.el).next(selector)[0] || nil;`
    Element.new element if element
  end
end

But I’m on Rails!

Here you served:

gem 'opal-rails'

Which il provide you a requirable libraries for application.js

//= require opal
//= require rquery

and the .opal extension for your files

# app/assets/javascripts/hi-world.js.opal

puts "G'day world!"

A template handler:

# app/views/posts/show.js.opal.erb

Element.id('<%= dom_id @post %>').show

and a Haml filter!

-# app/views/posts/show.html.haml

%article= post.body

%a#show-comments Display Comments!

.comments(style="display:none;")
  - post.comments.each do |comment|
    .comment= comment.body

:opal
  Document.ready? do
    Element.id('show-comments').on :click do
      Element.find('.comments').first.show
      false # aka preventDefault
    end
  end