25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

342 lines
8.9 KiB

  1. frappe.provide('frappe.desktop');
  2. frappe.pages['desktop'].on_page_load = function(wrapper) {
  3. // load desktop
  4. if(!frappe.list_desktop) {
  5. frappe.desktop.set_background();
  6. }
  7. frappe.desktop.refresh(wrapper);
  8. };
  9. frappe.pages['desktop'].on_page_show = function(wrapper) {
  10. if(frappe.list_desktop) {
  11. $("body").attr("data-route", "list-desktop");
  12. }
  13. };
  14. $.extend(frappe.desktop, {
  15. refresh: function(wrapper) {
  16. if (wrapper) {
  17. this.wrapper = $(wrapper);
  18. }
  19. this.render();
  20. this.make_sortable();
  21. },
  22. render: function() {
  23. var me = this;
  24. frappe.utils.set_title(__("Desktop"));
  25. var template = frappe.list_desktop ? "desktop_list_view" : "desktop_icon_grid";
  26. var all_icons = frappe.get_desktop_icons();
  27. var explore_icon = {
  28. module_name: 'Explore',
  29. label: 'Explore',
  30. _label: __('Explore'),
  31. _id: 'Explore',
  32. _doctype: '',
  33. icon: 'octicon octicon-telescope',
  34. color: '#7578f6',
  35. link: 'modules'
  36. };
  37. explore_icon.app_icon = frappe.ui.app_icon.get_html(explore_icon);
  38. all_icons.push(explore_icon);
  39. frappe.desktop.wrapper.html(frappe.render_template(template, {
  40. // all visible icons
  41. desktop_items: all_icons,
  42. }));
  43. frappe.desktop.setup_module_click();
  44. // notifications
  45. frappe.desktop.show_pending_notifications();
  46. $(document).on("notification-update", function() {
  47. me.show_pending_notifications();
  48. });
  49. $(document).trigger("desktop-render");
  50. },
  51. render_help_messages: function(help_messages) {
  52. var wrapper = frappe.desktop.wrapper.find('.help-message-wrapper');
  53. var $help_messages = wrapper.find('.help-messages');
  54. var set_current_message = function(idx) {
  55. idx = cint(idx);
  56. wrapper.current_message_idx = idx;
  57. wrapper.find('.left-arrow, .right-arrow').addClass('disabled');
  58. wrapper.find('.help-message-item').addClass('hidden');
  59. wrapper.find('[data-message-idx="'+idx+'"]').removeClass('hidden');
  60. if(idx > 0) {
  61. wrapper.find('.left-arrow').removeClass('disabled');
  62. }
  63. if(idx < help_messages.length - 1) {
  64. wrapper.find('.right-arrow').removeClass('disabled');
  65. }
  66. }
  67. if(help_messages) {
  68. wrapper.removeClass('hidden');
  69. help_messages.forEach(function(message, i) {
  70. var $message = $('<div class="help-message-item hidden"></div>')
  71. .attr('data-message-idx', i)
  72. .html(frappe.render_template('desktop_help_message', message))
  73. .appendTo($help_messages);
  74. });
  75. set_current_message(0);
  76. wrapper.find('.close').on('click', function() {
  77. wrapper.addClass('hidden');
  78. });
  79. }
  80. wrapper.find('.left-arrow').on('click', function() {
  81. if(wrapper.current_message_idx) {
  82. set_current_message(wrapper.current_message_idx - 1);
  83. }
  84. })
  85. wrapper.find('.right-arrow').on('click', function() {
  86. if(help_messages.length > wrapper.current_message_idx + 1) {
  87. set_current_message(wrapper.current_message_idx + 1);
  88. }
  89. });
  90. },
  91. setup_module_click: function() {
  92. frappe.desktop.wiggling = false;
  93. if(frappe.list_desktop) {
  94. frappe.desktop.wrapper.on("click", ".desktop-list-item", function() {
  95. frappe.desktop.open_module($(this));
  96. });
  97. } else {
  98. frappe.desktop.wrapper.on("click", ".app-icon", function() {
  99. if ( !frappe.desktop.wiggling ) {
  100. frappe.desktop.open_module($(this).parent());
  101. }
  102. });
  103. }
  104. frappe.desktop.wrapper.on("click", ".circle", function() {
  105. var doctype = $(this).attr('data-doctype');
  106. if(doctype) {
  107. frappe.ui.notifications.show_open_count_list(doctype);
  108. }
  109. });
  110. frappe.desktop.setup_wiggle();
  111. },
  112. setup_wiggle: () => {
  113. // Wiggle, Wiggle, Wiggle.
  114. const DURATION_LONG_PRESS = 1000;
  115. // lesser the antidode, more the wiggle (like your drunk uncle)
  116. // 75 seems good to replicate the iOS feels.
  117. const WIGGLE_ANTIDODE = 75;
  118. var timer_id = 0;
  119. const $cases = frappe.desktop.wrapper.find('.case-wrapper');
  120. const $icons = frappe.desktop.wrapper.find('.app-icon');
  121. const $notis = $(frappe.desktop.wrapper.find('.circle').toArray().filter((object) => {
  122. // This hack is so bad, I should punch myself.
  123. const doctype = $(object).data('doctype');
  124. return doctype;
  125. }));
  126. const clearWiggle = () => {
  127. const $closes = $cases.find('.module-remove');
  128. $closes.hide();
  129. $notis.show();
  130. $icons.trigger('stopRumble');
  131. frappe.desktop.wiggling = false;
  132. };
  133. // initiate wiggling.
  134. $icons.jrumble({
  135. speed: WIGGLE_ANTIDODE // seems neat enough to match the iOS way
  136. });
  137. frappe.desktop.wrapper.on('mousedown', '.app-icon', () => {
  138. timer_id = setTimeout(() => {
  139. frappe.desktop.wiggling = true;
  140. // hide all notifications.
  141. $notis.hide();
  142. $cases.each((i) => {
  143. const $case = $($cases[i]);
  144. const template =
  145. `
  146. <div class="circle module-remove" style="background-color:#E0E0E0; color:#212121">
  147. <div class="circle-text">
  148. <b>
  149. &times
  150. </b>
  151. </div>
  152. </div>
  153. `;
  154. $case.append(template);
  155. const $close = $case.find('.module-remove');
  156. const name = $case.attr('title');
  157. $close.click(() => {
  158. // good enough to create dynamic dialogs?
  159. const dialog = new frappe.ui.Dialog({
  160. title: __(`Hide ${name}?`)
  161. });
  162. dialog.set_primary_action(__('Hide'), () => {
  163. frappe.call({
  164. method: 'frappe.desk.doctype.desktop_icon.desktop_icon.hide',
  165. args: { name: name },
  166. freeze: true,
  167. callback: (response) =>
  168. {
  169. if ( response.message ) {
  170. location.reload();
  171. }
  172. }
  173. })
  174. dialog.hide();
  175. clearWiggle();
  176. });
  177. // Hacks, Hacks and Hacks.
  178. var $cancel = dialog.get_close_btn();
  179. $cancel.click(() => {
  180. clearWiggle();
  181. });
  182. $cancel.html(__(`Cancel`));
  183. dialog.show();
  184. });
  185. });
  186. $icons.trigger('startRumble');
  187. }, DURATION_LONG_PRESS);
  188. });
  189. frappe.desktop.wrapper.on('mouseup mouseleave', '.app-icon', () => {
  190. clearTimeout(timer_id);
  191. });
  192. // also stop wiggling if clicked elsewhere.
  193. $('body').click((event) => {
  194. if ( frappe.desktop.wiggling ) {
  195. const $target = $(event.target);
  196. // our target shouldn't be .app-icons or .close
  197. const $parent = $target.parents('.case-wrapper');
  198. if ( $parent.length == 0 )
  199. clearWiggle();
  200. }
  201. });
  202. // end wiggle
  203. },
  204. open_module: function(parent) {
  205. var link = parent.attr("data-link");
  206. if(link) {
  207. if(link.indexOf('javascript:')===0) {
  208. eval(link.substr(11));
  209. } else if(link.substr(0, 1)==="/" || link.substr(0, 4)==="http") {
  210. window.open(link, "_blank");
  211. } else {
  212. frappe.set_route(link);
  213. }
  214. return false;
  215. } else {
  216. var module = frappe.get_module(parent.attr("data-name"));
  217. if (module && module.onclick) {
  218. module.onclick();
  219. return false;
  220. }
  221. }
  222. },
  223. make_sortable: function() {
  224. if (frappe.dom.is_touchscreen() || frappe.list_desktop) {
  225. return;
  226. }
  227. new Sortable($("#icon-grid").get(0), {
  228. onUpdate: function(event) {
  229. var new_order = [];
  230. $("#icon-grid .case-wrapper").each(function(i, e) {
  231. new_order.push($(this).attr("data-name"));
  232. });
  233. frappe.call({
  234. method: 'frappe.desk.doctype.desktop_icon.desktop_icon.set_order',
  235. args: {
  236. 'new_order': new_order,
  237. 'user': frappe.session.user
  238. },
  239. quiet: true
  240. });
  241. }
  242. });
  243. },
  244. set_background: function() {
  245. frappe.ui.set_user_background(frappe.boot.user.background_image, null,
  246. frappe.boot.user.background_style);
  247. },
  248. show_pending_notifications: function() {
  249. var modules_list = frappe.get_desktop_icons();
  250. for (var i=0, l=modules_list.length; i < l; i++) {
  251. var module = modules_list[i];
  252. var module_doctypes = frappe.boot.notification_info.module_doctypes[module.module_name];
  253. var sum = 0;
  254. if(module_doctypes) {
  255. if(frappe.boot.notification_info.open_count_doctype) {
  256. // sum all doctypes for a module
  257. for (var j=0, k=module_doctypes.length; j < k; j++) {
  258. var doctype = module_doctypes[j];
  259. sum += (frappe.boot.notification_info.open_count_doctype[doctype] || 0);
  260. }
  261. }
  262. } else if(frappe.boot.notification_info.open_count_doctype
  263. && frappe.boot.notification_info.open_count_doctype[module.module_name]!=null) {
  264. // notification count explicitly for doctype
  265. sum = frappe.boot.notification_info.open_count_doctype[module.module_name];
  266. } else if(frappe.boot.notification_info.open_count_module
  267. && frappe.boot.notification_info.open_count_module[module.module_name]!=null) {
  268. // notification count explicitly for module
  269. sum = frappe.boot.notification_info.open_count_module[module.module_name];
  270. }
  271. // if module found
  272. if(module._id.indexOf('/')===-1) {
  273. var notifier = $(".module-count-" + module._id);
  274. if(notifier.length) {
  275. notifier.toggle(sum ? true : false);
  276. var circle = notifier.find(".circle-text");
  277. var text = sum || '';
  278. if(text > 20) {
  279. text = '20+';
  280. }
  281. if(circle.length) {
  282. circle.html(text);
  283. } else {
  284. notifier.html(text);
  285. }
  286. }
  287. }
  288. }
  289. }
  290. });