Практические руководства

Об общих правилах кастомизации читайте в соответствующей статье.

Как убрать режимы работы с панели

Чтобы убрать какие-либо вкладки (контролы для переключения режима работы) с верхнего тулбара, вам необходимо переопределить опции для NavBarView. Обратите внимание, что ID вкладок должны совпадать с названиями режимов работы.

class CustomBarsView extends scheduler.views["bars/nav"] {
    config() {
        const ui = super.config();
 
        ui.options = [
            { id: "week", value: "Week" },
            { id: "month", value: "Month" },
        ];
        return ui;
    }
}

Чтобы убрать опции в компактном режиме, вам необходимо внести соответствующие изменения в NavPopupView:

class CustomNavPopupView extends scheduler.views["bars/navpopup"] {
    config() {
        const ui = super.config();
 
        const options = [
            { id: "week", value: "Week", icon: "shi-week" },
            { id: "month", value: "Month", icon: "shi-month" },
        ];
 
        ui.body.body.rows[0].data = options;
        return ui;
    }
}

Не забудьте переопределить классы с помощью свойства override:

webix.ui({
  view: "scheduler",
  override: new Map([
    [scheduler.views["bars/nav"], CustomBarsView],
    [scheduler.views["bars/navpopup"], CustomNavPopupView]
  ])
});

Related sample:  Scheduler: Limited Tabs

Как показывать только рабочие дни в режиме Week

Сперва необходимо настроить WeekView, чтобы отображать только 5 столбцов (для дней) и переписать метод GetWeek таким образом, чтобы он возвращал данные только для первых пяти дней.

class CustomWeekView extends scheduler.views["modes/week"] {
    config() {
        const ui = super.config();
        if (!this.Compact) ui.rows[2].body.cols.length = 6; // шкала + 5 дней
        return ui;
    }
    GetWeek(start, end) {
        if (!this.Compact) end = webix.Date.add(end, -2, "day");
        return super.GetWeek(start, end);
    }
}

После чего вам нужно настроить MultiDayView и WeekHeaderView, чтобы показывать только 5 ячеек:

class CustomWeekHeader extends scheduler.views["modes/week/header"] {
    config() {
        const ui = super.config();
        ui.cols[1].xCount = 5;
        return ui;
    }
}
/* и то же самое для scheduler.views["modes/week/multiday"] */

Не забудьте переопределить необходимые классы с помощью свойства override:

webix.ui({
  view: "scheduler",
  mode: "week",
  override: new Map([
    [scheduler.views["modes/week"], CustomWeekView],
    [scheduler.views["modes/week/header"], CustomWeekHeader],
    [scheduler.views["modes/week/multiday"], CustomWeekMultiDay],
  ]),
});

Related sample:  Scheduler: Working Days

Обратите внимание, что данная кастомизация будет работать только в том случае, если в вашем регионе неделя начинается с понедельника. Если же нет - укажите эту настройку заранее.

webix.Date.startOnMonday = true;

Как показывать только рабочие часы на шкалах Day/Week

Прежде всего вам нужно определить и запарсить необходимые ячейки часов в HourScale и Day Events. При необходимости вы можете увеличить высоту ячеек шкалы.

Компонент DayEvents также используется в шкале недели, поэтому для неё не потребуется дополнительных действий.

 
class CustomHours extends scheduler.views["modes/common/hourscale"] {
    config() {
        const ui = super.config();
        ui.type.height = 60;
        return ui;
    }
    ParseHours() {
        const data = [];
        for (let h = 8; h < 22; h++) {
            data.push({ id: h + "" });
        }
        this.List.parse(data);
    }
}
/* и то же самое для scheduler.views["modes/day/events"]*/

Кроме этого, если ваши данные содержат события, которые не входят в рамки рабочих часов, вы можете настроить их до отрисовки:

class CustomDayEvents extends scheduler.views["modes/day/events"] {
    /* как выше */
    config() { ... },
    ParseHours() { ... }
    // подгоняем события 
    RenderEvents() {
        const evs = this.Events;
        if (evs && evs.length) {
            for (let i = 0; i < evs.length; i++) {
                if (evs[i].start_date.getHours() < 8) {
                    evs[i].start_date.setHours(8);
                    evs[i].start_date.setMinutes(0);
                }
                // same logic for the end_date
            }
        }
 
        super.RenderEvents();
    }
}

Не забудьте переопределить необходимые классы с помощью свойства override:

webix.ui({
  view: "scheduler",
  mode: "week",
  override: new Map([
    [scheduler.views["modes/common/hourscale"], CustomHours],
    [scheduler.views["modes/day/events"], CustomDayEvents],
  ]),
});

Related sample:  Scheduler: Working Hours

Всплывающее окно с информацией о событии и широкая форма для редактирования

