25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

576 satır
16 KiB

  1. frappe.provide("frappe.setup");
  2. frappe.provide("frappe.setup.events");
  3. frappe.provide("frappe.ui");
  4. frappe.setup = {
  5. slides: [],
  6. events: {},
  7. data: {},
  8. utils: {},
  9. on: function(event, fn) {
  10. if(!frappe.setup.events[event]) {
  11. frappe.setup.events[event] = [];
  12. }
  13. frappe.setup.events[event].push(fn);
  14. },
  15. add_slide: function(slide) {
  16. frappe.setup.slides.push(slide);
  17. },
  18. run_event: function(event) {
  19. $.each(frappe.setup.events[event] || [], function(i, fn) {
  20. fn();
  21. });
  22. }
  23. }
  24. frappe.pages['setup-wizard'].on_page_load = function(wrapper) {
  25. var requires = (frappe.boot.setup_wizard_requires || []);
  26. frappe.require(requires, function() {
  27. frappe.call({
  28. method: "frappe.desk.page.setup_wizard.setup_wizard.load_languages",
  29. freeze: true,
  30. callback: function(r) {
  31. frappe.setup.data.lang = r.message;
  32. frappe.setup.run_event("before_load");
  33. var wizard_settings = {
  34. parent: wrapper,
  35. slides: frappe.setup.slides,
  36. slide_class: frappe.setup.SetupWizardSlide,
  37. unidirectional: 1,
  38. before_load: ($footer) => {
  39. $footer.find('.next-btn').removeClass('btn-default')
  40. .addClass('btn-primary');
  41. $footer.find('.text-right').prepend(
  42. $(`<a class="complete-btn btn btn-sm primary">
  43. ${__("Complete Setup")}</a>`));
  44. }
  45. }
  46. frappe.wizard = new frappe.setup.SetupWizard(wizard_settings);
  47. frappe.setup.run_event("after_load");
  48. // frappe.wizard.values = test_values_edu;
  49. let route = frappe.get_route();
  50. if(route) {
  51. frappe.wizard.show_slide(route[1]);
  52. }
  53. }
  54. });
  55. });
  56. };
  57. frappe.pages['setup-wizard'].on_page_show = function(wrapper) {
  58. if(frappe.get_route()[1]) {
  59. frappe.wizard && frappe.wizard.show_slide(frappe.get_route()[1]);
  60. }
  61. };
  62. frappe.setup.on("before_load", function() {
  63. // load slides
  64. frappe.setup.slides_settings.forEach((s) => {
  65. if(!(s.name==='user' && frappe.boot.developer_mode)) {
  66. // if not user slide with developer mode
  67. frappe.setup.add_slide(s);
  68. }
  69. });
  70. });
  71. frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides {
  72. constructor(args = {}) {
  73. super(args);
  74. $.extend(this, args);
  75. this.welcomed = true;
  76. this.page_name = "setup-wizard";
  77. frappe.set_route("setup-wizard/0");
  78. }
  79. make() {
  80. super.make();
  81. this.container.addClass("container setup-wizard-slide with-form");
  82. this.$next_btn.addClass('action');
  83. this.$complete_btn = this.$footer.find('.complete-btn').addClass('action');
  84. this.setup_keyboard_nav();
  85. }
  86. setup_keyboard_nav() {
  87. $('body').on('keydown', this.handle_enter_press.bind(this));
  88. }
  89. disable_keyboard_nav() {
  90. $('body').off('keydown', this.handle_enter_press.bind(this));
  91. }
  92. handle_enter_press(e) {
  93. if (e.which === frappe.ui.keyCode.ENTER) {
  94. var $target = $(e.target);
  95. if($target.hasClass('prev-btn')) {
  96. $target.trigger('click');
  97. } else {
  98. this.container.find('.next-btn').trigger('click');
  99. e.preventDefault();
  100. }
  101. }
  102. }
  103. before_show_slide() {
  104. if(!this.welcomed) {
  105. frappe.set_route(this.page_name);
  106. return false;
  107. }
  108. return true;
  109. }
  110. show_slide(id) {
  111. if (id === this.slides.length) {
  112. // show_slide called on last slide
  113. this.action_on_complete();
  114. return;
  115. }
  116. super.show_slide(id);
  117. frappe.set_route(this.page_name, id + "");
  118. }
  119. show_hide_prev_next(id) {
  120. super.show_hide_prev_next(id);
  121. if (id + 1 === this.slides.length){
  122. this.$next_btn.removeClass("btn-primary").hide();
  123. this.$complete_btn.addClass("btn-primary").show()
  124. .on('click', this.action_on_complete.bind(this));
  125. } else {
  126. this.$next_btn.addClass("btn-primary").show();
  127. this.$complete_btn.removeClass("btn-primary").hide();
  128. }
  129. }
  130. refresh_slides() {
  131. // For Translations, etc.
  132. if(this.in_refresh_slides || !this.current_slide.set_values()) {
  133. return;
  134. }
  135. this.in_refresh_slides = true;
  136. this.update_values();
  137. frappe.setup.slides = [];
  138. frappe.setup.run_event("before_load");
  139. frappe.setup.slides = this.get_setup_slides_filtered_by_domain();
  140. this.slides = frappe.setup.slides;
  141. frappe.setup.run_event("after_load");
  142. // re-render all slide, only remake made slides
  143. $.each(this.slide_dict, (id, slide) => {
  144. if(slide.made) {
  145. this.made_slide_ids.push(id);
  146. }
  147. });
  148. this.made_slide_ids.push(this.current_id);
  149. this.setup();
  150. this.show_slide(this.current_id);
  151. setTimeout(() => {
  152. this.container.find('.form-control').first().focus();
  153. }, 200);
  154. this.in_refresh_slides = false;
  155. }
  156. action_on_complete() {
  157. var me = this;
  158. if (!this.current_slide.set_values()) return;
  159. this.update_values();
  160. this.show_working_state();
  161. this.disable_keyboard_nav();
  162. return frappe.call({
  163. method: "frappe.desk.page.setup_wizard.setup_wizard.setup_complete",
  164. args: {args: this.values},
  165. callback: function() {
  166. me.show_setup_complete_state();
  167. if(frappe.setup.welcome_page) {
  168. localStorage.setItem("session_last_route", frappe.setup.welcome_page);
  169. }
  170. setTimeout(function() {
  171. // Reload
  172. window.location.href = '';
  173. }, 2000);
  174. setTimeout(()=> {
  175. $('body').removeClass('setup-state');
  176. }, 20000);
  177. },
  178. error: function() {
  179. var d = frappe.msgprint(__("There were errors."));
  180. d.custom_onhide = function() {
  181. $(me.parent).find('.page-card-container').remove();
  182. $('body').removeClass('setup-state');
  183. me.container.show();
  184. frappe.set_route(me.page_name, me.slides.length - 1);
  185. };
  186. }
  187. });
  188. }
  189. get_setup_slides_filtered_by_domain() {
  190. var filtered_slides = [];
  191. frappe.setup.slides.forEach(function(slide) {
  192. if(frappe.setup.domain) {
  193. var domains = slide.domains;
  194. if (domains.indexOf('all') !== -1 ||
  195. domains.indexOf(frappe.setup.domain.toLowerCase()) !== -1) {
  196. filtered_slides.push(slide);
  197. }
  198. } else {
  199. filtered_slides.push(slide);
  200. }
  201. })
  202. return filtered_slides;
  203. }
  204. show_working_state() {
  205. this.container.hide();
  206. $('body').addClass('setup-state');
  207. frappe.set_route(this.page_name);
  208. this.working_state_message = this.get_message(
  209. __("Setting Up"),
  210. __("Sit tight while your system is being setup. This may take a few moments."),
  211. true
  212. ).appendTo(this.parent);
  213. this.current_id = this.slides.length;
  214. this.current_slide = null;
  215. this.completed_state_message = this.get_message(
  216. __("Setup Complete"),
  217. __("Refreshing...")
  218. );
  219. }
  220. show_setup_complete_state() {
  221. this.working_state_message.hide();
  222. this.completed_state_message.appendTo(this.parent);
  223. }
  224. get_message(title, message="", loading=false) {
  225. const loading_html = loading
  226. ? '<div style="width:100%;height:100%" class="lds-rolling state-icon"><div></div></div>'
  227. : `<div style="width:100%;height:100%" class="state-icon">
  228. <i class="fa fa-check-circle text-success"
  229. style="font-size: 64px; margin-top: -8px;"></i>
  230. </div>`;
  231. return $(`<div class="page-card-container" data-state="setup">
  232. <div class="page-card">
  233. <div class="page-card-head">
  234. ${loading
  235. ? `<span class="indicator orange">${title}</span>`
  236. : `<span class="indicator green">${title}</span>`
  237. }
  238. </div>
  239. <p>${message}</p>
  240. <div class="state-icon-container">
  241. ${loading_html}
  242. </div>
  243. </div>
  244. </div>`);
  245. }
  246. };
  247. frappe.setup.SetupWizardSlide = class SetupWizardSlide extends frappe.ui.Slide {
  248. constructor(slide = null) {
  249. super(slide);
  250. }
  251. make() {
  252. super.make();
  253. this.set_init_values();
  254. this.reset_action_button_state();
  255. }
  256. set_init_values () {
  257. var me = this;
  258. // set values from frappe.setup.values
  259. if(frappe.wizard.values && this.fields) {
  260. this.fields.forEach(function(f) {
  261. var value = frappe.wizard.values[f.fieldname];
  262. if(value) {
  263. me.get_field(f.fieldname).set_input(value);
  264. }
  265. });
  266. }
  267. }
  268. };
  269. // Frappe slides settings
  270. // ======================================================
  271. frappe.setup.slides_settings = [
  272. {
  273. // Welcome (language) slide
  274. name: "welcome",
  275. domains: ["all"],
  276. title: __("Hello!"),
  277. icon: "fa fa-world",
  278. // help: __("Let's prepare the system for first use."),
  279. fields: [
  280. { fieldname: "language", label: __("Your Language"),
  281. fieldtype: "Select", reqd: 1}
  282. ],
  283. onload: function(slide) {
  284. this.setup_fields(slide);
  285. var language_field = slide.get_field("language");
  286. language_field.set_input(frappe.setup.data.default_language || "English");
  287. if (!frappe.setup._from_load_messages) {
  288. language_field.$input.trigger("change");
  289. }
  290. delete frappe.setup._from_load_messages;
  291. moment.locale("en");
  292. },
  293. setup_fields: function(slide) {
  294. frappe.setup.utils.setup_language_field(slide);
  295. frappe.setup.utils.bind_language_events(slide);
  296. },
  297. },
  298. {
  299. // Region slide
  300. name: 'region',
  301. domains: ["all"],
  302. title: __("Select Your Region"),
  303. icon: "fa fa-flag",
  304. // help: __("Select your Country, Time Zone and Currency"),
  305. fields: [
  306. { fieldname: "country", label: __("Your Country"), reqd:1,
  307. fieldtype: "Select" },
  308. { fieldtype: "Section Break" },
  309. { fieldname: "timezone", label: __("Time Zone"), reqd:1,
  310. fieldtype: "Select" },
  311. { fieldtype: "Column Break" },
  312. { fieldname: "currency", label: __("Currency"), reqd:1,
  313. fieldtype: "Select" }
  314. ],
  315. onload: function(slide) {
  316. if(frappe.setup.data.regional_data) {
  317. this.setup_fields(slide);
  318. } else {
  319. frappe.setup.utils.load_regional_data(slide, this.setup_fields);
  320. }
  321. },
  322. setup_fields: function(slide) {
  323. frappe.setup.utils.setup_region_fields(slide);
  324. frappe.setup.utils.bind_region_events(slide);
  325. }
  326. },
  327. {
  328. // Profile slide
  329. name: 'user',
  330. domains: ["all"],
  331. title: __("The First User: You"),
  332. icon: "fa fa-user",
  333. fields: [
  334. { "fieldtype":"Attach Image", "fieldname":"attach_user_image",
  335. label: __("Attach Your Picture"), is_private: 0, align: 'center'},
  336. { "fieldname": "full_name", "label": __("Full Name"), "fieldtype": "Data",
  337. reqd:1},
  338. { "fieldname": "email", "label": __("Email Address") + ' (' + __("Will be your login ID") + ')',
  339. "fieldtype": "Data", "options":"Email"},
  340. { "fieldname": "password", "label": __("Password"), "fieldtype": "Password" }
  341. ],
  342. // help: __('The first user will become the System Manager (you can change this later).'),
  343. onload: function(slide) {
  344. if(frappe.session.user!=="Administrator") {
  345. slide.form.fields_dict.email.$wrapper.toggle(false);
  346. slide.form.fields_dict.password.$wrapper.toggle(false);
  347. // remove password field
  348. delete slide.form.fields_dict.password;
  349. if(frappe.boot.user.first_name || frappe.boot.user.last_name) {
  350. slide.form.fields_dict.full_name.set_input(
  351. [frappe.boot.user.first_name, frappe.boot.user.last_name].join(' ').trim());
  352. }
  353. var user_image = frappe.get_cookie("user_image");
  354. var $attach_user_image = slide.form.fields_dict.attach_user_image.$wrapper;
  355. if(user_image) {
  356. $attach_user_image.find(".missing-image").toggle(false);
  357. $attach_user_image.find("img").attr("src", decodeURIComponent(user_image));
  358. $attach_user_image.find(".img-container").toggle(true);
  359. }
  360. delete slide.form.fields_dict.email;
  361. } else {
  362. slide.form.fields_dict.email.df.reqd = 1;
  363. slide.form.fields_dict.email.refresh();
  364. slide.form.fields_dict.password.df.reqd = 1;
  365. slide.form.fields_dict.password.refresh();
  366. frappe.setup.utils.load_user_details(slide, this.setup_fields);
  367. }
  368. },
  369. setup_fields: function(slide) {
  370. if(frappe.setup.data.full_name) {
  371. slide.form.fields_dict.full_name.set_input(frappe.setup.data.full_name);
  372. }
  373. if(frappe.setup.data.email) {
  374. let email = frappe.setup.data.email;
  375. slide.form.fields_dict.email.set_input(email);
  376. if (frappe.get_gravatar(email, 200)) {
  377. var $attach_user_image = slide.form.fields_dict.attach_user_image.$wrapper;
  378. $attach_user_image.find(".missing-image").toggle(false);
  379. $attach_user_image.find("img").attr("src", frappe.get_gravatar(email, 200));
  380. $attach_user_image.find(".img-container").toggle(true);
  381. }
  382. }
  383. },
  384. }
  385. ];
  386. frappe.setup.utils = {
  387. load_regional_data: function(slide, callback) {
  388. frappe.call({
  389. method:"frappe.geo.country_info.get_country_timezone_info",
  390. callback: function(data) {
  391. frappe.setup.data.regional_data = data.message;
  392. callback(slide);
  393. }
  394. });
  395. },
  396. load_user_details: function(slide, callback) {
  397. frappe.call({
  398. method: "frappe.desk.page.setup_wizard.setup_wizard.load_user_details",
  399. freeze: true,
  400. callback: function(r) {
  401. frappe.setup.data.full_name = r.message.full_name;
  402. frappe.setup.data.email = r.message.email;
  403. callback(slide);
  404. }
  405. })
  406. },
  407. setup_language_field: function(slide) {
  408. var language_field = slide.get_field("language");
  409. language_field.df.options = frappe.setup.data.lang.languages;
  410. language_field.refresh();
  411. },
  412. setup_region_fields: function(slide) {
  413. /*
  414. Set a slide's country, timezone and currency fields
  415. */
  416. var data = frappe.setup.data.regional_data;
  417. var country_field = slide.get_field('country');
  418. slide.get_input("country").empty()
  419. .add_options([""].concat(Object.keys(data.country_info).sort()));
  420. slide.get_input("currency").empty()
  421. .add_options(frappe.utils.unique([""].concat($.map(data.country_info,
  422. function(opts, country) { return opts.currency; }))).sort());
  423. slide.get_input("timezone").empty()
  424. .add_options([""].concat(data.all_timezones));
  425. // set values if present
  426. if(frappe.wizard.values.country) {
  427. country_field.set_input(frappe.wizard.values.country);
  428. } else if (data.default_country) {
  429. country_field.set_input(data.default_country);
  430. }
  431. if(frappe.wizard.values.currency) {
  432. slide.get_field("currency").set_input(frappe.wizard.values.currency);
  433. }
  434. if(frappe.wizard.values.timezone) {
  435. slide.get_field("timezone").set_input(frappe.wizard.values.timezone);
  436. }
  437. },
  438. bind_language_events: function(slide) {
  439. slide.get_input("language").unbind("change").on("change", function() {
  440. clearTimeout (slide.language_call_timeout);
  441. slide.language_call_timeout = setTimeout (() => {
  442. var lang = $(this).val() || "English";
  443. frappe._messages = {};
  444. frappe.call({
  445. method: "frappe.desk.page.setup_wizard.setup_wizard.load_messages",
  446. freeze: true,
  447. args: {
  448. language: lang
  449. },
  450. callback: function(r) {
  451. frappe.setup._from_load_messages = true;
  452. frappe.wizard.refresh_slides();
  453. }
  454. });
  455. }, 500);
  456. });
  457. },
  458. bind_region_events: function(slide) {
  459. /*
  460. Bind a slide's country, timezone and currency fields
  461. */
  462. slide.get_input("country").on("change", function() {
  463. var country = slide.get_input("country").val();
  464. var $timezone = slide.get_input("timezone");
  465. var data = frappe.setup.data.regional_data;
  466. $timezone.empty();
  467. // add country specific timezones first
  468. if(country) {
  469. var timezone_list = data.country_info[country].timezones || [];
  470. $timezone.add_options(timezone_list.sort());
  471. slide.get_field("currency").set_input(data.country_info[country].currency);
  472. slide.get_field("currency").$input.trigger("change");
  473. }
  474. // add all timezones at the end, so that user has the option to change it to any timezone
  475. $timezone.add_options([""].concat(data.all_timezones));
  476. slide.get_field("timezone").set_input($timezone.val());
  477. // temporarily set date format
  478. frappe.boot.sysdefaults.date_format = (data.country_info[country].date_format
  479. || "dd-mm-yyyy");
  480. });
  481. slide.get_input("currency").on("change", function() {
  482. var currency = slide.get_input("currency").val();
  483. if (!currency) return;
  484. frappe.model.with_doc("Currency", currency, function() {
  485. frappe.provide("locals.:Currency." + currency);
  486. var currency_doc = frappe.model.get_doc("Currency", currency);
  487. var number_format = currency_doc.number_format;
  488. if (number_format==="#.###") {
  489. number_format = "#.###,##";
  490. } else if (number_format==="#,###") {
  491. number_format = "#,###.##"
  492. }
  493. frappe.boot.sysdefaults.number_format = number_format;
  494. locals[":Currency"][currency] = $.extend({}, currency_doc);
  495. });
  496. });
  497. },
  498. };