API Docs for:
Show:

File: models/client/Comment.js

"use strict";
var Promise = require("bluebird");
var _ = require("lodash");
var marked = require("marked");

var Base = require("./Base");
var UpdateMixin = require("./UpdateMixin");
var Attachment = require("./Attachment");

/**
 * Client Comment model
 *
 * @namespace models.client
 * @class Comment
 * @extends models.client.Base
 * @uses models.TicketMixin
 * @uses models.client.UpdateMixin
 */
var Comment = Base.extend({

    _htmlCache: null,

    defaults: function() {
        return {
            type: "comments",
            createdAt: new Date().toString(),
            comment: "",
            merged: []
        };
    },

    url: function() {
        return this.parent.url() + "/comments";
    },

    /**
     * Convert comment string to a HTML string assuming it is a Markdown string
     *
     * @method toHTML
     * @return {String}
     */
    toHTML: function(){
        // Because our client side models are immutable we can safely cache
        // this per model forever. i.e. the comment string will never change
        // during the lifetime of this model.
        if (this._htmlCache) return this._htmlCache;
        this._htmlCache = toMd(this.get("comment"));
        return this._htmlCache;
    },

    /**
     * Return comments that are merged to this comment using Comment#merge(...)
     *
     * @method getMergedComments
     * @return {Array} of models.client.Comment
     */
    getMergedComments: function() {
        var self = this;
        return this.get("merged").map(function(data) {
            return new Comment(data, { parent: self.parent });
        });
    },

    /**
     * @method ticket
     * @return {models.client.Ticket}
     */
    ticket: function() {
        var Ticket = require("./Ticket");
        return new Ticket(this.rel("ticket"));
    },

    /**
     * @method hasAttachments
     * @return {Boolean}
     */
    hasAttachments: function(){
        var a = this.get("attachments");
        return a && a.length > 0;
    },


    /**
     * @method attachments
     * @return {Array} of models.client.Attachment
     */
    attachments: function() {
        var self = this;
        return this.rel("attachments").map(function(data) {
            return new Attachment(data, { parent: self });
        });
    },


    /**
     * @method addAttachments
     * @param {Array} files Array of HTML5 file objects
     * @param {Function} progressHandler Called multiple times during the upload progress
     * @param {Object} [options}
     * @param {Function} [options.onProgress] Called periodically when the upload progresses
     * @return {Bluebird.Promise}
     */
    addAttachments: function(files, options) {
        var ticketId = this.parent.get("id");
        var commentId = this.get("id");
        var url = "/api/tickets/" + ticketId +
            "/comments/" + commentId + "/attachments";

        return new Promise(function(resolve, reject){
            // XXX https://github.com/francois2metz/html5-formdata
            var formData = new FormData();
            files.forEach(function(file, i) {
                formData.append("file" + i, file);
            });

            var xhr = new XMLHttpRequest();
            xhr.onload = resolve;
            xhr.onerror = reject;
            xhr.upload.addEventListener("progress", function(e) {
                 if (!e.lengthComputable) return;
                 if (!options) return;
                 if (typeof options.onProgress !== "function") return;
                 var percentage = Math.round((e.loaded * 100) / e.total);
                 console.log("Uploaded", percentage, e.loaded, "/", e.total);
                 options.onProgress({
                     percentage: percentage,
                     loaded: e.loaded,
                     total: e.total,
                     originalEvent: e
                 });
            });

            xhr.open("POST", url, true);
            xhr.send(formData);
        });

    },

    /**
     * Merge two comments to new one
     *
     * @method merge
     * @param {models.client.Comment} another
     * @return {models.client.Comment}
     */
    merge: function(another){
        if (this.get("createdById") !== another.get("createdById")) {
            throw new Error("Can merge comments only from the same creator");
        }

        var data = this.toJSON();
        data.merged = data.merged.concat(another.toJSON());

        // Use the last timestamp for the whole merged comment
        data.createdAt = another.get("createdAt");
        return new Comment(data, { parent: this.parent });
    }

});

/**
 * Convert Markdown string to HTML
 *
 * @static
 * @method toMd
 * @param {String} s
 * @return {String}
 */
function toMd(s) {
    // Configure options here
    // https://github.com/chjj/marked
    return marked(s);
}

_.extend(Comment.prototype, UpdateMixin);

module.exports = Comment;