1 //
  2 // The Antville Project
  3 // http://code.google.com/p/antville
  4 //
  5 // Copyright 2001-2007 by The Antville People
  6 //
  7 // Licensed under the Apache License, Version 2.0 (the ``License'');
  8 // you may not use this file except in compliance with the License.
  9 // You may obtain a copy of the License at
 10 //
 11 //    http://www.apache.org/licenses/LICENSE-2.0
 12 //
 13 // Unless required by applicable law or agreed to in writing, software
 14 // distributed under the License is distributed on an ``AS IS'' BASIS,
 15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16 // See the License for the specific language governing permissions and
 17 // limitations under the License.
 18 //
 19 // $Revision$
 20 // $LastChangedBy$
 21 // $LastChangedDate$
 22 // $URL$
 23 //
 24 
 25 /**
 26  * @fileOverview Defines the Comment prototype.
 27  */
 28 
 29 /**
 30  * @see defineConstants
 31  */
 32 Comment.getStatus = defineConstants(Comment, "closed", 
 33       "pending", "readonly", "public");
 34 
 35 /**
 36  * @returns {String}
 37  */
 38 Comment.remove = function(options) {
 39    if (this.constructor !== Comment) {
 40       return;
 41    }
 42    if (options && options.mode === "user" && options.confirm === "1") {
 43       var sql = new Sql;
 44       sql.retrieve("select id from content where site_id = $0 and creator_id = $1 \
 45             and prototype = 'Comment'", this.site._id, this.creator._id);
 46       sql.traverse(function() {
 47          Comment.remove.call(Comment.getById(this.id));
 48       });
 49    } else {
 50       while (this.size() > 0) {
 51          Comment.remove.call(this.get(0));
 52       }
 53       // Explicitely remove comment from aggressively cached collections:
 54       (this.parent || this).removeChild(this);
 55       this.story.comments.removeChild(this);
 56       this.remove();
 57    }
 58    return this.parent.href();
 59 }
 60 
 61 /**
 62  * @name Comment
 63  * @constructor
 64  * @param {Object} parent
 65  * @property {Comment[]} _children
 66  * @property {String} name
 67  * @property {Story|Comment} parent
 68  * @property {Story} story
 69  * @extends Story
 70  */
 71 Comment.prototype.constructor = function(parent) {
 72    this.name = String.EMPTY;
 73    this.site = parent.site;
 74    this.story = parent.story || parent;
 75    this.parent = parent;
 76    // FIXME: Correct parent_type (Helma bug?)
 77    this.parent_type = parent._prototype;
 78    this.status = Story.PUBLIC;
 79    this.creator = this.modifier = session.user;
 80    this.created = this.modified = new Date;
 81    return this;
 82 }
 83 
 84 /**
 85  * 
 86  * @param {Object} action
 87  * @returns {Boolean}
 88  */
 89 Comment.prototype.getPermission = function(action) {
 90    switch (action) {
 91       case ".":
 92       case "main":
 93       case "comment":
 94       // FIXME: temporary fix for lost stories due to shrunk database
 95       if (!this.story) {
 96          return false;
 97       }
 98       return this.site.commentMode === Site.ENABLED &&
 99             this.story.getPermission(action) && 
100             this.status !== Comment.CLOSED &&
101             this.status !== Comment.PENDING;
102       case "delete":
103       case "edit":
104       return this.story.getPermission.call(this, "delete");
105    }
106    return false;
107 }
108 
109 /**
110  * 
111  * @param {Object} action
112  * @returns {String}
113  */
114 Comment.prototype.href = function(action) {
115    var buffer = [];
116    switch (action) {
117       case null:
118       case undefined:
119       case "":
120       case ".":
121       case "main":
122       buffer.push(this.story.href(), "#", this._id);
123       break;
124       default:
125       buffer.push(this.story.comments.href(), this._id, "/", action);
126    }
127    return buffer.join(String.EMPTY);
128 }
129 
130 Comment.prototype.edit_action = function() {
131    if (req.postParams.save) {
132       try {
133          this.update(req.postParams);
134          delete session.data.backup;
135          res.message = gettext("The comment was successfully updated.");;
136          res.redirect(this.story.href() + "#" + this._id);
137       } catch (ex) {
138          res.message = ex;
139          app.log(ex);
140       }
141    }
142    
143    res.handlers.parent = this.parent;
144    res.data.action = this.href(req.action);
145    res.data.title = gettext("Edit Comment");
146    res.data.body = this.renderSkinAsString("Comment#edit");
147    this.site.renderSkin("Site#page");
148    return;
149 }
150 
151 /**
152  * 
153  * @param {Object} data
154  */
155 Comment.prototype.update = function(data) {
156    if (!data.title && !data.text) {
157       throw Error(gettext("Please enter at least something into the “title” or “text” field."));
158    }
159    // Get difference to current content before applying changes
160    var delta = this.getDelta(data);
161    this.title = data.title;
162    this.text = data.text;
163    this.setMetadata(data);
164 
165    if (this.story.commentMode === Story.MODERATED) {
166       this.mode = Comment.PENDING;
167    } else if (delta > 50) {
168       this.modified = new Date;
169       if (this.story.status !== Story.CLOSED) { 
170          this.site.modified = this.modified;
171       }
172       // We need persistence for adding the callback
173       this.isTransient() && this.persist();
174       res.handlers.site.callback(this);
175       // Notification is sent in Story.comment_action()
176    }
177    this.clearCache();
178    this.modifier = session.user;
179    return;
180 }
181 
182 /**
183  * 
184  * @param {String} name
185  * @returns {HopObject} 
186  */
187 Comment.prototype.getMacroHandler = function(name) {
188    if (name === "related") {
189       return this.creator.comments;
190    }
191    return null;
192 }
193