Об общих правилах кастомизации читайте в соответствующей статье.
Чтобы убрать какие-либо вкладки (контролы для переключения режима работы) с верхнего тулбара, вам необходимо переопределить опции для 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
Сперва необходимо настроить 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;
Прежде всего вам нужно определить и запарсить необходимые ячейки часов в 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 необходимо поместить в попап, поэтому внесём некоторые правки заранее:
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();
}
}
Следующим шагом будет показ/скрытия попапа при клике по событию. Для этого вам необходимо переопределить класс по умолчанию 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:
// очищаем форму и показывает сетку событий
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
По умолчанию у виджета есть три шкалы времени: день, неделя и месяц. Однако внутренняя логика поддерживает и другие типы, которые вы можете добавить с помощью кастомизации. Давайте добавим шкалу 'quarter' (квартал).
1.Добавляем настройки для шкалы:
class CustomTimelineView extends scheduler.views["modes/timeline"] {
// массив со шкалами
GetScalesArray(type) {
if (type === "quarter") return [{
unit: "month",
format: "%F %Y"
}];
return super.GetScalesArray(type);
}
// ширина юнита (в этом случае - месяц)
GetScalesCellWidth(type) {
if (type === "quarter") return 500;
return super.GetScalesCellWidth(type);
}
}
2.Добавляем опцию 'quarter' к селектору на верхней панели:
class CustomBarView extends scheduler.views["modes/timeline/bar"] {
config() {
const ui = super.config();
const rich = ui.elements[1];
rich.options.push({
id: "quarter",
value: "Quarter"
});
return ui;
}
}
Related sample: Scheduler: adding new scale types
Нам нужно переопределить scheduler.views["modes/timeline/chart"].
1.Найдём события, которые пересекаются друг с другом:
Создайте какую-либо коллекцию, чтобы хранить в ней координаты пересечений (подойдет обычный массив):
ClearCollections() {
super.ClearCollections();
this._intersections = [];
}
Проверьте все события, если они пересекаются с теми, которые уже были обработаны:
getIntersectionDates(task) {
const intersections = [];
this._processed.forEach(obj => {
if (obj.section == task.section) {
if (this.CheckDatesIntersection(obj, task)) {
const intersection = {
start: Math.max(obj.$x, task.$x),
end: Math.min(obj.$x + obj.$w, task.$x + task.$w),
section: task.section,
};
/* здесь сохраняются все пересечения для одного и того же юнита
(чем больше событий, тем ярче цвет);
если вам это не нужно, можете добавить проверку и удалять пересечения
в те дни, где есть уже хотя бы одно событие */
intersections.push(intersection);
}
}
});
return intersections;
}
CheckDatesIntersection(a, b) {
return a.id !== b.id && b.$x < a.$x + a.$w && b.$x + b.$w > a.$x;
}
Вызовите этот метод после того, как события были обработаны перед отрисовкой:
RefreshTask(updID) {
super.RefreshTask(updID);
const t = this.GetEvent(updID);
this._intersections.push(...this.getIntersectionDates(t));
}
2.Отрисуем подсвечивание:
RenderEvents() {
super.RenderEvents();
let html = "";
const sheight = this.GetSectionHeight();
this._intersections.forEach(intersection => {
const x = intersection.start;
const x1 = intersection.end;
const y = this.Bars.getItemNode(intersection.section).offsetTop;
html += `<div class="intersection" style="top:${y}px; left:${x}px; width:${x1 -
x}px; height:${sheight}px; position:absolute;"></div>`;
});
this._DataObj.insertAdjacentHTML("afterbegin", html);
}
3.Добавим стили:
.webix_scheduler_timeline_bars .intersection,
.webix_scheduler_timeline_touch_bars .intersection {
background: #abdbe3;
pointer-events: none; /* ! важно добавить, чтобы все действия с таймлайном
были доступны там, где добавились элементы для подсветки */
}
Related sample: Scheduler: Timeline with highlighted overlaps
Наверх