You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

556 lines
16 KiB

  1. // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. // MIT License. See license.txt
  3. wn.provide("website");
  4. $.extend(website, {
  5. toggle_permitted: function() {
  6. if(website.access) {
  7. // hide certain views
  8. $('li[data-view="add"]').toggleClass("hide", !website.access.write);
  9. $('li[data-view="settings"]').toggleClass("hide", !website.access.admin);
  10. $('li[data-view="edit"]').toggleClass("hide", website.view!=="edit");
  11. // show message
  12. $(".post-list-help").html(!website.access.write ? "You do not have permission to post" : "");
  13. }
  14. },
  15. setup_pagination: function() {
  16. var $btn = $(".btn-more")
  17. .removeClass("hide")
  18. .on("click", function() {
  19. wn.call({
  20. btn: $btn,
  21. type: "GET",
  22. args: {
  23. cmd: "webnotes.templates.website_group.forum.get_post_list_html",
  24. limit_start: $(".post").length,
  25. limit_length: 20,
  26. group: website.group,
  27. view: website.view,
  28. pathname: website.pathname
  29. },
  30. callback: function(data) {
  31. $(".post-list").append(data.message);
  32. $btn.toggleClass("hide", !(data.message && data.message.length===opts.args.limit_length));
  33. website.toggle_upvote();
  34. }
  35. })
  36. });
  37. },
  38. bind_add_post: function() {
  39. $(".btn-post-add").on("click", website.add_post);
  40. $pic_input = $(".control-post-add-picture").on("change", website.add_picture);
  41. $(".btn-post-add-picture").on("click", function() {
  42. $pic_input.click();
  43. });
  44. },
  45. add_post: function() {
  46. if(website.post) {
  47. wn.msgprint("Post already exists. Cannot add again!");
  48. return;
  49. }
  50. website._update_post(this, "webnotes.templates.website_group.post.add_post");
  51. },
  52. bind_save_post: function() {
  53. $(".btn-post-add").addClass("hide");
  54. $(".btn-post-save").removeClass("hide").on("click", website.save_post);
  55. $(".post-picture").toggleClass("hide", !$(".post-picture").attr("src"));
  56. },
  57. save_post: function() {
  58. if(!website.post) {
  59. wn.msgprint("Post does not exist. Please add post!");
  60. return;
  61. }
  62. website._update_post(this, "webnotes.templates.website_group.post.save_post");
  63. },
  64. _update_post: function(btn, cmd) {
  65. var values = website.get_editor_values();
  66. if(!values) {
  67. return;
  68. }
  69. wn.call({
  70. btn: btn,
  71. type: "POST",
  72. args: $.extend({
  73. cmd: cmd,
  74. group: website.group,
  75. post: website.post || undefined,
  76. }, values),
  77. callback: function(data) {
  78. var url = window.location.pathname + "?view=post&name=" + data.message;
  79. window.location.href = url;
  80. }
  81. });
  82. },
  83. get_editor_values: function() {
  84. var values = {};
  85. $.each($('.post-editor [data-fieldname]'), function(i, ele) {
  86. var $ele = $(ele);
  87. values[$ele.attr("data-fieldname")] = $ele.val();
  88. });
  89. values.parent_post = $(".post-editor").attr("data-parent-post");
  90. values.picture_name = $(".control-post-add-picture").val() || null;
  91. var dataurl = $(".post-picture img").attr("src");
  92. values.picture = dataurl ? dataurl.split(",")[1] : ""
  93. // validations
  94. if(!values.parent_post && !values.title) {
  95. wn.msgprint("Please enter title!");
  96. return;
  97. } else if(!values.content) {
  98. wn.msgprint("Please enter some text!");
  99. return;
  100. } else if($('.post-editor [data-fieldname="event_datetime"]').length && !values.event_datetime) {
  101. wn.msgprint("Please enter Event's Date and Time!");
  102. return;
  103. }
  104. // post process
  105. // convert links in content
  106. values.content = website.process_external_links(values.content);
  107. return values;
  108. },
  109. process_external_links: function(content) {
  110. return content.replace(/([^\s]*)(http|https|ftp):\/\/[^\s\[\]\(\)]+/g, function(match, p1) {
  111. // mimicing look behind! should not have anything in p1
  112. // replace(/match/g)
  113. // replace(/(p1)(p2)/g)
  114. // so, when there is a character before http://, it shouldn't be replaced!
  115. if(p1) return match;
  116. return "["+match+"]("+match+")";
  117. });
  118. },
  119. add_picture: function() {
  120. if (this.type === 'file' && this.files && this.files.length > 0) {
  121. $.each(this.files, function (idx, fileobj) {
  122. if (/^image\//.test(fileobj.type)) {
  123. $.canvasResize(fileobj, {
  124. width: 500,
  125. height: 0,
  126. crop: false,
  127. quality: 80,
  128. callback: function(data, width, height) {
  129. $(".post-picture").removeClass("hide").find("img").attr("src", data);
  130. }
  131. });
  132. }
  133. });
  134. }
  135. return false;
  136. },
  137. setup_tasks_editor: function() {
  138. // assign events
  139. var $post_editor = $(".post-editor");
  140. var $control_assign = $post_editor.find('.control-assign');
  141. var bind_close = function() {
  142. var close = $post_editor.find("a.close")
  143. if(close.length) {
  144. close.on("click", function() {
  145. // clear assignment
  146. $post_editor.find(".assigned-to").addClass("hide");
  147. $post_editor.find(".assigned-profile").html("");
  148. $post_editor.find('[data-fieldname="assigned_to"]').val(null);
  149. $control_assign.val(null);
  150. });
  151. }
  152. }
  153. if($control_assign.length) {
  154. website.setup_autosuggest({
  155. $control: $control_assign,
  156. select: function(value, item) {
  157. var $assigned_to = $post_editor.find(".assigned-to").removeClass("hide");
  158. $assigned_to.find(".assigned-profile").html(item.profile_html);
  159. $post_editor.find('[data-fieldname="assigned_to"]').val(value);
  160. bind_close();
  161. },
  162. method: "webnotes.templates.website_group.post.suggest_user"
  163. });
  164. bind_close();
  165. }
  166. },
  167. setup_event_editor: function() {
  168. var $post_editor = $(".post-editor");
  169. var $control_event = $post_editor.find('.control-event').empty();
  170. var $event_field = $post_editor.find('[data-fieldname="event_datetime"]');
  171. var set_event = function($control) {
  172. var datetime = website.datetimepicker.obj_to_str($control_event.datepicker("getDate"));
  173. if($event_field.val() !== datetime) {
  174. $event_field.val(datetime);
  175. }
  176. };
  177. website.setup_datepicker({
  178. $control: $control_event,
  179. onClose: function() { set_event($control_event) }
  180. });
  181. if($event_field.val()) {
  182. $control_event.val(website.datetimepicker.format_datetime($event_field.val()));
  183. }
  184. },
  185. format_event_timestamps: function() {
  186. var get_day = function(num) {
  187. return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  188. "Friday", "Saturday"][num];
  189. }
  190. var get_month = function(num) {
  191. return ["January", "February", "March", "April", "May", "June",
  192. "July", "August", "September", "October", "November", "December"][num-1];
  193. }
  194. var format = function(datetime) {
  195. if(!datetime) return "";
  196. var date = datetime.split(" ")[0].split("-");
  197. var time = datetime.split(" ")[1].split(":");
  198. var tt = "am";
  199. if(time[0] >= 12) {
  200. time[0] = parseInt(time[0]) - 12;
  201. tt = "pm";
  202. }
  203. if(!parseInt(time[0])) {
  204. time[0] = 12;
  205. }
  206. var hhmm = [time[0], time[1]].join(":")
  207. // DD, d MM, yy hh:mm tt
  208. var dateobj = new Date(date[0], date[1], date[2])
  209. return repl("%(day)s, %(date)s %(month)s, %(year)s %(time)s", {
  210. day: get_day(dateobj.getDay()),
  211. date: date[2],
  212. month: get_month(dateobj.getMonth()),
  213. year: date[0],
  214. time: hhmm + " " + tt
  215. })
  216. }
  217. $(".event-timestamp").each(function() {
  218. $(this).html(format($(this).attr("data-timestamp")));
  219. })
  220. },
  221. toggle_earlier_replies: function() {
  222. var $earlier_replies = $(".child-post").slice(0, $(".child-post").length - 2);
  223. var $btn = $(".btn-earlier-replies").on("click", function() {
  224. if($earlier_replies.hasClass("hide")) {
  225. $earlier_replies.removeClass("hide");
  226. $(".btn-earlier-label").html("Hide");
  227. } else {
  228. $earlier_replies.addClass("hide");
  229. $(".btn-earlier-label").html("Show");
  230. }
  231. });
  232. if($earlier_replies.length) {
  233. $btn.toggleClass("hide", false).click();
  234. }
  235. },
  236. toggle_edit: function(only_owner) {
  237. if(only_owner) {
  238. var user = wn.get_cookie("user_id");
  239. $(".edit-post").each(function() {
  240. $(this).toggleClass("hide", !(website.access.write && $(this).attr("data-owner")===user));
  241. });
  242. } else {
  243. $(".edit-post").toggleClass("hide", !website.access.write);
  244. }
  245. },
  246. toggle_upvote: function() {
  247. if(!website.access.read || !website.upvote) {
  248. $(".upvote").remove();
  249. }
  250. },
  251. toggle_post_editor: function() {
  252. $(".post-editor").toggleClass("hide", !website.access.write);
  253. },
  254. setup_upvote: function() {
  255. if(window.website.setup_upvote_done) return;
  256. window.website.setup_upvote_done = true;
  257. $(document).on("click", ".post-list .upvote a, .parent-post .upvote a", function() {
  258. console.log("clicked");
  259. var sid = wn.get_cookie("sid");
  260. if(!sid || sid==="Guest") {
  261. wn.msgprint("Please login to Upvote!");
  262. return;
  263. }
  264. var $post = $(this).parents(".post");
  265. var post = $post.attr("data-name");
  266. var $btn = $(this).prop("disabled", true);
  267. $.ajax({
  268. url: "/",
  269. type: "POST",
  270. data: {
  271. cmd: "webnotes.website.doctype.user_vote.user_vote.set_vote",
  272. ref_doctype: "Post",
  273. ref_name: post
  274. },
  275. statusCode: {
  276. 200: function(data) {
  277. if(data.exc) {
  278. console.log(data.exc);
  279. } else {
  280. var text_class = data.message === "ok" ? "text-success" : "text-danger";
  281. if(data.message==="ok") {
  282. var count = parseInt($post.find(".upvote-count").text());
  283. $post.find(".upvote-count").text(count + 1).removeClass("hide");
  284. }
  285. $btn.addClass(text_class);
  286. setTimeout(function() { $btn.removeClass(text_class); }, 2000);
  287. }
  288. }
  289. }
  290. }).always(function() {
  291. $btn.prop("disabled", false);
  292. });
  293. return false;
  294. });
  295. },
  296. setup_autosuggest: function(opts) {
  297. if(opts.$control.hasClass("ui-autocomplete-input")) return;
  298. wn.require("/assets/webnotes/js/lib/jquery/jquery.ui.min.js");
  299. wn.require("/assets/webnotes/js/lib/jquery/bootstrap_theme/jquery-ui.selected.css");
  300. var $user_suggest = opts.$control.autocomplete({
  301. source: function(request, response) {
  302. $.ajax({
  303. url: "/",
  304. data: {
  305. cmd: opts.method,
  306. term: request.term,
  307. group: website.group
  308. },
  309. success: function(data) {
  310. if(data.exc) {
  311. console.log(data.exc);
  312. } else {
  313. response(data.message);
  314. }
  315. }
  316. });
  317. },
  318. select: function(event, ui) {
  319. opts.$control.val("");
  320. opts.select(ui.item.profile, ui.item);
  321. }
  322. });
  323. $user_suggest.data( "ui-autocomplete" )._renderItem = function(ul, item) {
  324. return $("<li>").html("<a style='padding: 5px;'>" + item.profile_html + "</a>")
  325. .css("padding", "5px")
  326. .appendTo(ul);
  327. };
  328. return opts.$control
  329. },
  330. setup_datepicker: function(opts) {
  331. if(opts.$control.hasClass("hasDatetimepicker")) return;
  332. // libs required for datetime picker
  333. wn.require("/assets/webnotes/js/lib/jquery/jquery.ui.min.js");
  334. wn.require("/assets/webnotes/js/lib/jquery/bootstrap_theme/jquery-ui.selected.css");
  335. wn.require("/assets/webnotes/js/lib/jquery/jquery.ui.slider.min.js");
  336. wn.require("/assets/webnotes/js/lib/jquery/jquery.ui.sliderAccess.js");
  337. wn.require("/assets/webnotes/js/lib/jquery/jquery.ui.timepicker-addon.css");
  338. wn.require("/assets/webnotes/js/lib/jquery/jquery.ui.timepicker-addon.js");
  339. opts.$control.datetimepicker({
  340. timeFormat: "hh:mm tt",
  341. dateFormat: 'DD, d MM, yy',
  342. changeYear: true,
  343. yearRange: "-70Y:+10Y",
  344. stepMinute: 5,
  345. hour: 10,
  346. onClose: opts.onClose
  347. });
  348. website.setup_datetime_functions();
  349. return opts.$control;
  350. },
  351. setup_datetime_functions: function() {
  352. // requires datetime picker
  353. wn.provide("website.datetimepicker");
  354. website.datetimepicker.str_to_obj = function(datetime_str) {
  355. return $.datepicker.parseDateTime("yy-mm-dd", "HH:mm:ss", datetime_str);
  356. };
  357. website.datetimepicker.obj_to_str = function(datetime) {
  358. if(!datetime) {
  359. return "";
  360. }
  361. // requires datepicker
  362. var date_str = $.datepicker.formatDate("yy-mm-dd", datetime)
  363. var time_str = $.datepicker.formatTime("HH:mm:ss", {
  364. hour: datetime.getHours(),
  365. minute: datetime.getMinutes(),
  366. second: datetime.getSeconds()
  367. })
  368. return date_str + " " + time_str;
  369. };
  370. website.datetimepicker.format_datetime = function(datetime) {
  371. if (typeof(datetime)==="string") {
  372. datetime = website.datetimepicker.str_to_obj(datetime);
  373. }
  374. var date_str = $.datepicker.formatDate("DD, d MM, yy", datetime)
  375. var time_str = $.datepicker.formatTime("hh:mm tt", {
  376. hour: datetime.getHours(),
  377. minute: datetime.getMinutes(),
  378. second: datetime.getSeconds()
  379. })
  380. return date_str + " " + time_str;
  381. }
  382. },
  383. setup_settings: function() {
  384. // autosuggest
  385. website.setup_autosuggest({
  386. $control: $(".add-user-control"),
  387. select: function(value) {
  388. website.add_sitemap_permission(value);
  389. },
  390. method: "webnotes.templates.website_group.settings.suggest_user"
  391. });
  392. // trigger for change permission
  393. $(".permission-editor-area").on("click", ".sitemap-permission [type='checkbox']",
  394. website.update_permission);
  395. $(".permission-editor-area").find(".btn-add-group").on("click", website.add_group);
  396. $(".btn-settings").parent().addClass("active");
  397. // disabled public_write if not public_read
  398. var control_public_read = $(".control-add-group-public_read").click(function() {
  399. if(!$(this).prop("checked")) {
  400. $(".control-add-group-public_write").prop("checked", false).prop("disabled", true);
  401. } else {
  402. $(".control-add-group-public_write").prop("disabled", false);
  403. }
  404. }).trigger("click").trigger("click"); // hack
  405. },
  406. add_group: function() {
  407. var $control = $(".control-add-group"),
  408. $btn = $(".btn-add-group");
  409. if($control.val()) {
  410. $btn.prop("disabled", true);
  411. $.ajax({
  412. url:"/",
  413. type:"POST",
  414. data: {
  415. cmd:"webnotes.templates.website_group.settings.add_website_group",
  416. group: website.group,
  417. new_group: $control.val(),
  418. group_type: $(".control-add-group-type").val(),
  419. public_read: $(".control-add-group-public_read").is(":checked") ? 1 : 0,
  420. public_write: $(".control-add-group-public_write").is(":checked") ? 1 : 0
  421. },
  422. statusCode: {
  423. 403: function() {
  424. wn.msgprint("Name Not Permitted");
  425. },
  426. 200: function(data) {
  427. if(data.exc) {
  428. console.log(data.exc);
  429. if(data._server_messages) wn.msgprint(data._server_messages);
  430. } else {
  431. wn.msgprint("Group Added, refreshing...");
  432. setTimeout(function() { window.location.reload(); }, 1000)
  433. }
  434. }
  435. }
  436. }).always(function() {
  437. $btn.prop("disabled",false);
  438. $control.val("");
  439. })
  440. }
  441. },
  442. update_permission: function() {
  443. var $chk = $(this);
  444. var $tr = $chk.parents("tr:first");
  445. $chk.prop("disabled", true);
  446. $.ajax({
  447. url: "/",
  448. type: "POST",
  449. data: {
  450. cmd: "webnotes.templates.website_group.settings.update_permission",
  451. profile: $tr.attr("data-profile"),
  452. perm: $chk.attr("data-perm"),
  453. value: $chk.prop("checked") ? "1" : "0",
  454. group: website.group
  455. },
  456. statusCode: {
  457. 403: function() {
  458. wn.msgprint("Not Allowed");
  459. },
  460. 200: function(data) {
  461. $chk.prop("disabled", false);
  462. if(data.exc) {
  463. $chk.prop("checked", !$chk.prop("checked"));
  464. console.log(data.exc);
  465. } else {
  466. if(!$tr.find(":checked").length) $tr.remove();
  467. }
  468. }
  469. },
  470. });
  471. },
  472. add_sitemap_permission: function(profile) {
  473. $.ajax({
  474. url: "/",
  475. type: "POST",
  476. data: {
  477. cmd: "webnotes.templates.website_group.settings.add_sitemap_permission",
  478. profile: profile,
  479. group: website.group
  480. },
  481. success: function(data) {
  482. $(".add-user-control").val("");
  483. if(data.exc) {
  484. console.log(data.exc);
  485. } else {
  486. $(data.message).prependTo($(".permission-editor tbody"));
  487. }
  488. }
  489. });
  490. },
  491. update_group_description: function() {
  492. $(".btn-update-description").prop("disabled", true);
  493. $.ajax({
  494. url: "/",
  495. type: "POST",
  496. data: {
  497. cmd: "webnotes.templates.website_group.settings.update_description",
  498. description: $(".control-description").val() || "",
  499. group: website.group
  500. },
  501. success: function(data) {
  502. window.location.reload();
  503. }
  504. }).always(function() { $(".btn-update-description").prop("disabled", false); });
  505. }
  506. });
  507. $(document).on("apply_permissions", function() {
  508. website.toggle_permitted();
  509. });