├── LICENSE.txt ├── README.md ├── css ├── images │ ├── ui-anim_basic_16x16.gif │ └── user_blank_picture.png └── jquery.comment.css ├── demo ├── articles │ └── id │ │ └── 1 │ │ └── comments │ │ └── list └── index.html └── js ├── jquery.autogrow-textarea.js ├── jquery.comment.js └── jquery.timeago.js /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012 Hendrayana 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [jquery-comment](http://henyana.github.io/jquery-comment) 2 | 3 | It's jquery plugin for nested Comments like the [http://disqus.com](disqus). It's using ajax request and json data as the feeds. 4 | 5 | ## Quick start 6 | 7 | Two quick start options are available: 8 | 9 | * [Download the latest release](https://github.com/henyana/jquery-comment/zipball/master). 10 | * Clone the repo: `git clone git://github.com/henyana/jquery-comment.git`. 11 | 12 | ## Documentation 13 | 14 | [http://henyana.github.io/jquery-comment](http://henyana.github.io/jquery-comment) 15 | 16 | ## Demo 17 | 18 | [http://henyana.github.io/jquery-comment/demo](http://henyana.github.io/jquery-comment/demo) 19 | 20 | ## Authors 21 | 22 | **Hendrayana** 23 | 24 | + [http://twitter.com/h3ny4n4](http://twitter.com/h3ny4n4) 25 | + [http://github.com/henyana](http://github.com/henyana) 26 | -------------------------------------------------------------------------------- /css/images/ui-anim_basic_16x16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henyana/jquery-comment/d2f02ede0f1aaf834f84b5d0de1912b4d4f4b24d/css/images/ui-anim_basic_16x16.gif -------------------------------------------------------------------------------- /css/images/user_blank_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henyana/jquery-comment/d2f02ede0f1aaf834f84b5d0de1912b4d4f4b24d/css/images/user_blank_picture.png -------------------------------------------------------------------------------- /css/jquery.comment.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Post-Comment Plugin v.1.0 3 | * created [2013-02-26 17:49 AM] 4 | * TODO: Documentation 5 | * 6 | * Copyright 2013, hendra@kunchy.com or henyana@gmail.com 7 | * http://www.abelware.com 8 | */ 9 | .clear{ 10 | clear: both; 11 | } 12 | 13 | .comments-display{ 14 | 15 | } 16 | 17 | .comments-display .dot{ 18 | padding: 0 3px; 19 | font-size: 75%; 20 | color: #CCC; 21 | line-height: 1.4; 22 | } 23 | 24 | .comments-display .in-reply-to{ 25 | display:inline-table; 26 | } 27 | 28 | .comments-display .in-reply-to .ui-icon{ 29 | height:12px; 30 | } 31 | 32 | .comments-display .comment-length{ 33 | font-weight:bold; 34 | padding-bottom:7px; 35 | } 36 | 37 | .comments-display .posted-comments-postbox { 38 | padding-top:3px; 39 | border-bottom:2px solid #F0F0F0; 40 | } 41 | 42 | ul.posted-comments { 43 | list-style: none; 44 | margin: 0; 45 | } 46 | 47 | ul.posted-comments li { 48 | padding:10px 0 0; 49 | border-top:1px solid #F0F0F0; 50 | } 51 | 52 | .avatar img{ 53 | width:28px; 54 | height:28px; 55 | } 56 | 57 | .posted-comments-postbox .avatar{ 58 | 59 | } 60 | 61 | .posted-comments-postbox .form{ 62 | margin-left: 10px; 63 | min-width: 85%; 64 | } 65 | 66 | .posted-comments-postbox textarea, .posted-comment-form-edit textarea{ 67 | min-width:98%; 68 | } 69 | 70 | .posted-comment-container{ 71 | margin-left: 10px; 72 | min-width:85%; 73 | } 74 | 75 | .posted-comment-container .posted-comment-head{ 76 | font-size:7pt; 77 | } 78 | 79 | .posted-comment-container .posted-comment-head .posted-comment-author{ 80 | font-weight:bold; 81 | } 82 | 83 | .posted-comment-container .posted-comment-foot{ 84 | font-size:7pt; 85 | color:#F0F0F0; 86 | } 87 | 88 | ul.posted-comment-childs{ 89 | list-style: none; 90 | margin-left:40px; 91 | padding-top:7px; 92 | } 93 | 94 | ul.posted-comment-childs .avatar img{ 95 | width:22px; 96 | height:22px; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /demo/articles/id/1/comments/list: -------------------------------------------------------------------------------- 1 | { 2 | "results": { 3 | "comments": [ 4 | { 5 | "comment_id": "1", 6 | "parent_id": "0", 7 | "in_reply_to": null, 8 | "element_id": "134", 9 | "created_by": "1", 10 | "fullname": "Administrator admin", 11 | "picture": "../css/images/user_blank_picture.png", 12 | "posted_date": "2013-02-27 09:03:25", 13 | "text": "Test message one", 14 | "attachments": [], 15 | "childrens": [ 16 | { 17 | "comment_id": "3", 18 | "parent_id": "1", 19 | "in_reply_to": "Administrator admin", 20 | "element_id": "134", 21 | "created_by": "2", 22 | "fullname": "Manager manager", 23 | "picture": "../css/images/user_blank_picture.png", 24 | "posted_date": "2013-02-27 08:48:50", 25 | "text": "Hi, reply for you", 26 | "attachments": [], 27 | "childrens": [] 28 | }, 29 | { 30 | "comment_id": "2", 31 | "parent_id": "1", 32 | "in_reply_to": "Administrator admin", 33 | "element_id": "134", 34 | "created_by": "1", 35 | "fullname": "Administrator admin", 36 | "picture": "../css/images/user_blank_picture.png", 37 | "posted_date": "2013-02-26 11:30:44", 38 | "text": "Test message level 2", 39 | "attachments": [], 40 | "childrens": [ 41 | { 42 | "comment_id": "4", 43 | "parent_id": "2", 44 | "in_reply_to": "Administrator admin", 45 | "element_id": "134", 46 | "created_by": "2", 47 | "fullname": "Manager manager", 48 | "picture": "../css/images/user_blank_picture.png", 49 | "posted_date": "2013-02-27 08:50:05", 50 | "text": "replied as level 3", 51 | "attachments": [], 52 | "childrens": [] 53 | } 54 | ] 55 | } 56 | ] 57 | } 58 | ], 59 | "total_comment": 4, 60 | "user": { 61 | "user_id": 1, 62 | "fullname": "Administrator admin", 63 | "picture": "../css/images/user_blank_picture.png", 64 | "is_logged_in": true, 65 | "is_add_allowed": true, 66 | "is_edit_allowed": true 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Jquery Comment Plugin 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | ARTICLE CONTENT HERE! 18 |
 19 | list: json
 20 | {
 21 |     "results": {
 22 |         "comments": [
 23 |             {
 24 |                 "comment_id": "1",
 25 |                 "parent_id": "0",
 26 |                 "in_reply_to": null,
 27 |                 "element_id": "134",
 28 |                 "created_by": "1",
 29 |                 "fullname": "Administrator admin",
 30 |                 "picture": "../css/images/user_blank_picture.png",
 31 |                 "posted_date": "2013-02-27 09:03:25",
 32 |                 "text": "Test message one",
 33 |                 "attachments": [],
 34 |                 "childrens": [
 35 |                     {
 36 |                         "comment_id": "3",
 37 |                         "parent_id": "1",
 38 |                         "in_reply_to": "Administrator admin",
 39 |                         "element_id": "134",
 40 |                         "created_by": "2",
 41 |                         "fullname": "Manager manager",
 42 |                         "picture": "../css/images/user_blank_picture.png",
 43 |                         "posted_date": "2013-02-27 08:48:50",
 44 |                         "text": "Hi, reply for you",
 45 |                         "attachments": [],
 46 |                         "childrens": []
 47 |                     },
 48 |                     {
 49 |                         "comment_id": "2",
 50 |                         "parent_id": "1",
 51 |                         "in_reply_to": "Administrator admin",
 52 |                         "element_id": "134",
 53 |                         "created_by": "1",
 54 |                         "fullname": "Administrator admin",
 55 |                         "picture": "../css/images/user_blank_picture.png",
 56 |                         "posted_date": "2013-02-26 11:30:44",
 57 |                         "text": "Test message level 2",
 58 |                         "attachments": [],
 59 |                         "childrens": [
 60 |                             {
 61 |                                 "comment_id": "4",
 62 |                                 "parent_id": "2",
 63 |                                 "in_reply_to": "Administrator admin",
 64 |                                 "element_id": "134",
 65 |                                 "created_by": "2",
 66 |                                 "fullname": "Manager manager",
 67 |                                 "picture": "../css/images/user_blank_picture.png",
 68 |                                 "posted_date": "2013-02-27 08:50:05",
 69 |                                 "text": "replied as level 3",
 70 |                                 "attachments": [],
 71 |                                 "childrens": []
 72 |                             }
 73 |                         ]
 74 |                     }
 75 |                 ]
 76 |             }
 77 |         ],
 78 |         "total_comment": 4,
 79 |         "user": {
 80 |             "user_id": 1,
 81 |             "fullname": "Administrator admin",
 82 |             "picture": "../css/images/user_blank_picture.png",
 83 |             "is_logged_in": true,
 84 |             "is_add_allowed": true,
 85 |             "is_edit_allowed": true
 86 |         }
 87 |     }
 88 | }					
 89 | 				
90 |
91 |
92 | 93 |
94 | 95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 124 | 125 | -------------------------------------------------------------------------------- /js/jquery.autogrow-textarea.js: -------------------------------------------------------------------------------- 1 | 2 | (function($) 3 | { 4 | /** 5 | * Auto-growing textareas; technique ripped from Facebook 6 | * 7 | * http://github.com/jaz303/jquery-grab-bag/tree/master/javascripts/jquery.autogrow-textarea.js 8 | */ 9 | $.fn.autogrow = function(options) 10 | { 11 | return this.filter('textarea').each(function() 12 | { 13 | var self = this; 14 | var $self = $(self); 15 | var minHeight = $self.height(); 16 | var noFlickerPad = $self.hasClass('autogrow-short') ? 0 : parseInt($self.css('lineHeight')); 17 | 18 | var shadow = $('
').css({ 19 | position: 'absolute', 20 | top: -10000, 21 | left: -10000, 22 | width: $self.width(), 23 | fontSize: $self.css('fontSize'), 24 | fontFamily: $self.css('fontFamily'), 25 | fontWeight: $self.css('fontWeight'), 26 | lineHeight: $self.css('lineHeight'), 27 | resize: 'none' 28 | }).appendTo(document.body); 29 | 30 | var update = function() 31 | { 32 | var times = function(string, number) 33 | { 34 | for (var i=0, r=''; i/g, '>') 40 | .replace(/&/g, '&') 41 | .replace(/\n$/, '
 ') 42 | .replace(/\n/g, '
') 43 | .replace(/ {2,}/g, function(space){ return times(' ', space.length - 1) + ' ' }); 44 | 45 | shadow.css('width', $self.width()); 46 | shadow.html(val); 47 | $self.css('height', Math.max(shadow.height() + noFlickerPad, minHeight)); 48 | } 49 | 50 | $self.change(update).keyup(update).keydown(update); 51 | $(window).resize(update); 52 | 53 | update(); 54 | }); 55 | }; 56 | })(jQuery); -------------------------------------------------------------------------------- /js/jquery.comment.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Post-Comment Plugin v.1.0 3 | * created [2013-02-26 17:49 AM] 4 | * TODO: Documentation 5 | * 6 | * Copyright 2013, hendra@kunchy.com or henyana@gmail.com 7 | * http://www.abelware.com 8 | */ 9 | 10 | // Utility 11 | if ( typeof Object.create !== 'function' ) { 12 | Object.create = function( obj ) { 13 | function F() {}; 14 | F.prototype = obj; 15 | return new F(); 16 | }; 17 | } 18 | 19 | (function($, window, document, undefined){ 20 | 21 | var Comment = { 22 | init_: function( options, elem ) { 23 | var self = this; 24 | 25 | self.elem = elem; 26 | self.$elem = $( elem ); 27 | 28 | self.options = $.extend( {}, $.fn.comment.options, options ); 29 | 30 | self.refresh_( 1 ); 31 | }, 32 | 33 | buildForm_: function(comment_id, parent_id){ 34 | var self = this; 35 | 36 | var form_elem = $('
'); 37 | 38 | if(comment_id!=null) 39 | form_elem.attr('action', self.options.url_input+'/'+comment_id); 40 | else 41 | form_elem.attr('action', self.options.url_input); 42 | 43 | form_elem.attr('method', 'post'); 44 | 45 | if(parent_id!=null) 46 | { 47 | var parent_id_field = $(''); 48 | parent_id_field.attr('type', 'hidden'); 49 | parent_id_field.attr('name', 'parent_id'); 50 | parent_id_field.val(parent_id); 51 | form_elem.append(parent_id_field); 52 | } 53 | 54 | var textarea = $(''); 55 | textarea.attr('name', 'text'); 56 | textarea.attr('placeHolder', 'Leave a message...'); 57 | textarea.css('overflow', 'hidden'); 58 | textarea.autogrow(); 59 | 60 | textarea.on('keypress', function(e){ 61 | e = e || event; 62 | if (e.keyCode === 13 && !e.shiftKey && $.trim(this.value).length>0) { 63 | e.preventDefault(); 64 | //form_elem.submit(); 65 | 66 | 67 | self.submitForm_(comment_id, form_elem.serialize()); 68 | } 69 | }); 70 | 71 | form_elem.append(textarea); 72 | 73 | return form_elem; 74 | }, 75 | 76 | submitForm_: function(comment_id, form_data){ 77 | var self = this; 78 | 79 | var url_input = self.options.url_input; 80 | 81 | if(comment_id!=null) // form edit mode 82 | url_input = self.options.url_input+'/'+comment_id; 83 | 84 | return $.ajax({ 85 | url: url_input, 86 | data: form_data, 87 | type: 'post', 88 | dataType: 'json', 89 | beforeSend: function(xhr, opts){ 90 | 91 | $('textarea', self.$elem).attr("disabled", true); 92 | 93 | } 94 | }).done( function(result){ 95 | 96 | if(result.success!=undefined) 97 | { 98 | if(result.success===false) 99 | { 100 | // error 101 | $.each(result, function(key, val){ 102 | // check error if any 103 | if(val.error!=undefined) 104 | { 105 | $show_warning_(val.error); 106 | return false; 107 | } 108 | }); 109 | } 110 | else 111 | { 112 | if(comment_id!=null) // edit mode 113 | { 114 | var item = $('#posted-'+comment_id, self.$elem); 115 | 116 | var item_txt = $('.posted-comment-txt:hidden', item); 117 | item_txt.html(result.text); 118 | item_txt.toggle(); 119 | 120 | var item_form_edit = $('.posted-comment-form-edit', item); 121 | item_form_edit.toggle(); 122 | 123 | } 124 | else 125 | { 126 | result.fullname = self.user_info_.fullname; 127 | result.picture = self.user_info_.picture; 128 | 129 | // add new itemlist 130 | var itemlist = self.buildItemList_( result ); 131 | 132 | if(result.parent_id===undefined) 133 | self.$rootlist.prepend(itemlist); 134 | else 135 | { 136 | if(result.parent_id==0) 137 | self.$rootlist.prepend(itemlist); 138 | else 139 | { 140 | var id = 'posted-comment-child-'+result.parent_id; 141 | 142 | //prepend the new comment 143 | var the_child = $('ul[id="'+id+'"]', self.$elem).prepend(itemlist); 144 | 145 | // hide the form post 146 | $('div.posted-comments-postbox:visible', the_child).hide(); 147 | } 148 | } 149 | 150 | // update total comment 151 | self.total_comment++; 152 | self.$total_comment.html(self.total_comment+' '+self.options.title); 153 | } 154 | 155 | // clear and enable textarea 156 | $('textarea', self.$elem).val(''); 157 | $('textarea', self.$elem).attr("disabled", false); 158 | } 159 | } 160 | 161 | 162 | }); 163 | }, 164 | 165 | buildPostBox_: function(parent_id){ 166 | var self = this; 167 | 168 | var elem = $('
'); 169 | elem.addClass('posted-comments-postbox'); 170 | 171 | //self.user_info_ 172 | var img_elem = $(''); 173 | img_elem.attr('src', self.user_info_.picture); 174 | img_elem.attr('border', 0); 175 | img_elem.addClass('ui-corner-all'); 176 | img_elem.addClass('curr-user-photo'); 177 | 178 | var avatar = $('
'); 179 | avatar.addClass('avatar').addClass('pull-left'); 180 | avatar.append(img_elem); 181 | 182 | elem.append(avatar); 183 | 184 | 185 | var form = $('
'); 186 | form.addClass('form').addClass('pull-left'); 187 | 188 | if(self.user_info_.is_add_allowed) 189 | { 190 | // form new 191 | var form_elem = self.buildForm_(null, parent_id); 192 | form.append(form_elem); 193 | } 194 | 195 | elem.append(form); 196 | 197 | var clear = $('
'); 198 | clear.addClass('clear'); 199 | 200 | elem.append(clear); 201 | 202 | return elem; 203 | }, 204 | 205 | buildUl_: function(){ 206 | var self = this; 207 | 208 | var ul_elem = $(''); 209 | ul_elem.addClass('posted-comments'); 210 | 211 | return ul_elem; 212 | }, 213 | 214 | refresh_: function( length ) { 215 | var self = this; 216 | 217 | setTimeout(function() { 218 | self.fetch_().done(function( results ) { 219 | 220 | //console.log(results); 221 | 222 | // results['user'] 223 | if(results.results.user!=undefined) 224 | self.user_info_ = results.results.user; 225 | 226 | // results['comments'] 227 | if(results.results.comments!=undefined) 228 | results_ = results.results.comments; 229 | // results = self.limit_( results.results.comments, self.options.limit ); 230 | 231 | // results['total_comment'] 232 | if(results.results.total_comment!=undefined) 233 | self.total_comment = results.results.total_comment; 234 | 235 | self.buildList_( results_ ); 236 | 237 | self.display_(); 238 | 239 | if ( typeof self.options.onComplete === 'function' ) { 240 | self.options.onComplete.apply( self.elem, arguments ); 241 | } 242 | 243 | if ( self.options.refresh && self.options.auto_refresh ) { 244 | self.refresh_(); 245 | } 246 | }); 247 | }, length || self.options.refresh ); 248 | }, 249 | 250 | fetch_: function() { 251 | var self = this; 252 | return $.ajax({ 253 | url: self.options.url_get, 254 | dataType: 'json' 255 | }); 256 | }, 257 | 258 | buildList_: function( results ) { 259 | var self = this; 260 | self.comments = $.map( results, function( obj, i) { 261 | return self.buildItemList_( obj ); 262 | }); 263 | }, 264 | 265 | buildItemList_: function( comment_info ) { 266 | var self = this; 267 | 268 | var item = $( self.options.wrapEachWith ); 269 | 270 | item.attr('id', 'posted-'+comment_info.comment_id); 271 | 272 | // avatar-image 273 | var avatar = $('
'); 274 | avatar.addClass('avatar').addClass('pull-left'); 275 | 276 | var img_elem = $(''); 277 | img_elem.attr('src', comment_info.picture); 278 | img_elem.attr('border', 0); 279 | img_elem.addClass('ui-corner-all'); 280 | 281 | if(comment_info.created_by==self.user_info_.user_id) 282 | img_elem.addClass('curr-user-photo'); 283 | 284 | avatar.append(img_elem); 285 | 286 | item.append(avatar); 287 | 288 | // posted-comment-container 289 | var post_container = $('
'); 290 | post_container.addClass('posted-comment-container').addClass('pull-left'); 291 | 292 | // posted-comment-head 293 | var post_head = $('
'); 294 | post_head.addClass('posted-comment-head'); 295 | 296 | // user-fullname 297 | var username = $(''); 298 | username.addClass('posted-comment-author'); 299 | username.html(comment_info.fullname); 300 | 301 | post_head.append(username); 302 | 303 | // in reply-to 304 | if(comment_info.parent_id!=0) 305 | { 306 | // in-reply-to 307 | var in_reply_to = $(''); 308 | in_reply_to.addClass('in-reply-to'); 309 | in_reply_to.attr('title', 'in reply-to'); 310 | 311 | // arrow 312 | var arrow = $(''); 313 | arrow.addClass('ui-icon'); 314 | arrow.addClass('ui-icon-arrow-1-e'); 315 | 316 | in_reply_to.append(arrow); 317 | 318 | post_head.append(in_reply_to); 319 | 320 | // user-fullname reply 321 | var username_reply = $(''); 322 | username_reply.addClass('posted-comment-author-reply'); 323 | username_reply.html(comment_info.in_reply_to); 324 | 325 | post_head.append(username_reply); 326 | } 327 | 328 | // dot 329 | var dot = $(''); 330 | dot.addClass('dot'); 331 | dot.html('•'); 332 | 333 | post_head.append(dot); 334 | 335 | // posted time 336 | var posted_date = $(''); 337 | posted_date.addClass('real-time'); 338 | posted_date.attr('title', self.timeStringToABBR_(comment_info.posted_date)); 339 | posted_date.html(comment_info.posted_date); 340 | posted_date.timeago(); 341 | 342 | post_head.append(posted_date); 343 | 344 | post_container.append(post_head); 345 | 346 | // posted-comment-body 347 | var post_body = $('
'); 348 | post_body.addClass('posted-comment-body'); 349 | 350 | // posted-comment-txt 351 | var post_txt = $('
'); 352 | post_txt.addClass('posted-comment-txt'); 353 | post_txt.html(comment_info.text); 354 | 355 | post_body.append(post_txt); 356 | 357 | post_container.append(post_body); 358 | 359 | // posted-comment-foot 360 | var post_foot = $('
'); 361 | post_foot.addClass('posted-comment-foot'); 362 | 363 | // edit 364 | if(self.user_info_.is_edit_allowed && (comment_info.created_by==self.user_info_.user_id)) 365 | { 366 | // form edit 367 | var form_edit_container = $('
'); 368 | form_edit_container.addClass('posted-comment-form-edit'); 369 | form_edit_container.hide(); 370 | var form_edit_elem = self.buildForm_(comment_info.comment_id, comment_info.parent_id); 371 | form_edit_container.append(form_edit_elem); 372 | 373 | post_body.append(form_edit_container); 374 | 375 | 376 | var edit_container = $(''); 377 | edit_container.addClass('post-edit'); 378 | 379 | var edit = $('Edit'); 380 | edit.attr('href','#'); 381 | edit.attr('title','Edit'); 382 | 383 | edit_container.append(edit); 384 | 385 | post_foot.append(edit_container); 386 | 387 | var dot = $(''); 388 | dot.addClass('dot'); 389 | dot.html('•'); 390 | 391 | post_foot.append(dot); 392 | 393 | // edit events-apply 394 | edit.on('click', function(e){ 395 | e.preventDefault(); 396 | post_txt.toggle(); 397 | 398 | form_edit_container.toggle(); 399 | var textarea = $('textarea', form_edit_container); 400 | textarea.val(post_txt.html()); 401 | textarea.autogrow(); 402 | textarea.focus(); 403 | }); 404 | } 405 | 406 | // delete 407 | if(self.user_info_.is_edit_allowed && (comment_info.created_by==self.user_info_.user_id)) 408 | { 409 | var delete_container = $(''); 410 | delete_container.addClass('post-delete'); 411 | 412 | var delete_ = $('Delete'); 413 | delete_.attr('href','#'); 414 | delete_.attr('title','Delete'); 415 | 416 | delete_container.append(delete_); 417 | 418 | post_foot.append(delete_container); 419 | 420 | var dot = $(''); 421 | dot.addClass('dot'); 422 | dot.html('•'); 423 | 424 | post_foot.append(dot); 425 | 426 | // delete events-apply 427 | delete_.on('click', function(e){ 428 | e.preventDefault(); 429 | self.buildDeleteConfirm_(comment_info.comment_id); 430 | }); 431 | } 432 | 433 | // reply 434 | if(self.user_info_.is_add_allowed) 435 | { 436 | var reply_container = $(''); 437 | reply_container.addClass('post-reply'); 438 | 439 | var reply = $('Reply'); 440 | reply.attr('href','#'); 441 | reply.attr('title', 'Reply'); 442 | 443 | reply_container.append(reply); 444 | 445 | post_foot.append(reply_container); 446 | } 447 | 448 | post_container.append(post_foot); 449 | 450 | 451 | item.append(post_container); 452 | 453 | var clear = $('
'); 454 | clear.addClass('clear'); 455 | 456 | item.append(clear); 457 | 458 | var ul_child_elem = $(''); 459 | ul_child_elem.addClass('posted-comment-childs'); 460 | ul_child_elem.attr('id', 'posted-comment-child-'+comment_info.comment_id); 461 | 462 | // postbox reply will be toggled show/hide by reply event 463 | if(self.user_info_.is_add_allowed) 464 | { 465 | var postbox = self.buildPostBox_(comment_info.comment_id); 466 | postbox.hide(); 467 | ul_child_elem.append(postbox); 468 | 469 | // reply events-apply 470 | reply.on('click', function(e){ 471 | e.preventDefault(); 472 | postbox.toggle(); 473 | }); 474 | 475 | } 476 | 477 | // check if has childrens 478 | if(comment_info.childrens.length>0) 479 | { 480 | for(var i=0;i'); 498 | self.$total_comment.addClass('comment-length'); 499 | } 500 | 501 | self.$total_comment.html(self.total_comment+' '+self.options.title); 502 | 503 | return self.$total_comment; 504 | }, 505 | 506 | removeItemList_: function( comment_id ){ 507 | var self = this; 508 | 509 | // find target 510 | var target = $('#posted-'+comment_id, self.$elem); 511 | 512 | // remove target 513 | target.remove(); 514 | }, 515 | 516 | display_: function() { 517 | var self = this; 518 | 519 | self.$comment_display = $('
'); 520 | self.$comment_display.addClass('comments-display'); 521 | 522 | var tc = self.buildCountList_(self.total_comment); 523 | self.$comment_display.append(tc); 524 | 525 | // default comment post form reply 526 | var postbox = self.buildPostBox_(null); 527 | self.$comment_display.append(postbox); 528 | 529 | self.$rootlist = self.buildUl_(); 530 | self.$rootlist.append(self.comments); 531 | 532 | self.$comment_display.append(self.$rootlist); 533 | 534 | 535 | if ( self.options.transition === 'none' || !self.options.transition ) { 536 | self.$elem.html( self.$comment_display ); 537 | } else { 538 | self.$elem[ self.options.transition ]( 500, function() { 539 | self.$elem.html( self.$comment_display )[ self.options.transition ]( 500 ); 540 | }); 541 | } 542 | }, 543 | 544 | timeStringToABBR_: function( time_string ) { 545 | var abbr_str = ''; 546 | 547 | var split = time_string.split(' '); 548 | 549 | if(split.length==0) 550 | return abbr_str; 551 | 552 | abbr_str = split[0]+'T'; 553 | 554 | if(split.length==2) 555 | abbr_str += split[1]+'Z'; 556 | 557 | return abbr_str; 558 | }, 559 | 560 | buildDeleteConfirm_: function( comment_id ) { 561 | var self = this; 562 | 563 | var delete_confirm = $('div[id="dialog-delete-comment-confirm"]'); 564 | 565 | if(delete_confirm.length==0) 566 | { 567 | delete_confirm = $('
'); 568 | delete_confirm.attr('id', 'dialog-delete-comment-confirm'); 569 | delete_confirm.attr('title', 'Confirmation'); 570 | 571 | var p = $('

'); 572 | 573 | var icon_alert = $(''); 574 | 575 | var message = $('Are You sure want to delete this data?'); 576 | 577 | p.append(icon_alert); 578 | p.append(message); 579 | delete_confirm.append(p); 580 | delete_confirm.hide().appendTo('body'); 581 | } 582 | 583 | return delete_confirm.dialog({ 584 | autoOpen: true, 585 | modal: true, 586 | buttons: { 587 | Yes: function () { 588 | var form_data = { 'comment_id': comment_id }; 589 | 590 | $.ajax({ 591 | url: self.options.url_delete, 592 | data: form_data, 593 | type: 'post', 594 | dataType: 'json', 595 | }).done( function(result){ 596 | 597 | if(result.success!=undefined) 598 | { 599 | if(result.success===false) 600 | { 601 | // error 602 | $.each(result, function(key, val){ 603 | // check error if any 604 | if(val.error!=undefined) 605 | { 606 | $show_warning_(val.error); 607 | return false; 608 | } 609 | }); 610 | } 611 | else 612 | { 613 | self.removeItemList_(comment_id); 614 | 615 | self.total_comment = result.total_comment; 616 | 617 | self.$total_comment.html(self.total_comment+' '+self.options.title); 618 | 619 | delete_confirm.dialog("close"); 620 | } 621 | } 622 | }); 623 | }, 624 | No: function () { 625 | delete_confirm.dialog("close"); 626 | } 627 | } 628 | }); 629 | }, 630 | 631 | limit_: function( obj, count ) { 632 | return obj.slice( 0, count ); 633 | } 634 | }; 635 | 636 | $.fn.comment = function( options ) { 637 | return this.each(function() { 638 | var comment = Object.create( Comment ); 639 | 640 | comment.init_( options, this ); 641 | 642 | $.data( this, 'comment', comment ); 643 | }); 644 | }; 645 | 646 | // options 647 | $.fn.comment.options = { 648 | title: 'Notes', 649 | url_get: '#', 650 | url_input: '#', 651 | url_delete: '#', 652 | wrapEachWith: '
  • ', 653 | limit: 10, 654 | auto_refresh: true, 655 | refresh: null, 656 | onComplete: null, 657 | transition: 'fadeToggle', 658 | }; 659 | 660 | })(jQuery, window, document); 661 | -------------------------------------------------------------------------------- /js/jquery.timeago.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Timeago is a jQuery plugin that makes it easy to support automatically 3 | * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). 4 | * 5 | * @name timeago 6 | * @version 1.0.2 7 | * @requires jQuery v1.2.3+ 8 | * @author Ryan McGeary 9 | * @license MIT License - http://www.opensource.org/licenses/mit-license.php 10 | * 11 | * For usage and examples, visit: 12 | * http://timeago.yarp.com/ 13 | * 14 | * Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) 15 | */ 16 | 17 | (function (factory) { 18 | if (typeof define === 'function' && define.amd) { 19 | // AMD. Register as an anonymous module. 20 | define(['jquery'], factory); 21 | } else { 22 | // Browser globals 23 | factory(jQuery); 24 | } 25 | }(function ($) { 26 | $.timeago = function(timestamp) { 27 | if (timestamp instanceof Date) { 28 | return inWords(timestamp); 29 | } else if (typeof timestamp === "string") { 30 | return inWords($.timeago.parse(timestamp)); 31 | } else if (typeof timestamp === "number") { 32 | return inWords(new Date(timestamp)); 33 | } else { 34 | return inWords($.timeago.datetime(timestamp)); 35 | } 36 | }; 37 | var $t = $.timeago; 38 | 39 | $.extend($.timeago, { 40 | settings: { 41 | refreshMillis: 60000, 42 | allowFuture: false, 43 | strings: { 44 | prefixAgo: null, 45 | prefixFromNow: null, 46 | suffixAgo: "ago", 47 | suffixFromNow: "from now", 48 | seconds: "less than a minute", 49 | minute: "about a minute", 50 | minutes: "%d minutes", 51 | hour: "about an hour", 52 | hours: "about %d hours", 53 | day: "a day", 54 | days: "%d days", 55 | month: "about a month", 56 | months: "%d months", 57 | year: "about a year", 58 | years: "%d years", 59 | wordSeparator: " ", 60 | numbers: [] 61 | } 62 | }, 63 | inWords: function(distanceMillis) { 64 | var $l = this.settings.strings; 65 | var prefix = $l.prefixAgo; 66 | var suffix = $l.suffixAgo; 67 | if (this.settings.allowFuture) { 68 | if (distanceMillis < 0) { 69 | prefix = $l.prefixFromNow; 70 | suffix = $l.suffixFromNow; 71 | } 72 | } 73 | 74 | var seconds = Math.abs(distanceMillis) / 1000; 75 | var minutes = seconds / 60; 76 | var hours = minutes / 60; 77 | var days = hours / 24; 78 | var years = days / 365; 79 | 80 | function substitute(stringOrFunction, number) { 81 | var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; 82 | var value = ($l.numbers && $l.numbers[number]) || number; 83 | return string.replace(/%d/i, value); 84 | } 85 | 86 | var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || 87 | seconds < 90 && substitute($l.minute, 1) || 88 | minutes < 45 && substitute($l.minutes, Math.round(minutes)) || 89 | minutes < 90 && substitute($l.hour, 1) || 90 | hours < 24 && substitute($l.hours, Math.round(hours)) || 91 | hours < 42 && substitute($l.day, 1) || 92 | days < 30 && substitute($l.days, Math.round(days)) || 93 | days < 45 && substitute($l.month, 1) || 94 | days < 365 && substitute($l.months, Math.round(days / 30)) || 95 | years < 1.5 && substitute($l.year, 1) || 96 | substitute($l.years, Math.round(years)); 97 | 98 | var separator = $l.wordSeparator || ""; 99 | if ($l.wordSeparator === undefined) { separator = " "; } 100 | return $.trim([prefix, words, suffix].join(separator)); 101 | }, 102 | parse: function(iso8601) { 103 | var s = $.trim(iso8601); 104 | s = s.replace(/\.\d+/,""); // remove milliseconds 105 | s = s.replace(/-/,"/").replace(/-/,"/"); 106 | s = s.replace(/T/," ").replace(/Z/," UTC"); 107 | s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 108 | return new Date(s); 109 | }, 110 | datetime: function(elem) { 111 | var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title"); 112 | return $t.parse(iso8601); 113 | }, 114 | isTime: function(elem) { 115 | // jQuery's `is()` doesn't play well with HTML5 in IE 116 | return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time"); 117 | } 118 | }); 119 | 120 | $.fn.timeago = function() { 121 | var self = this; 122 | self.each(refresh); 123 | 124 | var $s = $t.settings; 125 | if ($s.refreshMillis > 0) { 126 | setInterval(function() { self.each(refresh); }, $s.refreshMillis); 127 | } 128 | return self; 129 | }; 130 | 131 | function refresh() { 132 | var data = prepareData(this); 133 | if (!isNaN(data.datetime)) { 134 | $(this).text(inWords(data.datetime)); 135 | } 136 | return this; 137 | } 138 | 139 | function prepareData(element) { 140 | element = $(element); 141 | if (!element.data("timeago")) { 142 | element.data("timeago", { datetime: $t.datetime(element) }); 143 | var text = $.trim(element.text()); 144 | if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) { 145 | element.attr("title", text); 146 | } 147 | } 148 | return element.data("timeago"); 149 | } 150 | 151 | function inWords(date) { 152 | return $t.inWords(distance(date)); 153 | } 154 | 155 | function distance(date) { 156 | return (new Date().getTime() - date.getTime()); 157 | } 158 | 159 | // fix for IE6 suckage 160 | document.createElement("abbr"); 161 | document.createElement("time"); 162 | })); 163 | --------------------------------------------------------------------------------