Этот пример показывает, как убрать правую панель и:

  • отображать небольшой попап с информацией вместо правой панели
  • открывать форму для редактирования на месте сетки событий

Изменения касаются только полноэкранного режима, компактный режим остаётся без изменений.

Подготавливаем попап

Компонент Event Info необходимо поместить в попап, поэтому внесём некоторые правки заранее:

  • укажите внутренние отступы и размеры UI элементов
  • опишите действи при клике по кнопке "Edit", чтобы оно открывало форму на месте сетки событий
class CustomInfo extends scheduler.views["event/info"] {
  // стилизация
  config() {
    this.Compact = this.getParam("compact", true);
    const ui = super.config();
    if (!this.Compact) {
      ui.body.rows[0].padding = 4;
      ui.body.rows[1].padding = 4;
      ui.body.rows[1].rows[1].inputWidth = 0;
    }
 
    return ui;
  }
  // открываем форму для редактирования
  EditEvent() {
    if (!this.Compact) {
      this.getParentView().Hide();
      this.app.show("main/event.form");
    } else super.EditEvent();
  }
}

После этого создайте класс InfoPopup с компонентом Popup, который содержит вышеупомянутый компонент Info внутри. Также опишите методы, чтобы показывать/прятать попап:

class InfoPopup extends scheduler.views.JetView {
  config() {
    return {
      view: "popup",
      width: 450,
      height: 350,
      body: CustomInfo,
    };
  }
  Show(node) {
    this.getRoot().show(node);
  }
  Hide() {
    this.getRoot().hide();
  }
}

Показываем и прячем Info попап

Следующим шагом будет показ/скрытия попапа при клике по событию. Для этого вам необходимо переопределить класс по умолчанию scheduler.views.main:

class CustomMainView extends scheduler.views.main {
  init(view) {
    super.init(view);
    this.Info = this.ui(InfoPopup);
  }
  ShowEvent(ev) {
    //"0" для новых событий, формы должна быть открыта
    if (!this.Compact) {
      if (ev.id === "0") {
        const mode = this.app.getState().mode;
        this.show(`event.form`);
      } else this.Info.Show(ev.node);
    } else super.ShowEvent(ev);
  }
  HideEvent() {
    this.Info.Hide();
    super.HideEvent();
  }
}

Подготавливаем форму для редактирования

Теперь переопределим Form View. При необходимости вы можете разбить форму на столбцы, а поле "Notes" показывать справа.

class CustomForm extends scheduler.views["event/form"] {
  config() {
    let ui = super.config();
    if (!this.Compact) {
      // textarea
      const notes = ui.body.rows[1].elements.splice(5, 1)[0];
      notes.labelPosition = "top";
      notes.height = 334;
 
      // форма с 3 столбцами
      const form = ui.body.rows[1];
      form.cols = [
        { margin: form.margin, rows: ui.body.rows[1].elements },
        { rows: [notes, {}] },
        { width: 300 },
      ];
      form.margin = 20;
      delete ui.body.rows[1].elements;
      ui.body.rows[1] = form;
 
      // bar
      ui.body.rows[0].padding.right = 335;
    }
 
    return ui;
  }
}

Теперь необходимо поправить логику FormView:

  • при клике по кнопке "Done" данные должны сохраняться, а форма - закрываться;
  • при клике по кнопке "Close", вы можете спрашивать у пользователей, сохранять ли измнения, если таковые есть;
// очищаем форму и показывает сетку событий
Back(close) {
  this.Form.clear();
  this.State.selected = null;
  if (!this.Compact)
    this.app.show(`main/modes.${this.State.mode}/event.form`);
  else super.Back(close);
}
// действие при клике по кнопке "Done" 
Done(close) {
  // сохраняем данные при создании нового события или редактировании уже существующего
  const change = this.Form.getDirtyValues();
  if (this.SubForm && this.SubForm.IsDirty()) {
    change.$recurring = this.SubForm.GetValues();
    delete change.rec_option;
  }
 
  this.UpdateEvent(change).then(() => this.Back(close));
}
// действие при клике по иконке "Close" 
Close() {
  const dirty =
        this.Form.isDirty() || (this.SubFrom && this.SubForm.IsDirty());
  // спрашивает пользователя в случае изменённых данных
  if (dirty) {
    webix
      .confirm({
      text: "Save changes?",
    })
      .then(() => this.Done(true))
      .catch(() => this.Back(true));
  } else this.Back(true);
}

Не забудьте переопределить классы по умолчанию с помощью соответствующего свойства:

webix.ui({
  view: "scheduler",
  override: new Map([
    [scheduler.views.main, CustomMainView],
    [scheduler.views["event/info"], CustomInfo],
    [scheduler.views["event/form"], CustomForm]
  ])
});

Related sample:  Scheduler: Info Window and Wide Form

Наверх