Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

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