// (anonymous) [javascript]
    return this.each(function () {
      // get current object
      var $this = $(this)

      // add wrapper and tooltip
      $this.html('<span>' + utils.string.htmlEncode($this.text()) + '</span><span style="display: none;" class="inlineEditTooltip label label-primary">' + options.tooltip + '</span>')

      // grab element
      var $span = $this.find('span')
      var element = $span.eq(0)
      var tooltip = $span.eq(1)

      // bind events
      element.bind('click focus', createElement)

      tooltip.bind('click', createElement)

      $this.hover(
        function () {
          if (element.hasClass('inlineEditing')) {
            $this.removeClass('inlineEditHover')
            tooltip.hide()
          } else {
            $this.addClass('inlineEditHover')
            tooltip.show()
          }
        },
        function () {
          $this.removeClass('inlineEditHover')
          tooltip.hide()
        }
      )

      // create an element
      function createElement () {
        // already editing
        if (editing) return

        // set var
        editing = true

        // grab current value
        options.current.value = element.html()

        // get current object
        var $this = $(this)

        // grab extra params
        if ($this.parent().data('id') !== '') {
          var extraParams = JSON.parse($this.parent().data('id').replace(/'/g, '"'))
          options.current.extraParams = extraParams
        }

        // add class
        element.addClass('inlineEditing')

        // hide label
        $this.removeClass('inlineEditHover')
        tooltip.hide()

        // remove events
        element.unbind('click').unbind('focus')

        // replacing quotes, less than and greater than with htmlentity, otherwise the inputfield is 'broken'
        options.current.value = utils.string.replaceAll(options.current.value, '"', '&quot;')

        // set html
        element.html('<input type="text" class="' + options.inputClasses + '" value="' + options.current.value + '" />')

        // store element
        options.current.element = $(element.find('input')[0])

        // set focus
        options.current.element.select()

        // bind events
        options.current.element.bind('blur', saveElement)
        options.current.element.keyup(function (e) {
          // handle escape
          if (e.which === 27) {
            // reset
            options.current.element.val(options.current.value)

            // destroy
            destroyElement()
          }

          // save when someone presses enter
          if (e.which === 13) saveElement()
        })
      }

      // destroy the element
      function destroyElement () {
        // get parent
        var parent = options.current.element.parent()

        // get value and replace quotes, less than and greater than with their htmlentities
        var newValue = options.current.element.val()
        newValue = utils.string.replaceAll(newValue, '"', '&quot;')
        newValue = utils.string.replaceAll(newValue, '<', '&lt;')
        newValue = utils.string.replaceAll(newValue, '>', '&gt;')

        // set HTML and rebind events
        parent.html(newValue).bind('click focus', createElement)

        // add class
        parent.removeClass('inlineEditing')

        // restore
        editing = false
      }

      // save the element
      function saveElement () {
        // if the new value is empty and that isn't allowed, we restore the original value
        if (!options.allowEmpty && options.current.element.val() === '') {
          options.current.element.val(options.current.value)
        }

        // is the value different from the original value
        if (options.current.element.val() !== options.current.value) {
          // add element to the params
          options.current.extraParams['value'] = options.current.element.val()

          // make the call
          $.ajax(
            {
              data: $.extend(options.params, options.current.extraParams),
              success: function (data, textStatus) {
                // call callback if it is a valid callback
                if (typeof options.afterSave === 'function') options.afterSave($this)

                // destroy the element
                destroyElement()
              },
              error: function (XMLHttpRequest, textStatus, errorThrown) {
                // reset
                options.current.element.val(options.current.value)

                // destroy the element
                destroyElement()

                // show message
                jsBackend.messages.add('danger', $.parseJSON(XMLHttpRequest.responseText).message)
              }
            })
        } else {
          // destroy the element
          destroyElement()
        }
      }
    })
  }