Search code examples
jquerycoffeescriptextend

How can I extend jQuery in Coffeescript so I append the Coffeescript class with jQuery?


What I want to do is append a Circle in main like this: stage.append circle. I thought that Circle extends jQuery would be good solution, but that doesn't seem to work.

My current code:

Circle.coffee:

define [], () ->
  class Circle
    constructor: (@x, @y, @radius) ->
      @circle = $ document.createElement "div"
      @circle.addClass "circle"
      @circle.width @radius * 2
      @circle.height @radius * 2
      @circle.css
        left: @x
        top: @y

Main.coffee:

define [
  'object/Circle'
], (Circle) ->

  stage = $ "#main"

  circle = new Circle 350, 350, 100
  stage.append circle.circle 

Solution

  • It is possible to do this. You have to take two cases into account. The first case is where the selector is a string pointing to an existing object in the DOM. The second case is where the selector is pointing to a 'new' element or when the selector is pointing to another object.

    For the first case you need to copy a newly created jQuery object into the instance. This in order to give jQuery a chance to search the DOM. The easiest way to check for this is to check if selector is a string and not an HTML tag. This method is probably not thorough enough, but for basic usage it works.

    For the second case you can call init with the this as the first parameter. This will create a new jQuery object around the current instance.

    class Element extends jQuery
      constructor: (selector, context) ->
        # When selector is a string and not an html tag:
        # body, #my-id, .error-class etc.
        if typeof selector is 'string' and not selector.match /^<.*>$/
          jQuery.extend true, this, jQuery.fn.init(selector, context, jQuery document)
    
        # When selector is a jQuery object
        else if selector instanceof jQuery
          jQuery.extend true, this, selector
    
        else
          # When selector points to an object which doesn't exist in the DOM:
          # <div>, document.createElement('span')
          # Or when selector is an object
          jQuery.fn.init.call this, selector, context
    
        @constructor = jQuery
    

    Now you can extend Element to create all kinds of custom elements.

    class Square extends Element
      constructor: (size) ->
        super(document.createElement('div')) # Square is a div with no parent
        @width size
        @height size
        @css 'background', 'repeating-linear-gradient(45deg, blue, blue 15px, green 15px, green 30px)'
    

    And use Element like $

    new Element('body').append(new Square())