class OperationView extends Backbone.View invocationUrl: null events: { 'submit .sandbox' : 'submitOperation' 'click .submit' : 'submitOperation' 'click .response_hider' : 'hideResponse' 'click .toggleOperation' : 'toggleOperationContent' 'mouseenter .api-ic' : 'mouseEnter' 'mouseout .api-ic' : 'mouseExit' } initialize: -> mouseEnter: (e) -> elem = $(e.currentTarget.parentNode).find('#api_information_panel') x = e.pageX y = e.pageY scX = $(window).scrollLeft() scY = $(window).scrollTop() scMaxX = scX + $(window).width() scMaxY = scY + $(window).height() wd = elem.width() hgh = elem.height() if (x + wd > scMaxX) x = scMaxX - wd if (x < scX) x = scX if (y + hgh > scMaxY) y = scMaxY - hgh if (y < scY) y = scY pos = {} pos.top = y pos.left = x elem.css(pos) $(e.currentTarget.parentNode).find('#api_information_panel').show() mouseExit: (e) -> $(e.currentTarget.parentNode).find('#api_information_panel').hide() render: -> isMethodSubmissionSupported = true #jQuery.inArray(@model.method, @model.supportedSubmitMethods) >= 0 @model.isReadOnly = true unless isMethodSubmissionSupported # 1.2 syntax for description was `notes` @model.description = (@model.description || @model.notes) if @model.description @model.description = @model.description.replace(/(?:\r\n|\r|\n)/g, '
') @model.oauth = null if @model.authorizations for k, v of @model.authorizations if k == "oauth2" if @model.oauth == null @model.oauth = {} if @model.oauth.scopes is undefined @model.oauth.scopes = [] for o in v @model.oauth.scopes.push o if typeof @model.responses isnt 'undefined' @model.responseMessages = [] for code, value of @model.responses schema = null schemaObj = @model.responses[code].schema if schemaObj and schemaObj['$ref'] schema = schemaObj['$ref'] if schema.indexOf('#/definitions/') is 0 schema = schema.substring('#/definitions/'.length) @model.responseMessages.push {code: code, message: value.description, responseModel: schema } if typeof @model.responseMessages is 'undefined' @model.responseMessages = [] $(@el).html(Handlebars.templates.operation(@model)) if @model.responseClassSignature and @model.responseClassSignature != 'string' signatureModel = sampleJSON: @model.responseSampleJSON isParam: false signature: @model.responseClassSignature responseSignatureView = new SignatureView({model: signatureModel, tagName: 'div'}) $('.model-signature', $(@el)).append responseSignatureView.render().el else @model.responseClassSignature = 'string' $('.model-signature', $(@el)).html(@model.type) contentTypeModel = isParam: false contentTypeModel.consumes = @model.consumes contentTypeModel.produces = @model.produces for param in @model.parameters type = param.type || param.dataType if typeof type is 'undefined' schema = param.schema if schema and schema['$ref'] ref = schema['$ref'] if ref.indexOf('#/definitions/') is 0 type = ref.substring('#/definitions/'.length) else type = ref if type and type.toLowerCase() == 'file' if !contentTypeModel.consumes contentTypeModel.consumes = 'multipart/form-data' param.type = type responseContentTypeView = new ResponseContentTypeView({model: contentTypeModel}) $('.response-content-type', $(@el)).append responseContentTypeView.render().el # Render each parameter @addParameter param, contentTypeModel.consumes for param in @model.parameters # Render each response code @addStatusCode statusCode for statusCode in @model.responseMessages @ addParameter: (param, consumes) -> # Render a parameter param.consumes = consumes paramView = new ParameterView({model: param, tagName: 'tr', readOnly: @model.isReadOnly}) $('.operation-params', $(@el)).append paramView.render().el addStatusCode: (statusCode) -> # Render status codes statusCodeView = new StatusCodeView({model: statusCode, tagName: 'tr'}) $('.operation-status', $(@el)).append statusCodeView.render().el submitOperation: (e) -> e?.preventDefault() # Check for errors form = $('.sandbox', $(@el)) error_free = true form.find("input.required").each -> $(@).removeClass "error" if jQuery.trim($(@).val()) is "" $(@).addClass "error" $(@).wiggle callback: => $(@).focus() error_free = false # if error free submit it if error_free map = {} opts = {parent: @} isFileUpload = false for o in form.find("input") if(o.value? && jQuery.trim(o.value).length > 0) map[o.name] = o.value if o.type is "file" isFileUpload = true for o in form.find("textarea") if(o.value? && jQuery.trim(o.value).length > 0) map["body"] = o.value for o in form.find("select") val = this.getSelectedValue o if(val? && jQuery.trim(val).length > 0) map[o.name] = val opts.responseContentType = $("div select[name=responseContentType]", $(@el)).val() opts.requestContentType = $("div select[name=parameterContentType]", $(@el)).val() $(".response_throbber", $(@el)).show() if isFileUpload @handleFileUpload map, form else @model.do(map, opts, @showCompleteStatus, @showErrorStatus, @) success: (response, parent) -> parent.showCompleteStatus response handleFileUpload: (map, form) -> for o in form.serializeArray() if(o.value? && jQuery.trim(o.value).length > 0) map[o.name] = o.value # requires HTML5 compatible browser bodyParam = new FormData() params = 0 # add params for param in @model.parameters if param.paramType is 'form' if param.type.toLowerCase() isnt 'file' and map[param.name] != undefined bodyParam.append(param.name, map[param.name]) # headers in operation headerParams = {} for param in @model.parameters if param.paramType is 'header' headerParams[param.name] = map[param.name] # add files for el in form.find('input[type~="file"]') if typeof el.files[0] isnt 'undefined' bodyParam.append($(el).attr('name'), el.files[0]) params += 1 @invocationUrl = if @model.supportHeaderParams() headerParams = @model.getHeaderParams(map) @model.urlify(map, false) else @model.urlify(map, true) $(".request_url", $(@el)).html("
") 
    $(".request_url pre", $(@el)).text(@invocationUrl);
    
    obj = 
      type: @model.method
      url: @invocationUrl
      headers: headerParams
      data: bodyParam
      dataType: 'json'
      contentType: false
      processData: false
      error: (data, textStatus, error) =>
        @showErrorStatus(@wrap(data), @)
      success: (data) =>
        @showResponse(data, @)
      complete: (data) =>
        @showCompleteStatus(@wrap(data), @)

    # apply authorizations
    if window.authorizations
      window.authorizations.apply obj

    if params is 0
      obj.data.append("fake", "true");

    jQuery.ajax(obj)
    false
    # end of file-upload nastiness

  # wraps a jquery response as a shred response

  wrap: (data) ->
    headers = {}
    headerArray = data.getAllResponseHeaders().split("\r")
    for i in headerArray
      h = i.split(':')
      if (h[0] != undefined && h[1] != undefined)
        headers[h[0].trim()] = h[1].trim()

    o = {}
    o.content = {}
    o.content.data = data.responseText
    o.headers = headers
    o.request = {}
    o.request.url = @invocationUrl
    o.status = data.status
    o

  getSelectedValue: (select) ->
    if !select.multiple 
      select.value
    else
      options = []
      options.push opt.value for opt in select.options when opt.selected
      if options.length > 0 
        options
      else
        null

  # handler for hide response link
  hideResponse: (e) ->
    e?.preventDefault()
    $(".response", $(@el)).slideUp()
    $(".response_hider", $(@el)).fadeOut()


  # Show response from server
  showResponse: (response) ->
    prettyJson = JSON.stringify(response, null, "\t").replace(/\n/g, "
") $(".response_body", $(@el)).html escape(prettyJson) # Show error from server showErrorStatus: (data, parent) -> parent.showStatus data # show the status codes showCompleteStatus: (data, parent) -> parent.showStatus data # Adapted from http://stackoverflow.com/a/2893259/454004 formatXml: (xml) -> reg = /(>)(<)(\/*)/g wsexp = /[ ]*(.*)[ ]+\n/g contexp = /(<.+>)(.+\n)/g xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2') pad = 0 formatted = '' lines = xml.split('\n') indent = 0 lastType = 'other' # 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions transitions = 'single->single': 0 'single->closing': -1 'single->opening': 0 'single->other': 0 'closing->single': 0 'closing->closing': -1 'closing->opening': 0 'closing->other': 0 'opening->single': 1 'opening->closing': 0 'opening->opening': 1 'opening->other': 1 'other->single': 0 'other->closing': -1 'other->opening': 0 'other->other': 0 for ln in lines do (ln) -> types = # is this line a single tag? ex.
single: Boolean(ln.match(/<.+\/>/)) # is this a closing tag? ex. closing: Boolean(ln.match(/<\/.+>/)) # is this even a tag (that's not ) opening: Boolean(ln.match(/<[^!?].*>/)) [type] = (key for key, value of types when value) type = if type is undefined then 'other' else type fromTo = lastType + '->' + type lastType = type padding = '' indent += transitions[fromTo] padding = (' ' for j in [0...(indent)]).join('') if fromTo == 'opening->closing' #substr removes line break (\n) from prev loop formatted = formatted.substr(0, formatted.length - 1) + ln + '\n' else formatted += padding + ln + '\n' formatted # puts the response data in UI showStatus: (response) -> if response.content is undefined content = response.data url = response.url else content = response.content.data url = response.request.url headers = response.headers # if server is nice, and sends content-type back, we can use it contentType = if headers && headers["Content-Type"] then headers["Content-Type"].split(";")[0].trim() else null if !content code = $('').text("no content") pre = $('
').append(code)
    else if contentType is "application/json" || /\+json$/.test(contentType)
      json = null
      try
        json = JSON.stringify(JSON.parse(content), null, "  ")
      catch e
        json = "can't parse JSON.  Raw result:\n\n" + content
      code = $('').text(json)
      pre = $('
').append(code)
    else if contentType is "application/xml" || /\+xml$/.test(contentType)
      code = $('').text(@formatXml(content))
      pre = $('
').append(code)
    else if contentType is "text/html"
      code = $('').html(_.escape(content))
      pre = $('
').append(code)
    else if /^image\//.test(contentType)
      pre = $('').attr('src',url)
    else
      # don't know what to render!
      code = $('').text(content)
      pre = $('
').append(code)

    response_body = pre
    $(".request_url", $(@el)).html("
") 
    $(".request_url pre", $(@el)).text(url);
    $(".response_code", $(@el)).html "
" + response.status + "
" $(".response_body", $(@el)).html response_body $(".response_headers", $(@el)).html "
" + _.escape(JSON.stringify(response.headers, null, "  ")).replace(/\n/g, "
") + "
" $(".response", $(@el)).slideDown() $(".response_hider", $(@el)).show() $(".response_throbber", $(@el)).hide() response_body_el = $('.response_body', $(@el))[0] # only highlight the response if response is less than threshold, default state is highlight response opts = @options.swaggerOptions if opts.highlightSizeThreshold && response.data.length > opts.highlightSizeThreshold then response_body_el else hljs.highlightBlock(response_body_el) toggleOperationContent: -> elem = $('#' + Docs.escapeResourceName(@model.parentId) + "_" + @model.nickname + "_content") if elem.is(':visible') then Docs.collapseOperation(elem) else Docs.expandOperation(elem)