comment.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. // This file is part of Moodle - http://moodle.org/
  2. //
  3. // Moodle is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // Moodle is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  15. /**
  16. * Comment Helper
  17. * @author Dongsheng Cai <dongsheng@moodle.com>
  18. */
  19. M.core_comment = {
  20. /**
  21. * Initialize commenting system
  22. */
  23. init: function(Y, options) {
  24. var CommentHelper = function(args) {
  25. CommentHelper.superclass.constructor.apply(this, arguments);
  26. };
  27. CommentHelper.NAME = "COMMENT";
  28. CommentHelper.ATTRS = {
  29. options: {},
  30. lang: {}
  31. };
  32. Y.extend(CommentHelper, Y.Base, {
  33. api: M.cfg.wwwroot+'/comment/comment_ajax.php',
  34. initializer: function(args) {
  35. var scope = this;
  36. this.client_id = args.client_id;
  37. this.itemid = args.itemid;
  38. this.commentarea = args.commentarea;
  39. this.component = args.component;
  40. this.courseid = args.courseid;
  41. this.contextid = args.contextid;
  42. this.autostart = (args.autostart);
  43. // expand comments?
  44. if (this.autostart) {
  45. this.view(args.page);
  46. }
  47. // load comments
  48. var handle = Y.one('#comment-link-'+this.client_id);
  49. // hide toggle link
  50. if (handle) {
  51. if (args.notoggle) {
  52. handle.setStyle('display', 'none');
  53. }
  54. handle.on('click', function(e) {
  55. e.preventDefault();
  56. this.view(0);
  57. return false;
  58. }, this);
  59. }
  60. scope.toggle_textarea(false);
  61. },
  62. post: function() {
  63. var ta = Y.one('#dlg-content-'+this.client_id);
  64. var scope = this;
  65. var value = ta.get('value');
  66. if (value && value != M.util.get_string('addcomment', 'moodle')) {
  67. ta.set('disabled', true);
  68. ta.setStyles({
  69. 'backgroundImage': 'url(' + M.util.image_url('i/loading_small', 'core') + ')',
  70. 'backgroundRepeat': 'no-repeat',
  71. 'backgroundPosition': 'center center'
  72. });
  73. var params = {'content': value};
  74. this.request({
  75. action: 'add',
  76. scope: scope,
  77. params: params,
  78. callback: function(id, obj, args) {
  79. var scope = args.scope;
  80. var cid = scope.client_id;
  81. var ta = Y.one('#dlg-content-'+cid);
  82. ta.set('value', '');
  83. ta.set('disabled', false);
  84. ta.setStyle('backgroundImage', 'none');
  85. scope.toggle_textarea(false);
  86. var container = Y.one('#comment-list-'+cid);
  87. var result = scope.render([obj], true);
  88. var newcomment = Y.Node.create(result.html);
  89. container.appendChild(newcomment);
  90. var ids = result.ids;
  91. var linkText = Y.one('#comment-link-text-' + cid);
  92. if (linkText) {
  93. linkText.set('innerHTML', M.util.get_string('commentscount', 'moodle', obj.count));
  94. }
  95. for(var i in ids) {
  96. var attributes = {
  97. color: { to: '#06e' },
  98. backgroundColor: { to: '#FFE390' }
  99. };
  100. var anim = new Y.YUI2.util.ColorAnim(ids[i], attributes);
  101. anim.animate();
  102. }
  103. scope.register_pagination();
  104. scope.register_delete_buttons();
  105. }
  106. }, true);
  107. } else {
  108. var attributes = {
  109. backgroundColor: { from: '#FFE390', to:'#FFFFFF' }
  110. };
  111. var anim = new Y.YUI2.util.ColorAnim('dlg-content-'+cid, attributes);
  112. anim.animate();
  113. }
  114. },
  115. request: function(args, noloading) {
  116. var params = {};
  117. var scope = this;
  118. if (args['scope']) {
  119. scope = args['scope'];
  120. }
  121. //params['page'] = args.page?args.page:'';
  122. // the form element only accept certain file types
  123. params['sesskey'] = M.cfg.sesskey;
  124. params['action'] = args.action?args.action:'';
  125. params['client_id'] = this.client_id;
  126. params['itemid'] = this.itemid;
  127. params['area'] = this.commentarea;
  128. params['courseid'] = this.courseid;
  129. params['contextid'] = this.contextid;
  130. params['component'] = this.component;
  131. if (args['params']) {
  132. for (i in args['params']) {
  133. params[i] = args['params'][i];
  134. }
  135. }
  136. var cfg = {
  137. method: 'POST',
  138. on: {
  139. complete: function(id,o,p) {
  140. if (!o) {
  141. alert('IO FATAL');
  142. return false;
  143. }
  144. var data = Y.JSON.parse(o.responseText);
  145. if (data.error) {
  146. if (data.error == 'require_login') {
  147. args.callback(id,data,p);
  148. return true;
  149. }
  150. alert(data.error);
  151. return false;
  152. } else {
  153. args.callback(id,data,p);
  154. return true;
  155. }
  156. }
  157. },
  158. arguments: {
  159. scope: scope
  160. },
  161. headers: {
  162. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  163. },
  164. data: build_querystring(params)
  165. };
  166. if (args.form) {
  167. cfg.form = args.form;
  168. }
  169. Y.io(this.api, cfg);
  170. if (!noloading) {
  171. this.wait();
  172. }
  173. },
  174. render: function(list, newcmt) {
  175. var ret = {};
  176. ret.ids = [];
  177. var template = Y.one('#cmt-tmpl');
  178. var html = '';
  179. for(var i in list) {
  180. var htmlid = 'comment-'+list[i].id+'-'+this.client_id;
  181. var val = template.get('innerHTML');
  182. if (list[i].profileurl) {
  183. val = val.replace('___name___', '<a href="'+list[i].profileurl+'">'+list[i].fullname+'</a>');
  184. } else {
  185. val = val.replace('___name___', list[i].fullname);
  186. }
  187. if (list[i]['delete']||newcmt) {
  188. list[i].content = '<div class="comment-delete"><a href="#" id ="comment-delete-'+this.client_id+'-'+list[i].id+'" title="'+M.util.get_string('deletecomment', 'moodle')+'"><img alt="" src="'+M.util.image_url('t/delete', 'core')+'" /></a></div>' + list[i].content;
  189. }
  190. val = val.replace('___time___', list[i].time);
  191. val = val.replace('___picture___', list[i].avatar);
  192. val = val.replace('___content___', list[i].content);
  193. val = '<li id="'+htmlid+'">'+val+'</li>';
  194. ret.ids.push(htmlid);
  195. html = (val+html);
  196. }
  197. ret.html = html;
  198. return ret;
  199. },
  200. load: function(page) {
  201. var scope = this;
  202. var container = Y.one('#comment-ctrl-'+this.client_id);
  203. var params = {
  204. 'action': 'get',
  205. 'page': page
  206. };
  207. this.request({
  208. scope: scope,
  209. params: params,
  210. callback: function(id, ret, args) {
  211. var linkText = Y.one('#comment-link-text-' + scope.client_id);
  212. if (ret.count && linkText) {
  213. linkText.set('innerHTML', M.util.get_string('commentscount', 'moodle', ret.count));
  214. }
  215. var container = Y.one('#comment-list-'+scope.client_id);
  216. var pagination = Y.one('#comment-pagination-'+scope.client_id);
  217. if (ret.pagination) {
  218. pagination.set('innerHTML', ret.pagination);
  219. } else {
  220. //empty paging bar
  221. pagination.set('innerHTML', '');
  222. }
  223. if (ret.error == 'require_login') {
  224. var result = {};
  225. result.html = M.util.get_string('commentsrequirelogin', 'moodle');
  226. } else {
  227. var result = scope.render(ret.list);
  228. }
  229. container.set('innerHTML', result.html);
  230. var img = Y.one('#comment-img-'+scope.client_id);
  231. if (img) {
  232. img.set('src', M.util.image_url('t/expanded', 'core'));
  233. }
  234. args.scope.register_pagination();
  235. args.scope.register_delete_buttons();
  236. }
  237. });
  238. },
  239. dodelete: function(id) { // note: delete is a reserved word in javascript, chrome and safary do not like it at all here!
  240. var scope = this,
  241. cid = scope.client_id,
  242. params = {'commentid': id};
  243. function remove_dom(type, anim, cmt) {
  244. cmt.remove();
  245. var linkText = Y.one('#comment-link-text-' + cid),
  246. comments = Y.all('#comment-list-' + cid + ' li');
  247. if (linkText && comments) {
  248. linkText.set('innerHTML', M.util.get_string('commentscount', 'moodle', comments.size()));
  249. }
  250. }
  251. this.request({
  252. action: 'delete',
  253. scope: scope,
  254. params: params,
  255. callback: function(id, resp, args) {
  256. var htmlid= 'comment-'+resp.commentid+'-'+resp.client_id;
  257. var attributes = {
  258. width:{to:0},
  259. height:{to:0}
  260. };
  261. var cmt = Y.one('#'+htmlid);
  262. cmt.setStyle('overflow', 'hidden');
  263. var anim = new Y.YUI2.util.Anim(htmlid, attributes, 1, Y.YUI2.util.Easing.easeOut);
  264. anim.onComplete.subscribe(remove_dom, cmt, this);
  265. anim.animate();
  266. }
  267. }, true);
  268. },
  269. register_actions: function() {
  270. // add new comment
  271. var action_btn = Y.one('#comment-action-post-'+this.client_id);
  272. if (action_btn) {
  273. action_btn.on('click', function(e) {
  274. e.preventDefault();
  275. this.post();
  276. return false;
  277. }, this);
  278. }
  279. // cancel comment box
  280. var cancel = Y.one('#comment-action-cancel-'+this.client_id);
  281. if (cancel) {
  282. cancel.on('click', function(e) {
  283. e.preventDefault();
  284. this.view(0);
  285. return false;
  286. }, this);
  287. }
  288. },
  289. register_delete_buttons: function() {
  290. var scope = this;
  291. // page buttons
  292. Y.all('div.comment-delete a').each(
  293. function(node, id) {
  294. var theid = node.get('id');
  295. var parseid = new RegExp("comment-delete-"+scope.client_id+"-(\\d+)", "i");
  296. var commentid = theid.match(parseid);
  297. if (!commentid) {
  298. return;
  299. }
  300. if (commentid[1]) {
  301. Y.Event.purgeElement('#'+theid, false, 'click');
  302. }
  303. node.on('click', function(e) {
  304. e.preventDefault();
  305. if (commentid[1]) {
  306. scope.dodelete(commentid[1]);
  307. }
  308. });
  309. // Also handle space/enter key.
  310. node.on('key', function(e) {
  311. e.preventDefault();
  312. if (commentid[1]) {
  313. scope.dodelete(commentid[1]);
  314. }
  315. }, '13,32');
  316. // 13 and 32 are the keycodes for space and enter.
  317. }
  318. );
  319. },
  320. register_pagination: function() {
  321. var scope = this;
  322. // page buttons
  323. Y.all('#comment-pagination-'+this.client_id+' a').each(
  324. function(node, id) {
  325. node.on('click', function(e, node) {
  326. e.preventDefault();
  327. var id = node.get('id');
  328. var re = new RegExp("comment-page-"+this.client_id+"-(\\d+)", "i");
  329. var result = id.match(re);
  330. this.load(result[1]);
  331. }, scope, node);
  332. }
  333. );
  334. },
  335. view: function(page) {
  336. var container = Y.one('#comment-ctrl-'+this.client_id);
  337. var ta = Y.one('#dlg-content-'+this.client_id);
  338. var img = Y.one('#comment-img-'+this.client_id);
  339. var d = container.getStyle('display');
  340. if (d=='none'||d=='') {
  341. // show
  342. if (!this.autostart) {
  343. this.load(page);
  344. } else {
  345. this.register_delete_buttons();
  346. this.register_pagination();
  347. }
  348. container.setStyle('display', 'block');
  349. if (img) {
  350. img.set('src', M.util.image_url('t/expanded', 'core'));
  351. }
  352. } else {
  353. // hide
  354. container.setStyle('display', 'none');
  355. var collapsedimage = 't/collapsed'; // ltr mode
  356. if ( Y.one(document.body).hasClass('dir-rtl') ) {
  357. collapsedimage = 't/collapsed_rtl';
  358. } else {
  359. collapsedimage = 't/collapsed';
  360. }
  361. img.set('src', M.util.image_url(collapsedimage, 'core'));
  362. if (ta) {
  363. ta.set('value','');
  364. }
  365. }
  366. if (ta) {
  367. //toggle_textarea.apply(ta, [false]);
  368. //// reset textarea size
  369. ta.on('focus', function() {
  370. this.toggle_textarea(true);
  371. }, this);
  372. //ta.onkeypress = function() {
  373. //if (this.scrollHeight > this.clientHeight && !window.opera)
  374. //this.rows += 1;
  375. //}
  376. ta.on('blur', function() {
  377. this.toggle_textarea(false);
  378. }, this);
  379. }
  380. this.register_actions();
  381. return false;
  382. },
  383. toggle_textarea: function(focus) {
  384. var t = Y.one('#dlg-content-'+this.client_id);
  385. if (!t) {
  386. return false;
  387. }
  388. if (focus) {
  389. if (t.get('value') == M.util.get_string('addcomment', 'moodle')) {
  390. t.set('value', '');
  391. t.setStyle('color', 'black');
  392. }
  393. }else{
  394. if (t.get('value') == '') {
  395. t.set('value', M.util.get_string('addcomment', 'moodle'));
  396. t.setStyle('color','grey');
  397. t.set('rows', 2);
  398. }
  399. }
  400. },
  401. wait: function() {
  402. var container = Y.one('#comment-list-'+this.client_id);
  403. container.set('innerHTML', '<div class="mdl-align"><img src="'+M.util.image_url('i/loading_small', 'core')+'" /></div>');
  404. }
  405. });
  406. new CommentHelper(options);
  407. },
  408. init_admin: function(Y) {
  409. var select_all = Y.one('#comment_select_all');
  410. select_all.on('click', function(e) {
  411. var comments = document.getElementsByName('comments');
  412. var checked = false;
  413. for (var i in comments) {
  414. if (comments[i].checked) {
  415. checked=true;
  416. }
  417. }
  418. for (i in comments) {
  419. comments[i].checked = !checked;
  420. }
  421. this.set('checked', !checked);
  422. });
  423. var comments_delete = Y.one('#comments_delete');
  424. if (comments_delete) {
  425. comments_delete.on('click', function(e) {
  426. e.preventDefault();
  427. var list = '';
  428. var comments = document.getElementsByName('comments');
  429. for (var i in comments) {
  430. if (typeof comments[i] == 'object' && comments[i].checked) {
  431. list += (comments[i].value + '-');
  432. }
  433. }
  434. if (!list) {
  435. return;
  436. }
  437. var args = {};
  438. args.message = M.util.get_string('confirmdeletecomments', 'admin');
  439. args.callback = function() {
  440. var url = M.cfg.wwwroot + '/comment/index.php';
  441. var data = {
  442. 'commentids': list,
  443. 'sesskey': M.cfg.sesskey,
  444. 'action': 'delete'
  445. };
  446. var cfg = {
  447. method: 'POST',
  448. on: {
  449. complete: function(id,o,p) {
  450. if (!o) {
  451. alert('IO FATAL');
  452. return;
  453. }
  454. if (o.responseText == 'yes') {
  455. location.reload();
  456. }
  457. }
  458. },
  459. arguments: {
  460. scope: this
  461. },
  462. headers: {
  463. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  464. },
  465. data: build_querystring(data)
  466. };
  467. Y.io(url, cfg);
  468. };
  469. M.util.show_confirm_dialog(e, args);
  470. });
  471. }
  472. }
  473. };