mirror of
https://github.com/zadam/trilium.git
synced 2025-12-07 16:04:23 +01:00
Compare commits
96 Commits
fc57314905
...
4bcf209072
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4bcf209072 | ||
|
|
4b34ae3fd4 | ||
|
|
8590ff1f46 | ||
|
|
c4e2c003de | ||
|
|
eee3aa2bb4 | ||
|
|
ce9f703e0c | ||
|
|
279ccec3ab | ||
|
|
ab3852678e | ||
|
|
65f7aaeee8 | ||
|
|
7a76b9dd0b | ||
|
|
e7b7afabea | ||
|
|
c072c1fd9d | ||
|
|
1f3d9db161 | ||
|
|
62852b8978 | ||
|
|
429767e45c | ||
|
|
87d6771c47 | ||
|
|
68033580a5 | ||
|
|
8a3b6ea694 | ||
|
|
ac269bb51e | ||
|
|
1d583a2d1f | ||
|
|
cdde69cc7c | ||
|
|
9e1e300c72 | ||
|
|
797741c7d0 | ||
|
|
10f844f232 | ||
|
|
5291649c50 | ||
|
|
a1ef80f5ae | ||
|
|
d9a350a003 | ||
|
|
3b9bb98d8d | ||
|
|
87e7449da2 | ||
|
|
a2c8695a6d | ||
|
|
2f74e84777 | ||
|
|
db9591a011 | ||
|
|
e56e29fd64 | ||
|
|
06e4a8bc50 | ||
|
|
d4a1905e73 | ||
|
|
bc583b0ceb | ||
|
|
d5b8666dee | ||
|
|
905e311e42 | ||
|
|
d3d4c88b47 | ||
|
|
7cdad71a8e | ||
|
|
4e2b331ba0 | ||
|
|
f0c0c6ec67 | ||
|
|
57656efacc | ||
|
|
a8b26cbe27 | ||
|
|
1c9ffe5378 | ||
|
|
47d3bb7575 | ||
|
|
03d6cb58db | ||
|
|
5d0f64db46 | ||
|
|
76a973ac8a | ||
|
|
0491f27d55 | ||
|
|
3caa7fcfa5 | ||
|
|
bfdb3caa50 | ||
|
|
f815c2ff8d | ||
|
|
7c654903f6 | ||
|
|
27bfaba5ec | ||
|
|
c2548cb4fa | ||
|
|
086fe79dd9 | ||
|
|
e8dfce7421 | ||
|
|
c55da9de12 | ||
|
|
ed5763d89a | ||
|
|
e49912e83c | ||
|
|
0b90bf460a | ||
|
|
cf5f5476df | ||
|
|
a12ba57de7 | ||
|
|
4574a233e6 | ||
|
|
6e9ebf75ad | ||
|
|
1e720d4810 | ||
|
|
2e2c20f8a3 | ||
|
|
f1b976d4e4 | ||
|
|
071e8a0cc1 | ||
|
|
c0006e961b | ||
|
|
7754829e1a | ||
|
|
a752e75409 | ||
|
|
61a9706b6a | ||
|
|
12a510c9c8 | ||
|
|
936d274f5a | ||
|
|
42fac91aed | ||
|
|
b934045cbd | ||
|
|
b77ebedf78 | ||
|
|
3c09f27676 | ||
|
|
c545a4c685 | ||
|
|
9f0c5bf123 | ||
|
|
22a1c4cc65 | ||
|
|
dcd51d64fb | ||
|
|
92f95e7288 | ||
|
|
31cbe99224 | ||
|
|
45aad74b01 | ||
|
|
f1b8a1b7f2 | ||
|
|
4356adcdfe | ||
|
|
8c1d9c27c2 | ||
|
|
52c593c54e | ||
|
|
977615aa2b | ||
|
|
58cc1280ce | ||
|
|
eaeb2f1bb2 | ||
|
|
f1d912e4bd | ||
|
|
7c3619675a |
@ -32,6 +32,7 @@
|
|||||||
"@triliumnext/commons": "workspace:*",
|
"@triliumnext/commons": "workspace:*",
|
||||||
"@triliumnext/highlightjs": "workspace:*",
|
"@triliumnext/highlightjs": "workspace:*",
|
||||||
"@triliumnext/share-theme": "workspace:*",
|
"@triliumnext/share-theme": "workspace:*",
|
||||||
|
"@triliumnext/split.js": "workspace:*",
|
||||||
"autocomplete.js": "0.38.1",
|
"autocomplete.js": "0.38.1",
|
||||||
"bootstrap": "5.3.8",
|
"bootstrap": "5.3.8",
|
||||||
"boxicons": "2.1.4",
|
"boxicons": "2.1.4",
|
||||||
@ -60,7 +61,6 @@
|
|||||||
"preact": "10.27.2",
|
"preact": "10.27.2",
|
||||||
"react-i18next": "16.1.2",
|
"react-i18next": "16.1.2",
|
||||||
"reveal.js": "5.2.1",
|
"reveal.js": "5.2.1",
|
||||||
"split.js": "1.6.5",
|
|
||||||
"svg-pan-zoom": "3.6.2",
|
"svg-pan-zoom": "3.6.2",
|
||||||
"tabulator-tables": "6.3.1",
|
"tabulator-tables": "6.3.1",
|
||||||
"vanilla-js-wheel-zoom": "9.0.4"
|
"vanilla-js-wheel-zoom": "9.0.4"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import options from "./options.js";
|
import options from "./options.js";
|
||||||
import Split from "split.js"
|
import Split from "@triliumnext/split.js";
|
||||||
|
|
||||||
export const DEFAULT_GUTTER_SIZE = 5;
|
export const DEFAULT_GUTTER_SIZE = 5;
|
||||||
|
|
||||||
@ -46,6 +46,7 @@ function setupLeftPaneResizer(leftPaneVisible: boolean) {
|
|||||||
sizes: [leftPaneWidth, restPaneWidth],
|
sizes: [leftPaneWidth, restPaneWidth],
|
||||||
gutterSize: DEFAULT_GUTTER_SIZE,
|
gutterSize: DEFAULT_GUTTER_SIZE,
|
||||||
minSize: [150, 300],
|
minSize: [150, 300],
|
||||||
|
rtl: glob.isRtl,
|
||||||
onDragEnd: (sizes) => {
|
onDragEnd: (sizes) => {
|
||||||
leftPaneWidth = Math.round(sizes[0]);
|
leftPaneWidth = Math.round(sizes[0]);
|
||||||
options.save("leftPaneWidth", Math.round(sizes[0]));
|
options.save("leftPaneWidth", Math.round(sizes[0]));
|
||||||
@ -79,6 +80,7 @@ function setupRightPaneResizer() {
|
|||||||
sizes: [100 - rightPaneWidth, rightPaneWidth],
|
sizes: [100 - rightPaneWidth, rightPaneWidth],
|
||||||
gutterSize: DEFAULT_GUTTER_SIZE,
|
gutterSize: DEFAULT_GUTTER_SIZE,
|
||||||
minSize: [300, 180],
|
minSize: [300, 180],
|
||||||
|
rtl: glob.isRtl,
|
||||||
onDragEnd: (sizes) => {
|
onDragEnd: (sizes) => {
|
||||||
rightPaneWidth = Math.round(sizes[1]);
|
rightPaneWidth = Math.round(sizes[1]);
|
||||||
options.save("rightPaneWidth", Math.round(sizes[1]));
|
options.save("rightPaneWidth", Math.round(sizes[1]));
|
||||||
@ -99,7 +101,7 @@ function setupNoteSplitResizer(ntxIds: string[]) {
|
|||||||
let targetNtxIds: string[] | undefined;
|
let targetNtxIds: string[] | undefined;
|
||||||
for (const ntxId of ntxIds) {
|
for (const ntxId of ntxIds) {
|
||||||
targetNtxIds = findKeyByNtxId(ntxId);
|
targetNtxIds = findKeyByNtxId(ntxId);
|
||||||
if (targetNtxIds) break;
|
if (targetNtxIds) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetNtxIds) {
|
if (targetNtxIds) {
|
||||||
@ -154,6 +156,7 @@ function createSplitInstance(targetNtxIds: string[]) {
|
|||||||
const splitPanels = [...splitNoteContainer.querySelectorAll<HTMLElement>(':scope > .note-split')]
|
const splitPanels = [...splitNoteContainer.querySelectorAll<HTMLElement>(':scope > .note-split')]
|
||||||
.filter(el => targetNtxIds.includes(el.getAttribute('data-ntx-id') ?? ""));
|
.filter(el => targetNtxIds.includes(el.getAttribute('data-ntx-id') ?? ""));
|
||||||
const splitInstance = Split(splitPanels, {
|
const splitInstance = Split(splitPanels, {
|
||||||
|
rtl: glob.isRtl,
|
||||||
gutterSize: DEFAULT_GUTTER_SIZE,
|
gutterSize: DEFAULT_GUTTER_SIZE,
|
||||||
minSize: 150,
|
minSize: 150,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,9 +4,6 @@ import froca from "./froca.js";
|
|||||||
import hoistedNoteService from "./hoisted_note.js";
|
import hoistedNoteService from "./hoisted_note.js";
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string|null}
|
|
||||||
*/
|
|
||||||
async function resolveNotePath(notePath: string, hoistedNoteId = "root") {
|
async function resolveNotePath(notePath: string, hoistedNoteId = "root") {
|
||||||
const runPath = await resolveNotePathToSegments(notePath, hoistedNoteId);
|
const runPath = await resolveNotePathToSegments(notePath, hoistedNoteId);
|
||||||
|
|
||||||
|
|||||||
@ -86,6 +86,11 @@ body ::-webkit-calendar-picker-indicator {
|
|||||||
--custom-color: var(--dark-theme-custom-color);
|
--custom-color: var(--dark-theme-custom-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reference-link,
|
||||||
|
.ck-content a.reference-link > span {
|
||||||
|
color: var(--dark-theme-custom-color, inherit);
|
||||||
|
}
|
||||||
|
|
||||||
.excalidraw.theme--dark {
|
.excalidraw.theme--dark {
|
||||||
--theme-filter: invert(80%) hue-rotate(180deg) !important;
|
--theme-filter: invert(80%) hue-rotate(180deg) !important;
|
||||||
}
|
}
|
||||||
@ -101,3 +106,4 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
|
|||||||
.ck-content pre {
|
.ck-content pre {
|
||||||
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6) !important;
|
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -84,4 +84,9 @@ html {
|
|||||||
|
|
||||||
#left-pane .fancytree-node.tinted {
|
#left-pane .fancytree-node.tinted {
|
||||||
--custom-color: var(--light-theme-custom-color);
|
--custom-color: var(--light-theme-custom-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reference-link,
|
||||||
|
.ck-content a.reference-link > span {
|
||||||
|
color: var(--light-theme-custom-color, inherit);
|
||||||
}
|
}
|
||||||
@ -277,6 +277,11 @@
|
|||||||
--custom-bg-color: hsl(var(--custom-color-hue), 20%, 33%, 0.4);
|
--custom-bg-color: hsl(var(--custom-color-hue), 20%, 33%, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reference-link,
|
||||||
|
.ck-content a.reference-link > span {
|
||||||
|
color: var(--dark-theme-custom-color, inherit);
|
||||||
|
}
|
||||||
|
|
||||||
body ::-webkit-calendar-picker-indicator {
|
body ::-webkit-calendar-picker-indicator {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -666,4 +666,17 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
|
|||||||
.ck-content .table > figcaption {
|
.ck-content .table > figcaption {
|
||||||
background: var(--accented-background-color);
|
background: var(--accented-background-color);
|
||||||
color: var(--main-text-color);
|
color: var(--main-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reference link */
|
||||||
|
|
||||||
|
.ck-content a.reference-link,
|
||||||
|
.ck-content a.reference-link:hover {
|
||||||
|
/* Apply underline only to the span inside the link so it can follow the
|
||||||
|
* target note's user defined color */
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck-content a.reference-link > span {
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -353,18 +353,18 @@
|
|||||||
},
|
},
|
||||||
"sort_child_notes": {
|
"sort_child_notes": {
|
||||||
"sort_children_by": "子ノートの並び替え...",
|
"sort_children_by": "子ノートの並び替え...",
|
||||||
"sorting_criteria": "ソート基準",
|
"sorting_criteria": "並べ替えの基準",
|
||||||
"title": "タイトル",
|
"title": "タイトル",
|
||||||
"date_created": "作成日",
|
"date_created": "作成日",
|
||||||
"date_modified": "更新日",
|
"date_modified": "更新日",
|
||||||
"sorting_direction": "ソート方向",
|
"sorting_direction": "並べ替えの方向",
|
||||||
"ascending": "昇順",
|
"ascending": "昇順",
|
||||||
"descending": "降順",
|
"descending": "降順",
|
||||||
"folders": "フォルダ",
|
"folders": "フォルダ",
|
||||||
"sort_folders_at_top": "フォルダーを一番上にソートする",
|
"sort_folders_at_top": "フォルダーを上にして並べ替える",
|
||||||
"natural_sort": "自然順",
|
"natural_sort": "自然順",
|
||||||
"sort_with_respect_to_different_character_sorting": "言語や地域によって異なる文字の並べ替えや照合順序の規則に従ってソートする。",
|
"sort_with_respect_to_different_character_sorting": "言語や地域によって異なる文字の並べ替えや照合順序の規則に従って並べ替える。",
|
||||||
"sort": "ソート",
|
"sort": "並べ替え",
|
||||||
"natural_sort_language": "自然順言語",
|
"natural_sort_language": "自然順言語",
|
||||||
"the_language_code_for_natural_sort": "自然順の言語コード。例えば、中国語の場合は \"zh-CN\"。"
|
"the_language_code_for_natural_sort": "自然順の言語コード。例えば、中国語の場合は \"zh-CN\"。"
|
||||||
},
|
},
|
||||||
@ -1078,7 +1078,7 @@
|
|||||||
"sorted": "子ノートをアルファベット順に並べ替える",
|
"sorted": "子ノートをアルファベット順に並べ替える",
|
||||||
"sort_direction": "ASC(デフォルト)または DESC",
|
"sort_direction": "ASC(デフォルト)または DESC",
|
||||||
"sort_folders_first": "フォルダ(子を持つノート)を上にして並べる",
|
"sort_folders_first": "フォルダ(子を持つノート)を上にして並べる",
|
||||||
"top": "指定されたノートをその親ノートの一番上に表示します(ソートされた親ノートにのみ適用されます)",
|
"top": "指定されたノートをその親ノートの一番上に表示します(並べ替えらた親ノートにのみ適用されます)",
|
||||||
"hide_promoted_attributes": "このノートのプロモート属性を非表示にする",
|
"hide_promoted_attributes": "このノートのプロモート属性を非表示にする",
|
||||||
"read_only": "エディターは読み取り専用モードです。テキストとコードノートのみ機能します。",
|
"read_only": "エディターは読み取り専用モードです。テキストとコードノートのみ機能します。",
|
||||||
"auto_read_only_disabled": "テキスト/コードノートは、サイズが大きすぎる場合、自動的に読み取りモードに設定されます。このラベルをノートに追加することで、ノートごとにこの動作を無効にすることができます",
|
"auto_read_only_disabled": "テキスト/コードノートは、サイズが大きすぎる場合、自動的に読み取りモードに設定されます。このラベルをノートに追加することで、ノートごとにこの動作を無効にすることができます",
|
||||||
@ -1214,7 +1214,7 @@
|
|||||||
},
|
},
|
||||||
"bulk_actions": {
|
"bulk_actions": {
|
||||||
"bulk_actions": "一括操作",
|
"bulk_actions": "一括操作",
|
||||||
"affected_notes": "影響されたノート",
|
"affected_notes": "影響されるノート",
|
||||||
"include_descendants": "選択したノートの子ノートを含む",
|
"include_descendants": "選択したノートの子ノートを含む",
|
||||||
"available_actions": "利用可能なアクション",
|
"available_actions": "利用可能なアクション",
|
||||||
"chosen_actions": "選択されたアクション",
|
"chosen_actions": "選択されたアクション",
|
||||||
|
|||||||
19
apps/client/src/utils/formatters.spec.ts
Normal file
19
apps/client/src/utils/formatters.spec.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import options from "../services/options";
|
||||||
|
import { formatDateTime, normalizeLocale } from "./formatters";
|
||||||
|
|
||||||
|
describe("formatters", () => {
|
||||||
|
it("tolerates incorrect locale", () => {
|
||||||
|
options.set("formattingLocale", "cn_TW");
|
||||||
|
|
||||||
|
expect(formatDateTime(new Date())).toBeTruthy();
|
||||||
|
expect(formatDateTime(new Date(), "full", "none")).toBeTruthy();
|
||||||
|
expect(formatDateTime(new Date(), "none", "full")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("normalizes locale", () => {
|
||||||
|
expect(normalizeLocale("zh_CN")).toBe("zh-CN");
|
||||||
|
expect(normalizeLocale("cn")).toBe("zh-CN");
|
||||||
|
expect(normalizeLocale("tw")).toBe("zh-TW");
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -10,7 +10,7 @@ export function formatDateTime(date: string | Date | number | null | undefined,
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const locale = options.get("formattingLocale") || options.get("locale") || navigator.language;
|
const locale = normalizeLocale(options.get("formattingLocale") || options.get("locale") || navigator.language);
|
||||||
|
|
||||||
let parsedDate;
|
let parsedDate;
|
||||||
if (typeof date === "string" || typeof date === "number") {
|
if (typeof date === "string" || typeof date === "number") {
|
||||||
@ -26,15 +26,37 @@ export function formatDateTime(date: string | Date | number | null | undefined,
|
|||||||
|
|
||||||
if (timeStyle !== "none" && dateStyle !== "none") {
|
if (timeStyle !== "none" && dateStyle !== "none") {
|
||||||
// Format the date and time
|
// Format the date and time
|
||||||
const formatter = new Intl.DateTimeFormat(locale, { dateStyle, timeStyle });
|
try {
|
||||||
return formatter.format(parsedDate);
|
const formatter = new Intl.DateTimeFormat(locale, { dateStyle, timeStyle });
|
||||||
|
return formatter.format(parsedDate);
|
||||||
|
} catch (e) {
|
||||||
|
const formatter = new Intl.DateTimeFormat(undefined, { dateStyle, timeStyle });
|
||||||
|
return formatter.format(parsedDate);
|
||||||
|
}
|
||||||
} else if (timeStyle === "none" && dateStyle !== "none") {
|
} else if (timeStyle === "none" && dateStyle !== "none") {
|
||||||
// Format only the date
|
// Format only the date
|
||||||
return parsedDate.toLocaleDateString(locale, { dateStyle });
|
try {
|
||||||
|
return parsedDate.toLocaleDateString(locale, { dateStyle });
|
||||||
|
} catch (e) {
|
||||||
|
return parsedDate.toLocaleDateString(undefined, { dateStyle });
|
||||||
|
}
|
||||||
} else if (dateStyle === "none" && timeStyle !== "none") {
|
} else if (dateStyle === "none" && timeStyle !== "none") {
|
||||||
// Format only the time
|
// Format only the time
|
||||||
return parsedDate.toLocaleTimeString(locale, { timeStyle });
|
try {
|
||||||
|
return parsedDate.toLocaleTimeString(locale, { timeStyle });
|
||||||
|
} catch (e) {
|
||||||
|
return parsedDate.toLocaleTimeString(undefined, { timeStyle });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Incorrect state.");
|
throw new Error("Incorrect state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function normalizeLocale(locale: string) {
|
||||||
|
locale = locale.replaceAll("_", "-");
|
||||||
|
switch (locale) {
|
||||||
|
case "cn": return "zh-CN";
|
||||||
|
case "tw": return "zh-TW";
|
||||||
|
default: return locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export const LOCALE_MAPPINGS: Record<DISPLAYABLE_LOCALE_IDS, (() => Promise<{ de
|
|||||||
de: () => import("@fullcalendar/core/locales/de"),
|
de: () => import("@fullcalendar/core/locales/de"),
|
||||||
es: () => import("@fullcalendar/core/locales/es"),
|
es: () => import("@fullcalendar/core/locales/es"),
|
||||||
fr: () => import("@fullcalendar/core/locales/fr"),
|
fr: () => import("@fullcalendar/core/locales/fr"),
|
||||||
|
it: () => import("@fullcalendar/core/locales/it"),
|
||||||
cn: () => import("@fullcalendar/core/locales/zh-cn"),
|
cn: () => import("@fullcalendar/core/locales/zh-cn"),
|
||||||
tw: () => import("@fullcalendar/core/locales/zh-tw"),
|
tw: () => import("@fullcalendar/core/locales/zh-tw"),
|
||||||
ro: () => import("@fullcalendar/core/locales/ro"),
|
ro: () => import("@fullcalendar/core/locales/ro"),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type FNote from "../../entities/fnote.js";
|
|||||||
import utils from "../../services/utils.js";
|
import utils from "../../services/utils.js";
|
||||||
import EditableCodeTypeWidget from "./editable_code.js";
|
import EditableCodeTypeWidget from "./editable_code.js";
|
||||||
import TypeWidget from "./type_widget.js";
|
import TypeWidget from "./type_widget.js";
|
||||||
import Split from "split.js";
|
import Split from "@triliumnext/split.js";
|
||||||
import { DEFAULT_GUTTER_SIZE } from "../../services/resizer.js";
|
import { DEFAULT_GUTTER_SIZE } from "../../services/resizer.js";
|
||||||
import options from "../../services/options.js";
|
import options from "../../services/options.js";
|
||||||
import type { EventData } from "../../components/app_context.js";
|
import type { EventData } from "../../components/app_context.js";
|
||||||
@ -229,6 +229,7 @@ export default abstract class AbstractSplitTypeWidget extends TypeWidget {
|
|||||||
|
|
||||||
if (!this.isReadOnly) {
|
if (!this.isReadOnly) {
|
||||||
this.splitInstance = Split(elements, {
|
this.splitInstance = Split(elements, {
|
||||||
|
rtl: glob.isRtl,
|
||||||
sizes: [ 50, 50 ],
|
sizes: [ 50, 50 ],
|
||||||
direction: this.layoutOrientation,
|
direction: this.layoutOrientation,
|
||||||
gutterSize: DEFAULT_GUTTER_SIZE,
|
gutterSize: DEFAULT_GUTTER_SIZE,
|
||||||
|
|||||||
@ -33,7 +33,11 @@ function LocalizationOptions() {
|
|||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
formattingLocales: [
|
formattingLocales: [
|
||||||
...allLocales.filter(locale => locale.electronLocale)
|
...allLocales.filter(locale => {
|
||||||
|
if (!locale.electronLocale) return false;
|
||||||
|
if (locale.devOnly && !glob.isDev) return false;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import BNote from "../../becca/entities/bnote.js";
|
|
||||||
import { mapByNoteType } from "./single.js";
|
import { mapByNoteType } from "./single.js";
|
||||||
|
import { buildNote } from "../../test/becca_easy_mocking.js";
|
||||||
|
|
||||||
describe("Note type mappings", () => {
|
describe("Note type mappings", () => {
|
||||||
it("supports mermaid note", () => {
|
it("supports mermaid note", () => {
|
||||||
const note = new BNote({
|
const note = buildNote({
|
||||||
type: "mermaid",
|
type: "mermaid",
|
||||||
title: "New note"
|
title: "New note"
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export const DAYJS_LOADER: Record<LOCALE_IDS, () => Promise<typeof import("dayjs
|
|||||||
"es": () => import("dayjs/locale/es.js"),
|
"es": () => import("dayjs/locale/es.js"),
|
||||||
"fa": () => import("dayjs/locale/fa.js"),
|
"fa": () => import("dayjs/locale/fa.js"),
|
||||||
"fr": () => import("dayjs/locale/fr.js"),
|
"fr": () => import("dayjs/locale/fr.js"),
|
||||||
|
"it": () => import("dayjs/locale/it.js"),
|
||||||
"he": () => import("dayjs/locale/he.js"),
|
"he": () => import("dayjs/locale/he.js"),
|
||||||
"ja": () => import("dayjs/locale/ja.js"),
|
"ja": () => import("dayjs/locale/ja.js"),
|
||||||
"ku": () => import("dayjs/locale/ku.js"),
|
"ku": () => import("dayjs/locale/ku.js"),
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import utils from "../services/utils.js";
|
|||||||
import BNote from "../becca/entities/bnote.js";
|
import BNote from "../becca/entities/bnote.js";
|
||||||
import BAttribute from "../becca/entities/battribute.js";
|
import BAttribute from "../becca/entities/battribute.js";
|
||||||
import BBranch from "../becca/entities/bbranch.js";
|
import BBranch from "../becca/entities/bbranch.js";
|
||||||
|
import { NoteType } from "@triliumnext/commons";
|
||||||
|
|
||||||
type AttributeDefinitions = { [key in `#${string}`]: string; };
|
type AttributeDefinitions = { [key in `#${string}`]: string; };
|
||||||
type RelationDefinitions = { [key in `~${string}`]: string; };
|
type RelationDefinitions = { [key in `~${string}`]: string; };
|
||||||
@ -10,6 +11,7 @@ interface NoteDefinition extends AttributeDefinitions, RelationDefinitions {
|
|||||||
id?: string | undefined;
|
id?: string | undefined;
|
||||||
title?: string;
|
title?: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
|
type?: NoteType;
|
||||||
children?: NoteDefinition[];
|
children?: NoteDefinition[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ export function buildNote(noteDef: NoteDefinition) {
|
|||||||
const note = new BNote({
|
const note = new BNote({
|
||||||
noteId: noteDef.id ?? utils.randomString(12),
|
noteId: noteDef.id ?? utils.randomString(12),
|
||||||
title: noteDef.title ?? "New note",
|
title: noteDef.title ?? "New note",
|
||||||
type: "text",
|
type: noteDef.type ?? "text",
|
||||||
mime: "text/html",
|
mime: "text/html",
|
||||||
isProtected: false,
|
isProtected: false,
|
||||||
blobId: ""
|
blobId: ""
|
||||||
|
|||||||
@ -3,6 +3,47 @@
|
|||||||
"title": "Commencer",
|
"title": "Commencer",
|
||||||
"desktop_title": "Télécharger l'application de bureau (v{{version}})",
|
"desktop_title": "Télécharger l'application de bureau (v{{version}})",
|
||||||
"architecture": "Architecture:",
|
"architecture": "Architecture:",
|
||||||
"older_releases": "Voir les versions plus anciennes"
|
"older_releases": "Voir les versions plus anciennes",
|
||||||
|
"server_title": "Configurer un serveur pour accéder à plusieurs appareils"
|
||||||
|
},
|
||||||
|
"hero_section": {
|
||||||
|
"github": "GitHub",
|
||||||
|
"get_started": "Commencer",
|
||||||
|
"title": "Organisez vos pensées. Construisez votre base de connaissances personnelles.",
|
||||||
|
"subtitle": "Trilium est une solution open source pour la prise de notes et l'organisation de votre base de connaissances personnelle. Utilisez-la localement sur votre ordinateur ou synchronisez-la avec votre serveur auto-hébergé pour conserver vos notes où que vous soyez.",
|
||||||
|
"dockerhub": "Docker Hub",
|
||||||
|
"screenshot_alt": "Capture d'écran de l'application de bureau Trilium Notes"
|
||||||
|
},
|
||||||
|
"organization_benefits": {
|
||||||
|
"title": "Organisation",
|
||||||
|
"note_structure_title": "Structure des notes",
|
||||||
|
"note_structure_description": "Les notes peuvent être organisées hiérarchiquement. Il n'est pas nécessaire de créer des dossiers, car chaque note peut contenir des sous-notes. Une même note peut être ajoutée à plusieurs endroits de la hiérarchie.",
|
||||||
|
"attributes_title": "Noter les étiquettes et les relations",
|
||||||
|
"attributes_description": "Utilisez des relations entre les notes ou ajoutez des étiquettes pour faciliter la catégorisation. Utilisez les attributs promus pour saisir des informations structurées utilisables dans des tableaux et des tableaux de bord.",
|
||||||
|
"hoisting_title": "Espaces de travail et focalisation",
|
||||||
|
"hoisting_description": "Séparez facilement vos notes personnelles et professionnelles en les regroupant sous un espace de travail, ce qui concentre votre arborescence de notes pour afficher uniquement l'ensemble spécifique de celles-ci."
|
||||||
|
},
|
||||||
|
"productivity_benefits": {
|
||||||
|
"title": "Productivité et sécurité",
|
||||||
|
"revisions_title": "Révisions de note",
|
||||||
|
"revisions_content": "Les notes sont sauvegardées périodiquement en arrière-plan, et les révisions peuvent être utilisées pour consulter l’historique ou annuler des modifications accidentelles. Il est également possible de créer des révisions à la demande.",
|
||||||
|
"sync_title": "Synchronisation",
|
||||||
|
"sync_content": "Utilisez une instance auto-hébergée ou cloud pour synchroniser facilement vos notes sur plusieurs appareils, et pour y accéder à partir de votre téléphone mobile en utilisant un PWA.",
|
||||||
|
"protected_notes_title": "Notes protégées",
|
||||||
|
"protected_notes_content": "Protégez les informations personnelles sensibles en chiffrant les notes et en les verrouillant dans une session protégée par mot de passe.",
|
||||||
|
"jump_to_title": "Recherche rapide et commandes",
|
||||||
|
"jump_to_content": "Accédez rapidement à des notes ou commandes de l’interface dans toute la hiérarchie en recherchant leur titre, avec une correspondance approximative pour gérer les fautes de frappe ou légères variations.",
|
||||||
|
"search_title": "Recherche puissante",
|
||||||
|
"search_content": "Ou recherchez du texte à l’intérieur des notes et affinez les résultats en filtrant par note parente ou par profondeur.",
|
||||||
|
"web_clipper_title": "Web clipper",
|
||||||
|
"web_clipper_content": "Récupérez des pages Web (ou des captures d'écran) et placez-les directement dans Trilium à l'aide de l'extension de navigateur \"Web Clipper\"."
|
||||||
|
},
|
||||||
|
"note_types": {
|
||||||
|
"text_title": "Notes de texte",
|
||||||
|
"text_description": "Les notes sont éditées à l'aide d'un éditeur visuel (WYSIWYG) prenant en charge les tableaux, les images, les expressions mathématiques et les blocs de code avec coloration syntaxique. Formatez rapidement le texte grâce à une syntaxe de type Markdown ou à des commandes slash.",
|
||||||
|
"code_title": "Notes de code"
|
||||||
|
},
|
||||||
|
"faq": {
|
||||||
|
"database_question": "Où sont les données stockées?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,5 +5,30 @@
|
|||||||
"architecture": "Architectuur:",
|
"architecture": "Architectuur:",
|
||||||
"older_releases": "Bekijk oudere versies",
|
"older_releases": "Bekijk oudere versies",
|
||||||
"server_title": "Richt een server in voor toegang vanaf meerdere apparaten"
|
"server_title": "Richt een server in voor toegang vanaf meerdere apparaten"
|
||||||
|
},
|
||||||
|
"hero_section": {
|
||||||
|
"title": "Organiseer je gedachten. Bouw je persoonlijke kennisbank.",
|
||||||
|
"subtitle": "Trilium is een open-source oplossing voor notities en het organiseren van een persoonlijke kennisbank. Gebruik het lokaal op je desktop, of synchroniseer het met je zelfgehoste server om je notities overal bij de hand te hebben.",
|
||||||
|
"get_started": "Aan de slag",
|
||||||
|
"github": "GitHub",
|
||||||
|
"dockerhub": "Docker Hub",
|
||||||
|
"screenshot_alt": "Schermafbeelding van de Trilium Notes-desktopapplicatie"
|
||||||
|
},
|
||||||
|
"organization_benefits": {
|
||||||
|
"title": "Organisatie",
|
||||||
|
"note_structure_title": "Notitie structuur",
|
||||||
|
"note_structure_description": "Notities kunnen hiërarchisch worden geordend. Mappen zijn niet nodig, aangezien elke notitie subnotities kan bevatten. Een enkele notitie kan bovendien op meerdere plaatsen in de hiërarchie worden toegevoegd.",
|
||||||
|
"attributes_title": "Notitielabels en relaties",
|
||||||
|
"attributes_description": "Gebruik relaties tussen notities of voeg labels toe voor eenvoudige categorisatie. Gebruik gepromoveerde attributen om gestructureerde informatie in te voeren die kan worden gebruikt in tabellen en borden.",
|
||||||
|
"hoisting_title": "Werkruimtes en focus (hoisting)",
|
||||||
|
"hoisting_description": "Scheid eenvoudig je persoonlijke en werknotities door ze te groeperen onder een werkruimte, waarmee je de notitieboom kunt focussen op een specifieke set notities."
|
||||||
|
},
|
||||||
|
"productivity_benefits": {
|
||||||
|
"title": "Productiviteit en veiligheid",
|
||||||
|
"revisions_title": "Notitie revisies",
|
||||||
|
"revisions_content": "Notities worden periodiek op de achtergrond opgeslagen, en versies kunnen worden gebruikt om wijzigingen te bekijken of om per ongeluk gemaakte aanpassingen ongedaan te maken. Revisies kunnen ook handmatig worden aangemaakt.",
|
||||||
|
"sync_title": "Synchronisatie",
|
||||||
|
"sync_content": "Gebruik een zelfgehoste of cloudinstantie om je notities eenvoudig te synchroniseren tussen meerdere apparaten, en om er via een PWA toegang toe te krijgen op je mobiele telefoon.",
|
||||||
|
"protected_notes_title": "Beveiligde notities"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
124
docs/README-fr.md
vendored
124
docs/README-fr.md
vendored
@ -30,78 +30,80 @@ Trilium Notes est une application gratuite, open-source et multiplateforme de
|
|||||||
prise de notes hiérarchique, conçue pour créer et gérer de vastes bases de
|
prise de notes hiérarchique, conçue pour créer et gérer de vastes bases de
|
||||||
connaissances personnelles.
|
connaissances personnelles.
|
||||||
|
|
||||||
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for
|
Voir [les captures d'écran]
|
||||||
quick overview:
|
(https://triliumnext.github.io/Docs/Wiki/screenshot-tour) pour un aperçu rapide:
|
||||||
|
|
||||||
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
|
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
|
||||||
|
|
||||||
## ⏬ Download
|
## ⏬ Télécharger
|
||||||
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) –
|
- [Dernière version](https://github.com/TriliumNext/Trilium/releases/latest) –
|
||||||
stable version, recommended for most users.
|
version stable, recommandée pour la plupart des utilisateurs.
|
||||||
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) –
|
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) –
|
||||||
unstable development version, updated daily with the latest features and
|
version de développement instable, mise à jour quotidiennement avec les
|
||||||
fixes.
|
dernières fonctionnalités et corrections.
|
||||||
|
|
||||||
## 📚 Documentation
|
## 📚 Documentation
|
||||||
|
|
||||||
**Visit our comprehensive documentation at
|
**Visitez notre documentation complète sur
|
||||||
[docs.triliumnotes.org](https://docs.triliumnotes.org/)**
|
[docs.triliumnotes.org](https://docs.triliumnotes.org/)**
|
||||||
|
|
||||||
Our documentation is available in multiple formats:
|
Notre documentation est disponible sous plusieurs formats:
|
||||||
- **Online Documentation**: Browse the full documentation at
|
- ** Documentation en ligne**: Parcourez la documentation complète sur
|
||||||
[docs.triliumnotes.org](https://docs.triliumnotes.org/)
|
[docs.triliumnotes.org](https://docs.triliumnotes.org/)
|
||||||
- **In-App Help**: Press `F1` within Trilium to access the same documentation
|
- **Aide intégrée**: Appuyez sur `F1` dans Trilium pour accéder à la même
|
||||||
directly in the application
|
documentation directement dans l'application
|
||||||
- **GitHub**: Navigate through the [User
|
- **GitHub**: Naviguer dans le [Guide utilisateur]
|
||||||
Guide](./docs/User%20Guide/User%20Guide/) in this repository
|
(./docs/User%20Guide/User%20Guide/) dans ce dépôt
|
||||||
|
|
||||||
### Quick Links
|
### Liens rapides
|
||||||
- [Getting Started Guide](https://docs.triliumnotes.org/)
|
- [Guide de démarrage](https://docs.triliumnotes.org/)
|
||||||
- [Installation
|
- [Instructions
|
||||||
Instructions](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
|
d'installation](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
|
||||||
- [Docker
|
- [Configuration
|
||||||
Setup](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
|
Docker](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
|
||||||
- [Upgrading
|
- [Mise à jour de TriliumNext]
|
||||||
TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
|
(./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
|
||||||
- [Basic Concepts and
|
- [Concepts et fonctionnalités de
|
||||||
Features](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
|
base](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
|
||||||
- [Patterns of Personal Knowledge
|
- [Modèles de base de connaissances
|
||||||
Base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
|
personnelles](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
|
||||||
|
|
||||||
## 🎁 Features
|
## 🎁 Fonctionnalités
|
||||||
|
|
||||||
* Notes can be arranged into arbitrarily deep tree. Single note can be placed
|
* Les notes peuvent être organisées selon une arborescence de profondeur
|
||||||
into multiple places in the tree (see
|
arbitraire. Une même note peut être placée à plusieurs endroits de
|
||||||
[cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
|
l'arborescence (voir
|
||||||
* Rich WYSIWYG note editor including e.g. tables, images and
|
[clonage](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
|
||||||
[math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown
|
* Éditeur de notes WYSIWYG enrichi comprenant par exemple des tableaux, des
|
||||||
[autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
|
images et [des formules
|
||||||
* Support for editing [notes with source
|
mathématiques](https://triliumnext.github.io/Docs/Wiki/text-notes) avec
|
||||||
code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax
|
[formatage automatique en
|
||||||
highlighting
|
Markdown](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
|
||||||
* Fast and easy [navigation between
|
* Prise en charge de l'édition [de notes avec code
|
||||||
notes](https://triliumnext.github.io/Docs/Wiki/note-navigation), full text
|
source](https://triliumnext.github.io/Docs/Wiki/code-notes), incluant la
|
||||||
search and [note
|
coloration syntaxique
|
||||||
hoisting](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
|
* Navigation rapide et facile entre les
|
||||||
* Seamless [note
|
notes(https://triliumnext.github.io/Docs/Wiki/note-navigation), recherche en
|
||||||
versioning](https://triliumnext.github.io/Docs/Wiki/note-revisions)
|
texte intégral et [focalisation de
|
||||||
* Note [attributes](https://triliumnext.github.io/Docs/Wiki/attributes) can be
|
notes](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
|
||||||
used for note organization, querying and advanced
|
* Gestion transparente des [versions de
|
||||||
[scripting](https://triliumnext.github.io/Docs/Wiki/scripts)
|
notes](https://triliumnext.github.io/Docs/Wiki/note-revisions)
|
||||||
* UI available in English, German, Spanish, French, Romanian, and Chinese
|
* Les [attributs] de note(https://triliumnext.github.io/Docs/Wiki/attributes)
|
||||||
(simplified and traditional)
|
peuvent être utilisés pour l'organisation, l'interrogation et les [scripts]
|
||||||
* Direct [OpenID and TOTP
|
avancés(https://triliumnext.github.io/Docs/Wiki/scripts)
|
||||||
integration](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/Multi-Factor%20Authentication.md)
|
* Interface utilisateur disponible en anglais, allemand, espagnol, français,
|
||||||
for more secure login
|
roumain et chinois (simplifié et traditionnel)
|
||||||
* [Synchronization](https://triliumnext.github.io/Docs/Wiki/synchronization)
|
* [Intégration directe d'OpenID et
|
||||||
with self-hosted sync server
|
TOTP](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/Multi-Factor%20Authentication.md)
|
||||||
* there's a [3rd party service for hosting synchronisation
|
pour une connexion plus sécurisée
|
||||||
server](https://trilium.cc/paid-hosting)
|
* [Synchronisation](https://triliumnext.github.io/Docs/Wiki/synchronization)
|
||||||
* [Sharing](https://triliumnext.github.io/Docs/Wiki/sharing) (publishing) notes
|
avec un serveur de synchronisation auto-hébergé
|
||||||
to public internet
|
* il existe un [service tiers pour l'hébergement du serveur de
|
||||||
* Strong [note
|
synchronisation](https://trilium.cc/paid-hosting)
|
||||||
encryption](https://triliumnext.github.io/Docs/Wiki/protected-notes) with
|
* [Partage](https://triliumnext.github.io/Docs/Wiki/sharing) (publication) de
|
||||||
per-note granularity
|
notes sur Internet
|
||||||
|
* [Cryptage de note](https://triliumnext.github.io/Docs/Wiki/protected-notes)
|
||||||
|
fort avec granularité par note
|
||||||
* Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type
|
* Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type
|
||||||
"canvas")
|
"canvas")
|
||||||
* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and
|
* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and
|
||||||
@ -179,8 +181,8 @@ and run the `trilium` executable.
|
|||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
If your distribution is listed in the table below, use your distribution's
|
Si votre distribution est répertoriée dans le tableau ci-dessous, utilisez le
|
||||||
package.
|
package de votre distribution.
|
||||||
|
|
||||||
[](https://repology.org/project/triliumnext/versions)
|
status](https://repology.org/badge/vertical-allrepos/triliumnext.svg)](https://repology.org/project/triliumnext/versions)
|
||||||
|
|||||||
8
docs/README-nl.md
vendored
8
docs/README-nl.md
vendored
@ -20,10 +20,10 @@ releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)\
|
|||||||
[](https://hosted.weblate.org/engage/trilium/)
|
status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
|
||||||
|
|
||||||
[English](./README.md) | [Chinese (Simplified)](./docs/README-ZH_CN.md) |
|
[Engels](./README.md) [Chinees (Versimpeld)](./docs/README-ZH_CN.md) [Chinees
|
||||||
[Chinese (Traditional)](./docs/README-ZH_TW.md) | [Russian](./docs/README-ru.md)
|
(Traditioneel)](./docs/README-ZH_TW.md) [Russisch](./docs/README-ru.md)
|
||||||
| [Japanese](./docs/README-ja.md) | [Italian](./docs/README-it.md) |
|
[Japans](./docs/README-ja.md) [Italiaans](./docs/README-it.md)
|
||||||
[Spanish](./docs/README-es.md)
|
[Spaans](./docs/README-es.md)
|
||||||
|
|
||||||
Trillium Notes is een gratis en open-source, platformonafhankelijke,
|
Trillium Notes is een gratis en open-source, platformonafhankelijke,
|
||||||
hiërarchische notitie-applicatie die zich richt op het opbouwen van grote
|
hiërarchische notitie-applicatie die zich richt op het opbouwen van grote
|
||||||
|
|||||||
1
docs/Release Notes/Release Notes/v0.99.2.md
vendored
1
docs/Release Notes/Release Notes/v0.99.2.md
vendored
@ -49,6 +49,7 @@
|
|||||||
* Allow any date for first day of the week by @werererer
|
* Allow any date for first day of the week by @werererer
|
||||||
* Searches now have the _Collection Properties_ tab, to change the display mode from a list to one of the collections.
|
* Searches now have the _Collection Properties_ tab, to change the display mode from a list to one of the collections.
|
||||||
* [Clarify importing .zip structures when importing notes](https://github.com/TriliumNext/Trilium/issues/7429)
|
* [Clarify importing .zip structures when importing notes](https://github.com/TriliumNext/Trilium/issues/7429)
|
||||||
|
* [Style overhaul for the Canvas note type](https://github.com/TriliumNext/Trilium/pull/7372) by @adoriandoran
|
||||||
|
|
||||||
## 📖 Documentation
|
## 📖 Documentation
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron/rebuild": "4.0.1",
|
"@electron/rebuild": "4.0.1",
|
||||||
|
"@fast-csv/parse": "5.0.5",
|
||||||
"@playwright/test": "1.56.1",
|
"@playwright/test": "1.56.1",
|
||||||
"@triliumnext/server": "workspace:*",
|
"@triliumnext/server": "workspace:*",
|
||||||
"@types/express": "5.0.3",
|
"@types/express": "5.0.3",
|
||||||
|
|||||||
@ -17,6 +17,7 @@ const UNSORTED_LOCALES = [
|
|||||||
{ id: "en", name: "English", electronLocale: "en" },
|
{ id: "en", name: "English", electronLocale: "en" },
|
||||||
{ id: "es", name: "Español", electronLocale: "es" },
|
{ id: "es", name: "Español", electronLocale: "es" },
|
||||||
{ id: "fr", name: "Français", electronLocale: "fr" },
|
{ id: "fr", name: "Français", electronLocale: "fr" },
|
||||||
|
{ id: "it", name: "Italiano", electronLocale: "it" },
|
||||||
{ id: "ja", name: "日本語", electronLocale: "ja" },
|
{ id: "ja", name: "日本語", electronLocale: "ja" },
|
||||||
{ id: "pt_br", name: "Português (Brasil)", electronLocale: "pt_BR" },
|
{ id: "pt_br", name: "Português (Brasil)", electronLocale: "pt_BR" },
|
||||||
{ id: "pt", name: "Português (Portugal)", electronLocale: "pt_PT" },
|
{ id: "pt", name: "Português (Portugal)", electronLocale: "pt_PT" },
|
||||||
|
|||||||
19
packages/splitjs/LICENSE.txt
Normal file
19
packages/splitjs/LICENSE.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 Nathan Cahill
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
602
packages/splitjs/README.md
Normal file
602
packages/splitjs/README.md
Normal file
@ -0,0 +1,602 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img alt="Split.js" title="Split.js" src="https://rawcdn.githack.com/nathancahill/split/df1873f0c74d2da60f42e1774040651d6191b9bb/packages/splitjs/logo.svg?sanitize=true" width="430">
|
||||||
|
<br><br>
|
||||||
|
<a href="https://circleci.com/gh/nathancahill/split"><img src="https://img.shields.io/circleci/project/github/nathancahill/split/master.svg" alt="Build Status"></a>
|
||||||
|
<img src="https://img.badgesize.io/https://unpkg.com/split.js/dist/split.min.js?compression=gzip&label=size&v=1.6.0" alt="File Size">
|
||||||
|
<img src="https://badge.fury.io/js/split.js.svg" alt="npm version">
|
||||||
|
<img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="Dependencies">
|
||||||
|
<img src = "https://opencollective.com/splitjs/backers/badge.svg" alt="Backers on Open Collective"/>
|
||||||
|
<img src = "https://opencollective.com/splitjs/sponsors/badge.svg" alt="Sponsors on Open Collective"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Split.js
|
||||||
|
|
||||||
|
> 2kb unopinionated utility for resizeable split views.
|
||||||
|
|
||||||
|
- **Zero Deps**
|
||||||
|
- **Tiny:** Weights 2kb gzipped.
|
||||||
|
- **Fast:** No overhead or attached window event listeners, uses pure CSS for resizing.
|
||||||
|
- **Unopinionated:** Plays nicely with `float`, `flex` and other layouts.
|
||||||
|
- **Compatible:** Works great in IE9, early Firefox/Chrome/Safari/Opera supported too.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
- [Important Note](#important-note)
|
||||||
|
- [Options](#options)
|
||||||
|
- [Examples](#usage-examples)
|
||||||
|
- [Saving State](#saving-state)
|
||||||
|
- [Flexbox](#flex-layout)
|
||||||
|
- [API](#api)
|
||||||
|
- [CSS](#css)
|
||||||
|
- [React](#react)
|
||||||
|
- [Browser Support](#browser-support)
|
||||||
|
- [Credits](#credits)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Yarn:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ yarn add split.js
|
||||||
|
```
|
||||||
|
|
||||||
|
npm:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install --save split.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Include with a module bundler like [rollup](http://rollupjs.org/) or [webpack](https://webpack.github.io/):
|
||||||
|
|
||||||
|
```js
|
||||||
|
// using ES6 modules
|
||||||
|
import Split from 'split.js'
|
||||||
|
|
||||||
|
// using CommonJS modules
|
||||||
|
var Split = require('split.js')
|
||||||
|
```
|
||||||
|
|
||||||
|
The [UMD](https://github.com/umdjs/umd) build is also available on [unpkg](http://unpkg.com/):
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="https://unpkg.com/split.js/dist/split.min.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
or [cdnjs](https://cdnjs.com/):
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/split.js/1.6.0/split.min.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find the library on `window.Split`.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
```js
|
||||||
|
var split = Split(<HTMLElement|selector[]> elements, <options> options?)
|
||||||
|
```
|
||||||
|
|
||||||
|
| Options | Type | Default | Description |
|
||||||
|
| -------------- | --------------- | -------------- | -------------------------------------------------------- |
|
||||||
|
| `sizes` | Array | | Initial sizes of each element in percents or CSS values. |
|
||||||
|
| `minSize` | Number or Array | `100` | Minimum size of each element. |
|
||||||
|
| `maxSize` | Number or Array | `Infinity` | Maximum size of each element. |
|
||||||
|
| `expandToMin` | Boolean | `false` | Grow initial sizes to `minSize` |
|
||||||
|
| `gutterSize` | Number | `10` | Gutter size in pixels. |
|
||||||
|
| `gutterAlign` | String | `'center'` | Gutter alignment between elements. |
|
||||||
|
| `snapOffset` | Number | `30` | Snap to minimum size offset in pixels. |
|
||||||
|
| `dragInterval` | Number | `1` | Number of pixels to drag. |
|
||||||
|
| `direction` | String | `'horizontal'` | Direction to split: horizontal or vertical. |
|
||||||
|
| `cursor` | String | `'col-resize'` | Cursor to display while dragging. |
|
||||||
|
| `gutter` | Function | | Called to create each gutter element |
|
||||||
|
| `elementStyle` | Function | | Called to set the style of each element. |
|
||||||
|
| `gutterStyle` | Function | | Called to set the style of the gutter. |
|
||||||
|
| `onDrag` | Function | | Callback on drag. |
|
||||||
|
| `onDragStart` | Function | | Callback on drag start. |
|
||||||
|
| `onDragEnd` | Function | | Callback on drag end. |
|
||||||
|
|
||||||
|
## Important Note
|
||||||
|
|
||||||
|
Split.js does not set CSS beyond the minimum needed to manage the width or height of the elements.
|
||||||
|
This is by design. It makes Split.js flexible and useful in many different situations.
|
||||||
|
If you create a horizontal split, you are responsible for (likely) floating the elements and the gutter,
|
||||||
|
and setting their heights. See the [CSS](#css) section below. If your gutters are not showing up, check the applied CSS styles.
|
||||||
|
|
||||||
|
**THIS IS THE #1 QUESTION ABOUT THE LIBRARY**.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
#### sizes
|
||||||
|
|
||||||
|
An array of initial sizes of the elements, specified as percentage values. Example: Setting the initial sizes to `25%` and `75%`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
sizes: [25, 75],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### minSize. Default: `100`
|
||||||
|
|
||||||
|
An array of minimum sizes of the elements, specified as pixel values. Example: Setting the minimum sizes to `100px` and `300px`, respectively.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
minSize: [100, 300],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### maxSize. Default: `Infinity`
|
||||||
|
|
||||||
|
An array of maximum sizes of the elements, specified as pixel values. Example: Setting the maximum sizes of the first element to `500px`, and not setting a maximum size on the second element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
maxSize: [500, Infinity],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
If a number is passed instead of an array, all elements are set to the same minimum size:
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
minSize: 100,
|
||||||
|
maxSize: 500,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### expandToMin. Default: `false`
|
||||||
|
|
||||||
|
When the split is created, if `expandToMin` is `true`, the minSize for each element overrides the percentage value from the `sizes` option.
|
||||||
|
Example: The first element (`#one`) is set to 25% width of the parent container. However, it's `minSize` is `300px`. Using `expandToMin: true` means that
|
||||||
|
the first element will always load at at least `300px`, even if `25%` were smaller.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
sizes: [25, 75],
|
||||||
|
minSize: [300, 100],
|
||||||
|
expandToMin: true,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### gutterSize. Default: `10`
|
||||||
|
|
||||||
|
Gutter size in pixels. Example: Setting the gutter size to `20px`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
gutterSize: 20,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### gutterAlign. Default: `'center'`
|
||||||
|
|
||||||
|
Possible options are `'start'`, `'end'` and `'center'`. Determines how the gutter aligns between the two elements.
|
||||||
|
`'start'` shrinks the first element to fit the gutter, `'end'` shrinks the second element to fit the gutter and `'center'` shrinks both
|
||||||
|
elements by the same amount so the gutter sits between. Added in v1.5.3.
|
||||||
|
|
||||||
|
Example: move gutter to the side of the second element:
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
gutterAlign: 'end',
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### snapOffset. Default: `30`
|
||||||
|
|
||||||
|
Snap to minimum size at this offset in pixels. Example: Set to `0` to disable to snap effect.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
snapOffset: 0,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### dragInterval. Default: `1`
|
||||||
|
|
||||||
|
Drag this number of pixels at a time. Defaults to `1` for smooth dragging, but can be set to a pixel value to
|
||||||
|
give more control over the resulting sizes. Works particularly well when the `gutterSize` is set to the same size.
|
||||||
|
Added in v1.5.3. Example: Drag 20px at a time:
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
dragInterval: 20,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### direction. Default: `'horizontal'`
|
||||||
|
|
||||||
|
Direction to split in. Can be `'vertical'` or `'horizontal'`. Determines which CSS properties are applied (ie. width/height) to each element and gutter. Example: split vertically:
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
direction: 'vertical',
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### cursor. Default: `'col-resize'`
|
||||||
|
|
||||||
|
Cursor to show on the gutter (also applied to the body on dragging to prevent flickering). Defaults to `'col-resize'`for `direction: 'horizontal'` and `'row-resize'` for `direction: 'vertical'`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
direction: 'vertical',
|
||||||
|
cursor: 'row-resize',
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### gutter
|
||||||
|
|
||||||
|
Optional function called to create each gutter element. The signature looks like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(index, direction, pairElement) => HTMLElement
|
||||||
|
```
|
||||||
|
|
||||||
|
Defaults to creating a `div` with `class="gutter gutter-horizontal"` or `class="gutter gutter-vertical"`, depending on the direction. The default gutter function looks like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(index, direction) => {
|
||||||
|
const gutter = document.createElement('div')
|
||||||
|
gutter.className = `gutter gutter-${direction}`
|
||||||
|
return gutter
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned element is then inserted into the DOM, and it's width or height are set. This option can be used to clone an existing DOM element, or to create a new element with custom styles.
|
||||||
|
|
||||||
|
Returning a falsey value like `null` or `false` will not insert a gutter. This behavior was added in v1.4.1.
|
||||||
|
An additional argument, `pairElement`, is passed to the gutter function: this is the DOM element after (to the right or below) the gutter. This argument was added in v1.4.1.
|
||||||
|
|
||||||
|
This final argument makes it easy to return the gutter that has already been created, for example, if `split.destroy()` was called with the option to preserve the gutters.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(index, direction, pairElement) => pairElement.previousSibling
|
||||||
|
```
|
||||||
|
|
||||||
|
#### elementStyle
|
||||||
|
|
||||||
|
Optional function called setting the CSS style of the elements. The signature looks like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(dimension, elementSize, gutterSize, index) => Object
|
||||||
|
```
|
||||||
|
|
||||||
|
Dimension will be a string, `'width'` or `'height'`, and can be used in the return style. `elementSize` is the target percentage value of the element, and `gutterSize` is the target pixel value of the gutter.
|
||||||
|
|
||||||
|
It should return an object with CSS properties to apply to the element. For horizontal splits, the return object looks like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
'width': 'calc(50% - 5px)'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A vertical split style would look like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
'height': 'calc(50% - 5px)'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You might use this function if you're using a different layout like flex (see [Flex Layout](#flex-layout)).
|
||||||
|
Flex styles for a horizontal split could return an object like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
'flex-basis': 'calc(50% - 5px)'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### gutterStyle
|
||||||
|
|
||||||
|
Optional function called when setting the CSS style of the gutters. The signature looks like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(dimension, gutterSize, index) => Object
|
||||||
|
```
|
||||||
|
|
||||||
|
Dimension is a string, either `'width'` or `'height'`, and `gutterSize` is a pixel value representing the width of the gutter.
|
||||||
|
|
||||||
|
It should return a similar object as `elementStyle`, an object with CSS properties to apply to the gutter. Since gutters have fixed widths, it will generally look like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
'width': '10px'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Both `elementStyle` and `gutterStyle` are called continously while dragging, so don't do anything besides return the style object in these functions. Both of these functions should be _pure_, returning the same values for the same inputs and not modifying any external state.
|
||||||
|
|
||||||
|
#### onDrag, onDragStart, onDragEnd
|
||||||
|
|
||||||
|
Callbacks that can be added on drag (fired continously), drag start and drag end. If doing more than basic operations in `onDrag`, add a debounce function to rate limit the callback.
|
||||||
|
|
||||||
|
`onDrag`, `onDragStart` and `onDragEnd` are passed the initial and final sizes of the split since it's a common pattern to access the sizes this way.
|
||||||
|
|
||||||
|
Their function signature looks like this, where `sizes` is an array of percentage values like returned by `getSizes()`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
sizes => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
Reference HTML for examples. Gutters are inserted automatically:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div>
|
||||||
|
<div id="one">content one</div>
|
||||||
|
<div id="two">content two</div>
|
||||||
|
<div id="three">content three</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
A split with two elements, starting at `25%` and `75%` wide, with `200px` minimum width.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
sizes: [25, 75],
|
||||||
|
minSize: 200,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
A split with three elements, starting with even (default) widths and minimum widths set to `100px`, `100px` and `300px`, respectively.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two', '#three'], {
|
||||||
|
minSize: [100, 100, 300],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
A vertical split with two elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#one', '#two'], {
|
||||||
|
direction: 'vertical',
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Saving State
|
||||||
|
|
||||||
|
Use local storage to save the most recent state:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var sizes = localStorage.getItem('split-sizes')
|
||||||
|
|
||||||
|
if (sizes) {
|
||||||
|
sizes = JSON.parse(sizes)
|
||||||
|
} else {
|
||||||
|
sizes = [50, 50] // default sizes
|
||||||
|
}
|
||||||
|
|
||||||
|
var split = Split(['#one', '#two'], {
|
||||||
|
sizes: sizes,
|
||||||
|
onDragEnd: function (sizes) {
|
||||||
|
localStorage.setItem('split-sizes', JSON.stringify(sizes))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flex Layout
|
||||||
|
|
||||||
|
Flex layout is supported easily by adding a `display: flex` to the parent element. The `width` or `height` CSS values
|
||||||
|
assigned by default by Split.js work well with flex.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div id="flex">
|
||||||
|
<div id="flex-1"></div>
|
||||||
|
<div id="flex-2"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
And CSS style like this:
|
||||||
|
|
||||||
|
```css
|
||||||
|
#flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more complicated flex layouts, the `elementStyle` and `gutterStyle` can be used to set flex-basis:
|
||||||
|
|
||||||
|
```js
|
||||||
|
Split(['#flex-1', '#flex-2'], {
|
||||||
|
elementStyle: function (dimension, size, gutterSize) {
|
||||||
|
return {
|
||||||
|
'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gutterStyle: function (dimension, gutterSize) {
|
||||||
|
return {
|
||||||
|
'flex-basis': gutterSize + 'px',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
Split.js returns an instance with a couple of functions. The instance is returned on creation:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var instance = Split([], ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `.setSizes([])`
|
||||||
|
|
||||||
|
setSizes behaves the same as the `sizes` configuration option, passing an array of percentages. It updates the sizes of the elements in the split. Added in v1.1.0:
|
||||||
|
|
||||||
|
```js
|
||||||
|
instance.setSizes([25, 75])
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `.getSizes()`
|
||||||
|
|
||||||
|
getSizes returns an array of percents, suitable for using with `setSizes` or creation. Not supported in IE8. Added in v1.1.2:
|
||||||
|
|
||||||
|
```js
|
||||||
|
instance.getSizes() > [25, 75]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `.collapse(index)`
|
||||||
|
|
||||||
|
collapse changes the size of element at `index` to it's `minSize`. Every element except the last is collapsed towards the front (left or top). The last is collapsed towards the back. Not supported in IE8. Added in v1.1.0:
|
||||||
|
|
||||||
|
```js
|
||||||
|
instance.collapse(0)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `.destroy(preserveStyles? = false, preserveGutters? = false)`
|
||||||
|
|
||||||
|
Destroy the instance. It removes the gutter elements, and the size CSS styles Split.js set. Added in v1.1.1.
|
||||||
|
Passing `preserveStyles = true` does not remove the CSS styles. Option added in v1.4.0.
|
||||||
|
Passing `preserveGutters = true` does not remove the gutter elements. Option added in v1.4.1.
|
||||||
|
|
||||||
|
```js
|
||||||
|
instance.destroy()
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSS
|
||||||
|
|
||||||
|
In being non-opionionated, the only CSS Split.js sets is the widths or heights of the elements. Everything else is left up to you. You must set the elements and gutter heights when using horizontal mode. The gutters will not be visible if their height is 0px. Here's some basic CSS to style the gutters with, although it's not required. Both grip images are included in this repo:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.gutter {
|
||||||
|
background-color: #eee;
|
||||||
|
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gutter.gutter-horizontal {
|
||||||
|
background-image: url('grips/vertical.png');
|
||||||
|
cursor: col-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gutter.gutter-vertical {
|
||||||
|
background-image: url('grips/horizontal.png');
|
||||||
|
cursor: row-resize;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The grip images are small files and can be included with base64 instead:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.gutter.gutter-vertical {
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=');
|
||||||
|
}
|
||||||
|
|
||||||
|
.gutter.gutter-horizontal {
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Split.js also works best when the elements are sized using `border-box`. The `split` class would have to be added manually to apply these styles:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.split {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And for horizontal splits, make sure the layout allows elements (including gutters) to be displayed side-by-side. Floating the elements is one option:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.split,
|
||||||
|
.gutter.gutter-horizontal {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you use floats, set the height of the elements including the gutters. The gutters will not be visible otherwise if the height is set to 0px.
|
||||||
|
|
||||||
|
```css
|
||||||
|
.split,
|
||||||
|
.gutter.gutter-horizontal {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Overflow can be handled as well, to get scrolling within the elements:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.split {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## React
|
||||||
|
|
||||||
|
**[React Split](https://github.com/nathancahill/split/tree/master/packages/react-split)** - Thin wrapper component for Split.js.
|
||||||
|
|
||||||
|
## Browser Support
|
||||||
|
|
||||||
|
This library uses [CSS calc()](https://developer.mozilla.org/en-US/docs/Web/CSS/calc#AutoCompatibilityTable), [CSS box-sizing](https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing#AutoCompatibilityTable) and [JS getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#AutoCompatibilityTable). These features are supported in the following browsers:
|
||||||
|
|
||||||
|
| <img src="http://i.imgur.com/dJC1GUv.png" width="48px" height="48px" alt="Chrome logo"> | <img src="http://i.imgur.com/o1m5RcQ.png" width="48px" height="48px" alt="Firefox logo"> | <img src="http://i.imgur.com/8h3iz5H.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="http://i.imgur.com/iQV4nmJ.png" width="48px" height="48px" alt="Opera logo"> | <img src="http://i.imgur.com/j3tgNKJ.png" width="48px" height="48px" alt="Safari logo"> | [<img src="https://i.imgur.com/29eVTCg.png" height="28px" alt="Sauce Labs">](https://saucelabs.com) |
|
||||||
|
| :-------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------- |
|
||||||
|
| 22+ ✔ | 6+ ✔ | 9+ ✔ | 15+ ✔ | 6.2+ ✔ | Sponsored ✔ |
|
||||||
|
|
||||||
|
Cross-browser Testing Platform and Open Source <3 Provided by [Sauce Labs](https://saucelabs.com).
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||||
|
<a href="graphs/contributors"><img src="https://opencollective.com/splitjs/contributors.svg?width=890&button=false" /></a>
|
||||||
|
|
||||||
|
### Backers
|
||||||
|
|
||||||
|
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/splitjs#backer)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/splitjs#backers" target="_blank"><img src="https://opencollective.com/splitjs/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
### Sponsors
|
||||||
|
|
||||||
|
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/splitjs#sponsor)]
|
||||||
|
|
||||||
|
[<img src="https://i.imgur.com/29eVTCg.png" height="28px" alt="Sauce Labs">](https://saucelabs.com)
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/0/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/0/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/1/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/2/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/3/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/4/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/5/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/6/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/7/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/8/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/splitjs/sponsor/9/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/9/avatar.svg"></a>
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Nathan Cahill
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
BIN
packages/splitjs/grips/horizontal.png
Normal file
BIN
packages/splitjs/grips/horizontal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 B |
BIN
packages/splitjs/grips/vertical.png
Normal file
BIN
packages/splitjs/grips/vertical.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 91 B |
100
packages/splitjs/index.d.ts
vendored
Normal file
100
packages/splitjs/index.d.ts
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// Type definitions for Split.js
|
||||||
|
// Project: https://github.com/nathancahill/split/tree/master/packages/splitjs
|
||||||
|
// Definitions by: Ilia Choly <https://github.com/icholy>
|
||||||
|
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||||
|
// TypeScript Version: 2.1
|
||||||
|
|
||||||
|
// Global variable outside module loader
|
||||||
|
export as namespace Split
|
||||||
|
|
||||||
|
// Module loader
|
||||||
|
export = Split
|
||||||
|
|
||||||
|
declare function Split(
|
||||||
|
elements: Array<string | HTMLElement>,
|
||||||
|
options?: Split.Options,
|
||||||
|
): Split.Instance
|
||||||
|
|
||||||
|
declare namespace Split {
|
||||||
|
type Partial<T> = { [P in keyof T]?: T[P] }
|
||||||
|
type CSSStyleDeclarationPartial = Partial<CSSStyleDeclaration>
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
// Initial sizes of each element in percents or CSS values.
|
||||||
|
sizes?: number[]
|
||||||
|
|
||||||
|
// Minimum size of each element.
|
||||||
|
minSize?: number | number[]
|
||||||
|
|
||||||
|
// Maximum size of each element.
|
||||||
|
maxSize?: number | number[]
|
||||||
|
|
||||||
|
expandToMin?: boolean
|
||||||
|
|
||||||
|
// Gutter size in pixels.
|
||||||
|
gutterSize?: number
|
||||||
|
|
||||||
|
gutterAlign?: string
|
||||||
|
|
||||||
|
// Snap to minimum size offset in pixels.
|
||||||
|
snapOffset?: number | number[]
|
||||||
|
|
||||||
|
dragInterval?: number
|
||||||
|
|
||||||
|
// Direction to split: horizontal or vertical.
|
||||||
|
direction?: 'horizontal' | 'vertical'
|
||||||
|
|
||||||
|
// If the UI is right-to-left. Affects the drag direction.
|
||||||
|
rtl?: boolean
|
||||||
|
|
||||||
|
// Cursor to display while dragging.
|
||||||
|
cursor?: string
|
||||||
|
|
||||||
|
// Callback on drag.
|
||||||
|
onDrag?(sizes: number[]): void
|
||||||
|
|
||||||
|
// Callback on drag start.
|
||||||
|
onDragStart?(sizes: number[]): void
|
||||||
|
|
||||||
|
// Callback on drag end.
|
||||||
|
onDragEnd?(sizes: number[]): void
|
||||||
|
|
||||||
|
// Called to create each gutter element
|
||||||
|
gutter?(
|
||||||
|
index: number,
|
||||||
|
direction: 'horizontal' | 'vertical',
|
||||||
|
): HTMLElement
|
||||||
|
|
||||||
|
// Called to set the style of each element.
|
||||||
|
elementStyle?(
|
||||||
|
dimension: 'width' | 'height',
|
||||||
|
elementSize: number,
|
||||||
|
gutterSize: number,
|
||||||
|
index: number,
|
||||||
|
): CSSStyleDeclarationPartial
|
||||||
|
|
||||||
|
// Called to set the style of the gutter.
|
||||||
|
gutterStyle?(
|
||||||
|
dimension: 'width' | 'height',
|
||||||
|
gutterSize: number,
|
||||||
|
index: number,
|
||||||
|
): CSSStyleDeclarationPartial
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Instance {
|
||||||
|
// setSizes behaves the same as the sizes configuration option, passing an array of percents or CSS values.
|
||||||
|
// It updates the sizes of the elements in the split.
|
||||||
|
setSizes(sizes: number[]): void
|
||||||
|
|
||||||
|
// getSizes returns an array of percents, suitable for using with setSizes or creation.
|
||||||
|
getSizes(): number[]
|
||||||
|
|
||||||
|
// collapse changes the size of element at index to 0.
|
||||||
|
// Every element except the last is collapsed towards the front (left or top).
|
||||||
|
// The last is collapsed towards the back.
|
||||||
|
collapse(index: number): void
|
||||||
|
|
||||||
|
// Destroy the instance. It removes the gutter elements, and the size CSS styles Split.js set.
|
||||||
|
destroy(preserveStyles?: boolean, preserveGutters?: boolean): void
|
||||||
|
}
|
||||||
|
}
|
||||||
51
packages/splitjs/karma.conf.js
Normal file
51
packages/splitjs/karma.conf.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module.exports = config => {
|
||||||
|
config.set({
|
||||||
|
customLaunchers: {
|
||||||
|
// latest firefox, chrome, safari
|
||||||
|
sl_firefox_latest: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'firefox',
|
||||||
|
platform: 'Windows 10',
|
||||||
|
version: 'latest',
|
||||||
|
},
|
||||||
|
sl_chrome_latest: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'chrome',
|
||||||
|
platform: 'Windows 10',
|
||||||
|
version: 'latest',
|
||||||
|
},
|
||||||
|
sl_safari: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'safari',
|
||||||
|
platform: 'macOS 10.15',
|
||||||
|
version: 'latest',
|
||||||
|
},
|
||||||
|
|
||||||
|
// latest edge
|
||||||
|
sl_edge: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'MicrosoftEdge',
|
||||||
|
platform: 'Windows 10',
|
||||||
|
version: 'latest',
|
||||||
|
},
|
||||||
|
// ie 11
|
||||||
|
sl_ie_11: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'internet explorer',
|
||||||
|
platform: 'Windows 10',
|
||||||
|
version: 'latest',
|
||||||
|
},
|
||||||
|
// ie 10
|
||||||
|
sl_ie_10: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'internet explorer',
|
||||||
|
platform: 'Windows 7',
|
||||||
|
version: '10.0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
frameworks: ['jasmine'],
|
||||||
|
browsers: ['FirefoxHeadless', 'ChromeHeadless'],
|
||||||
|
singleRun: true,
|
||||||
|
files: ['dist/split.js', 'test/split.spec.js'],
|
||||||
|
})
|
||||||
|
}
|
||||||
1
packages/splitjs/logo.svg
Normal file
1
packages/splitjs/logo.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 416 139" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M295 109.488V95.66c3.555 3.164 7.227 5.537 11.016 7.12 3.79 1.58 7.714 2.372 11.777 2.372 5.586 0 9.482-1.455 11.69-4.365 2.206-2.91 3.31-8.33 3.31-16.26V35.543H310.47v-9.96h34.16v58.944c0 11.016-2.062 18.81-6.183 23.38-4.12 4.57-11.006 6.855-20.654 6.855-3.75 0-7.48-.43-11.19-1.29-3.712-.86-7.58-2.187-11.603-3.984zM410.156 28.57v12.012c-3.594-2.305-7.197-4.043-10.81-5.215-3.614-1.172-7.256-1.758-10.928-1.758-5.586 0-10 1.298-13.242 3.896-3.242 2.598-4.863 6.103-4.863 10.517 0 3.868 1.064 6.817 3.193 8.848 2.13 2.032 6.103 3.732 11.924 5.1l6.21 1.405c8.204 1.914 14.18 4.922 17.93 9.023 3.75 4.102 5.625 9.688 5.625 16.758 0 8.32-2.578 14.668-7.734 19.043-5.155 4.374-12.655 6.562-22.5 6.562-4.1 0-8.222-.44-12.362-1.32-4.14-.878-8.3-2.196-12.48-3.954V96.89c4.49 2.852 8.74 4.942 12.743 6.27 4.005 1.328 8.038 1.992 12.1 1.992 5.978 0 10.626-1.338 13.946-4.013 3.32-2.677 4.98-6.417 4.98-11.222 0-4.375-1.142-7.715-3.427-10.02-2.286-2.304-6.26-4.082-11.925-5.332l-6.328-1.464c-8.125-1.836-14.023-4.61-17.695-8.32-3.672-3.712-5.508-8.692-5.508-14.942 0-7.813 2.627-14.072 7.88-18.78 5.255-4.707 12.237-7.06 20.948-7.06 3.36 0 6.895.38 10.606 1.143 3.71.76 7.617 1.904 11.718 3.427zM51.152 28.57v12.012c-3.593-2.305-7.197-4.043-10.81-5.215-3.614-1.172-7.256-1.758-10.928-1.758-5.586 0-10 1.298-13.242 3.896-3.242 2.598-4.863 6.103-4.863 10.517 0 3.868 1.063 6.817 3.192 8.848 2.13 2.032 6.103 3.732 11.924 5.1l6.21 1.405c8.204 1.914 14.18 4.922 17.93 9.023 3.75 4.102 5.625 9.688 5.625 16.758 0 8.32-2.577 14.668-7.733 19.043-5.156 4.374-12.656 6.562-22.5 6.562-4.102 0-8.223-.44-12.363-1.32-4.14-.878-8.3-2.196-12.48-3.954V96.89c4.49 2.852 8.74 4.942 12.743 6.27 4.004 1.328 8.038 1.992 12.1 1.992 5.977 0 10.625-1.338 13.945-4.013 3.32-2.677 4.98-6.417 4.98-11.222 0-4.375-1.142-7.715-3.427-10.02-2.285-2.304-6.26-4.082-11.924-5.332l-6.327-1.464c-8.125-1.836-14.023-4.61-17.695-8.32C1.836 61.07 0 56.09 0 49.84c0-7.813 2.627-14.072 7.88-18.78C13.136 26.354 20.118 24 28.83 24c3.36 0 6.895.38 10.606 1.143 3.71.76 7.617 1.904 11.718 3.427zm26.328 6.74v32.87h13.71c5.47 0 9.738-1.446 12.804-4.336 3.067-2.89 4.6-6.934 4.6-12.13 0-5.194-1.524-9.228-4.57-12.1-3.047-2.87-7.325-4.305-12.833-4.305H77.48zM65.645 25.58H91.19c9.767 0 17.17 2.217 22.208 6.65 5.04 4.434 7.56 10.928 7.56 19.483 0 8.633-2.51 15.156-7.53 19.57-5.02 4.414-12.432 6.62-22.237 6.62H77.48v35.157H65.645v-87.48zm63.3 0h11.895v77.52h42.246v9.96h-54.14v-87.48z" fill="#34495E"/><path d="M207 6v127" stroke="#34495E" stroke-width="12" stroke-linecap="square"/><path d="M244.795 68.91l-11.088-11.087c-.55-.55-1.2-.823-1.95-.823s-1.4.274-1.95.823c-.547.548-.82 1.198-.82 1.95v5.543h-44.354v-5.544c0-.75-.275-1.4-.824-1.95-.55-.548-1.2-.822-1.95-.822s-1.4.274-1.95.823L168.824 68.91c-.55.55-.823 1.2-.823 1.95s.274 1.4.823 1.95l11.088 11.087c.55.548 1.2.823 1.95.823s1.4-.275 1.95-.823c.548-.548.823-1.198.823-1.95v-5.544h44.353v5.545c0 .75.274 1.4.822 1.95.55.547 1.2.822 1.95.822s1.4-.275 1.95-.823l11.087-11.088c.55-.55.823-1.2.823-1.95s-.274-1.4-.823-1.95z" fill="#34495E" fill-rule="nonzero"/><path fill="#34495E" d="M285.14 113.48h-11.894V35.96H231V26h54.14"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
48
packages/splitjs/package.json
Normal file
48
packages/splitjs/package.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "@triliumnext/split.js",
|
||||||
|
"version": "1.6.5",
|
||||||
|
"description": "2kb unopinionated utility for resizeable split views",
|
||||||
|
"main": "src/split.js",
|
||||||
|
"types": "index.d.ts",
|
||||||
|
"repository": "https://github.com/nathancahill/split",
|
||||||
|
"keywords": [
|
||||||
|
"css",
|
||||||
|
"split",
|
||||||
|
"flexbox",
|
||||||
|
"tiny",
|
||||||
|
"split-layout"
|
||||||
|
],
|
||||||
|
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://split.js.org/",
|
||||||
|
"scripts": {
|
||||||
|
"test": "pnpm build && karma start",
|
||||||
|
"prepublish": "rollup -c",
|
||||||
|
"build": "rollup -c && npm run size",
|
||||||
|
"watch": "rollup -cw",
|
||||||
|
"size": "echo \"gzip size: $(gzip-size --raw $npm_package_minified_main) bytes\"",
|
||||||
|
"saucelabs": "yarn run test --browsers sl_firefox_latest,sl_chrome_latest,sl_safari,sl_edge,sl_ie_11,sl_ie_10"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.d.ts",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"browserslist": [
|
||||||
|
"Chrome >= 22",
|
||||||
|
"Firefox >= 6",
|
||||||
|
"Opera >= 15",
|
||||||
|
"Safari >= 6.2",
|
||||||
|
"IE >= 9"
|
||||||
|
],
|
||||||
|
"collective": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/splitjs"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-buble": "1.0.3",
|
||||||
|
"karma": "6.4.4",
|
||||||
|
"karma-chrome-launcher": "3.2.0",
|
||||||
|
"karma-firefox-launcher": "2.1.3",
|
||||||
|
"karma-jasmine": "5.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
25
packages/splitjs/rollup.config.mjs
Normal file
25
packages/splitjs/rollup.config.mjs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import buble from '@rollup/plugin-buble'
|
||||||
|
import pkg from "./package.json" with { type: "json" };
|
||||||
|
|
||||||
|
const output = {
|
||||||
|
format: 'umd',
|
||||||
|
file: "dist/split.js",
|
||||||
|
name: 'Split',
|
||||||
|
sourcemap: false,
|
||||||
|
banner: `/*! Split.js - v${pkg.version} */\n`
|
||||||
|
}
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
input: 'src/split.js',
|
||||||
|
output: [
|
||||||
|
output,
|
||||||
|
{
|
||||||
|
file: "dist/split.min.js",
|
||||||
|
format: 'esm',
|
||||||
|
sourcemap: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
plugins: [buble()],
|
||||||
|
}
|
||||||
|
]
|
||||||
769
packages/splitjs/src/split.js
Normal file
769
packages/splitjs/src/split.js
Normal file
@ -0,0 +1,769 @@
|
|||||||
|
// The programming goals of Split.js are to deliver readable, understandable and
|
||||||
|
// maintainable code, while at the same time manually optimizing for tiny minified file size,
|
||||||
|
// browser compatibility without additional requirements
|
||||||
|
// and very few assumptions about the user's page layout.
|
||||||
|
const global = typeof window !== 'undefined' ? window : null
|
||||||
|
const ssr = global === null
|
||||||
|
const document = !ssr ? global.document : undefined
|
||||||
|
|
||||||
|
// Save a couple long function names that are used frequently.
|
||||||
|
// This optimization saves around 400 bytes.
|
||||||
|
const addEventListener = 'addEventListener'
|
||||||
|
const removeEventListener = 'removeEventListener'
|
||||||
|
const getBoundingClientRect = 'getBoundingClientRect'
|
||||||
|
const gutterStartDragging = '_a'
|
||||||
|
const aGutterSize = '_b'
|
||||||
|
const bGutterSize = '_c'
|
||||||
|
const HORIZONTAL = 'horizontal'
|
||||||
|
const NOOP = () => false
|
||||||
|
|
||||||
|
// Helper function determines which prefixes of CSS calc we need.
|
||||||
|
// We only need to do this once on startup, when this anonymous function is called.
|
||||||
|
//
|
||||||
|
// Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
|
||||||
|
// http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
|
||||||
|
const calc = ssr
|
||||||
|
? 'calc'
|
||||||
|
: `${['', '-webkit-', '-moz-', '-o-']
|
||||||
|
.filter(prefix => {
|
||||||
|
const el = document.createElement('div')
|
||||||
|
el.style.cssText = `width:${prefix}calc(9px)`
|
||||||
|
|
||||||
|
return !!el.style.length
|
||||||
|
})
|
||||||
|
.shift()}calc`
|
||||||
|
|
||||||
|
// Helper function checks if its argument is a string-like type
|
||||||
|
const isString = v => typeof v === 'string' || v instanceof String
|
||||||
|
|
||||||
|
// Helper function allows elements and string selectors to be used
|
||||||
|
// interchangeably. In either case an element is returned. This allows us to
|
||||||
|
// do `Split([elem1, elem2])` as well as `Split(['#id1', '#id2'])`.
|
||||||
|
const elementOrSelector = el => {
|
||||||
|
if (isString(el)) {
|
||||||
|
const ele = document.querySelector(el)
|
||||||
|
if (!ele) {
|
||||||
|
throw new Error(`Selector ${el} did not match a DOM element`)
|
||||||
|
}
|
||||||
|
return ele
|
||||||
|
}
|
||||||
|
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function gets a property from the properties object, with a default fallback
|
||||||
|
const getOption = (options, propName, def) => {
|
||||||
|
const value = options[propName]
|
||||||
|
if (value !== undefined) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
const getGutterSize = (gutterSize, isFirst, isLast, gutterAlign) => {
|
||||||
|
if (isFirst) {
|
||||||
|
if (gutterAlign === 'end') {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if (gutterAlign === 'center') {
|
||||||
|
return gutterSize / 2
|
||||||
|
}
|
||||||
|
} else if (isLast) {
|
||||||
|
if (gutterAlign === 'start') {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if (gutterAlign === 'center') {
|
||||||
|
return gutterSize / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gutterSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default options
|
||||||
|
const defaultGutterFn = (i, gutterDirection) => {
|
||||||
|
const gut = document.createElement('div')
|
||||||
|
gut.className = `gutter gutter-${gutterDirection}`
|
||||||
|
return gut
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultElementStyleFn = (dim, size, gutSize) => {
|
||||||
|
const style = {}
|
||||||
|
|
||||||
|
if (!isString(size)) {
|
||||||
|
style[dim] = `${calc}(${size}% - ${gutSize}px)`
|
||||||
|
} else {
|
||||||
|
style[dim] = size
|
||||||
|
}
|
||||||
|
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultGutterStyleFn = (dim, gutSize) => ({ [dim]: `${gutSize}px` })
|
||||||
|
|
||||||
|
// The main function to initialize a split. Split.js thinks about each pair
|
||||||
|
// of elements as an independant pair. Dragging the gutter between two elements
|
||||||
|
// only changes the dimensions of elements in that pair. This is key to understanding
|
||||||
|
// how the following functions operate, since each function is bound to a pair.
|
||||||
|
//
|
||||||
|
// A pair object is shaped like this:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// a: DOM element,
|
||||||
|
// b: DOM element,
|
||||||
|
// aMin: Number,
|
||||||
|
// bMin: Number,
|
||||||
|
// dragging: Boolean,
|
||||||
|
// parent: DOM element,
|
||||||
|
// direction: 'horizontal' | 'vertical'
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The basic sequence:
|
||||||
|
//
|
||||||
|
// 1. Set defaults to something sane. `options` doesn't have to be passed at all.
|
||||||
|
// 2. Initialize a bunch of strings based on the direction we're splitting.
|
||||||
|
// A lot of the behavior in the rest of the library is paramatized down to
|
||||||
|
// rely on CSS strings and classes.
|
||||||
|
// 3. Define the dragging helper functions, and a few helpers to go with them.
|
||||||
|
// 4. Loop through the elements while pairing them off. Every pair gets an
|
||||||
|
// `pair` object and a gutter.
|
||||||
|
// 5. Actually size the pair elements, insert gutters and attach event listeners.
|
||||||
|
const Split = (idsOption, options = {}) => {
|
||||||
|
if (ssr) return {}
|
||||||
|
|
||||||
|
let ids = idsOption
|
||||||
|
let dimension
|
||||||
|
let clientAxis
|
||||||
|
let position
|
||||||
|
let positionEnd
|
||||||
|
let clientSize
|
||||||
|
let elements
|
||||||
|
|
||||||
|
// Allow HTMLCollection to be used as an argument when supported
|
||||||
|
if (Array.from) {
|
||||||
|
ids = Array.from(ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
// All DOM elements in the split should have a common parent. We can grab
|
||||||
|
// the first elements parent and hope users read the docs because the
|
||||||
|
// behavior will be whacky otherwise.
|
||||||
|
const firstElement = elementOrSelector(ids[0])
|
||||||
|
const parent = firstElement.parentNode
|
||||||
|
const parentStyle = getComputedStyle ? getComputedStyle(parent) : null
|
||||||
|
const parentFlexDirection = parentStyle ? parentStyle.flexDirection : null
|
||||||
|
|
||||||
|
// Set default options.sizes to equal percentages of the parent element.
|
||||||
|
let sizes = getOption(options, 'sizes') || ids.map(() => 100 / ids.length)
|
||||||
|
|
||||||
|
// Standardize minSize and maxSize to an array if it isn't already.
|
||||||
|
// This allows minSize and maxSize to be passed as a number.
|
||||||
|
const minSize = getOption(options, 'minSize', 100)
|
||||||
|
const minSizes = Array.isArray(minSize) ? minSize : ids.map(() => minSize)
|
||||||
|
const maxSize = getOption(options, 'maxSize', Infinity)
|
||||||
|
const maxSizes = Array.isArray(maxSize) ? maxSize : ids.map(() => maxSize)
|
||||||
|
|
||||||
|
// Get other options
|
||||||
|
const expandToMin = getOption(options, 'expandToMin', false)
|
||||||
|
const gutterSize = getOption(options, 'gutterSize', 10)
|
||||||
|
const gutterAlign = getOption(options, 'gutterAlign', 'center')
|
||||||
|
const snapOffset = getOption(options, 'snapOffset', 30)
|
||||||
|
const snapOffsets = Array.isArray(snapOffset) ? snapOffset : ids.map(() => snapOffset)
|
||||||
|
const dragInterval = getOption(options, 'dragInterval', 1)
|
||||||
|
const direction = getOption(options, 'direction', HORIZONTAL)
|
||||||
|
const cursor = getOption(
|
||||||
|
options,
|
||||||
|
'cursor',
|
||||||
|
direction === HORIZONTAL ? 'col-resize' : 'row-resize',
|
||||||
|
)
|
||||||
|
const gutter = getOption(options, 'gutter', defaultGutterFn)
|
||||||
|
const elementStyle = getOption(
|
||||||
|
options,
|
||||||
|
'elementStyle',
|
||||||
|
defaultElementStyleFn,
|
||||||
|
)
|
||||||
|
const gutterStyle = getOption(options, 'gutterStyle', defaultGutterStyleFn)
|
||||||
|
const rtl = getOption(options, 'rtl', false)
|
||||||
|
|
||||||
|
// 2. Initialize a bunch of strings based on the direction we're splitting.
|
||||||
|
// A lot of the behavior in the rest of the library is paramatized down to
|
||||||
|
// rely on CSS strings and classes.
|
||||||
|
if (direction === HORIZONTAL) {
|
||||||
|
dimension = 'width'
|
||||||
|
clientAxis = 'clientX'
|
||||||
|
position = 'left'
|
||||||
|
positionEnd = 'right'
|
||||||
|
clientSize = 'clientWidth'
|
||||||
|
} else if (direction === 'vertical') {
|
||||||
|
dimension = 'height'
|
||||||
|
clientAxis = 'clientY'
|
||||||
|
position = 'top'
|
||||||
|
positionEnd = 'bottom'
|
||||||
|
clientSize = 'clientHeight'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Define the dragging helper functions, and a few helpers to go with them.
|
||||||
|
// Each helper is bound to a pair object that contains its metadata. This
|
||||||
|
// also makes it easy to store references to listeners that that will be
|
||||||
|
// added and removed.
|
||||||
|
//
|
||||||
|
// Even though there are no other functions contained in them, aliasing
|
||||||
|
// this to self saves 50 bytes or so since it's used so frequently.
|
||||||
|
//
|
||||||
|
// The pair object saves metadata like dragging state, position and
|
||||||
|
// event listener references.
|
||||||
|
|
||||||
|
function setElementSize(el, size, gutSize, i) {
|
||||||
|
// Split.js allows setting sizes via numbers (ideally), or if you must,
|
||||||
|
// by string, like '300px'. This is less than ideal, because it breaks
|
||||||
|
// the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
|
||||||
|
// make sure you calculate the gutter size by hand.
|
||||||
|
const style = elementStyle(dimension, size, gutSize, i)
|
||||||
|
|
||||||
|
Object.keys(style).forEach(prop => {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
el.style[prop] = style[prop]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGutterSize(gutterElement, gutSize, i) {
|
||||||
|
const style = gutterStyle(dimension, gutSize, i)
|
||||||
|
|
||||||
|
Object.keys(style).forEach(prop => {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
gutterElement.style[prop] = style[prop]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSizes() {
|
||||||
|
return elements.map(element => element.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supports touch events, but not multitouch, so only the first
|
||||||
|
// finger `touches[0]` is counted.
|
||||||
|
function getMousePosition(e) {
|
||||||
|
if ('touches' in e) return e.touches[0][clientAxis]
|
||||||
|
return e[clientAxis]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually adjust the size of elements `a` and `b` to `offset` while dragging.
|
||||||
|
// calc is used to allow calc(percentage + gutterpx) on the whole split instance,
|
||||||
|
// which allows the viewport to be resized without additional logic.
|
||||||
|
// Element a's size is the same as offset. b's size is total size - a size.
|
||||||
|
// Both sizes are calculated from the initial parent percentage,
|
||||||
|
// then the gutter size is subtracted.
|
||||||
|
function adjust(offset) {
|
||||||
|
const a = elements[this.a]
|
||||||
|
const b = elements[this.b]
|
||||||
|
const percentage = a.size + b.size
|
||||||
|
|
||||||
|
a.size = (offset / this.size) * percentage
|
||||||
|
b.size = percentage - (offset / this.size) * percentage
|
||||||
|
|
||||||
|
setElementSize(a.element, a.size, this[aGutterSize], a.i)
|
||||||
|
setElementSize(b.element, b.size, this[bGutterSize], b.i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// drag, where all the magic happens. The logic is really quite simple:
|
||||||
|
//
|
||||||
|
// 1. Ignore if the pair is not dragging.
|
||||||
|
// 2. Get the offset of the event.
|
||||||
|
// 3. Snap offset to min if within snappable range (within min + snapOffset).
|
||||||
|
// 4. Actually adjust each element in the pair to offset.
|
||||||
|
//
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// | | <- a.minSize || b.minSize -> | |
|
||||||
|
// | | | <- this.snapOffset || this.snapOffset -> | | |
|
||||||
|
// | | | || | | |
|
||||||
|
// | | | || | | |
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// | <- this.start this.size -> |
|
||||||
|
function drag(e) {
|
||||||
|
let offset
|
||||||
|
const a = elements[this.a]
|
||||||
|
const b = elements[this.b]
|
||||||
|
|
||||||
|
if (!this.dragging) return
|
||||||
|
|
||||||
|
// Get the offset of the event from the first side of the
|
||||||
|
// pair `this.start`. Then offset by the initial position of the
|
||||||
|
// mouse compared to the gutter size.
|
||||||
|
offset =
|
||||||
|
getMousePosition(e) -
|
||||||
|
this.start +
|
||||||
|
(this[aGutterSize] - this.dragOffset)
|
||||||
|
|
||||||
|
if (dragInterval > 1) {
|
||||||
|
offset = Math.round(offset / dragInterval) * dragInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
// If within snapOffset of min or max, set offset to min or max.
|
||||||
|
// snapOffset buffers a.minSize and b.minSize, so logic is opposite for both.
|
||||||
|
// Include the appropriate gutter sizes to prevent overflows.
|
||||||
|
if (offset <= a.minSize + a.snapOffset + this[aGutterSize]) {
|
||||||
|
offset = a.minSize + this[aGutterSize]
|
||||||
|
} else if (
|
||||||
|
offset >=
|
||||||
|
this.size - (b.minSize + b.snapOffset + this[bGutterSize])
|
||||||
|
) {
|
||||||
|
offset = this.size - (b.minSize + this[bGutterSize])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset >= a.maxSize - a.snapOffset + this[aGutterSize]) {
|
||||||
|
offset = a.maxSize + this[aGutterSize]
|
||||||
|
} else if (
|
||||||
|
offset <=
|
||||||
|
this.size - (b.maxSize - b.snapOffset + this[bGutterSize])
|
||||||
|
) {
|
||||||
|
offset = this.size - (b.maxSize + this[bGutterSize])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually adjust the size.
|
||||||
|
adjust.call(this, offset)
|
||||||
|
|
||||||
|
// Call the drag callback continously. Don't do anything too intensive
|
||||||
|
// in this callback.
|
||||||
|
getOption(options, 'onDrag', NOOP)(getSizes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache some important sizes when drag starts, so we don't have to do that
|
||||||
|
// continously:
|
||||||
|
//
|
||||||
|
// `size`: The total size of the pair. First + second + first gutter + second gutter.
|
||||||
|
// `start`: The leading side of the first element.
|
||||||
|
//
|
||||||
|
// ------------------------------------------------
|
||||||
|
// | aGutterSize -> ||| |
|
||||||
|
// | ||| |
|
||||||
|
// | ||| |
|
||||||
|
// | ||| <- bGutterSize |
|
||||||
|
// ------------------------------------------------
|
||||||
|
// | <- start size -> |
|
||||||
|
function calculateSizes() {
|
||||||
|
// Figure out the parent size minus padding.
|
||||||
|
const a = elements[this.a].element
|
||||||
|
const b = elements[this.b].element
|
||||||
|
|
||||||
|
const aBounds = a[getBoundingClientRect]()
|
||||||
|
const bBounds = b[getBoundingClientRect]()
|
||||||
|
|
||||||
|
this.size =
|
||||||
|
aBounds[dimension] +
|
||||||
|
bBounds[dimension] +
|
||||||
|
this[aGutterSize] +
|
||||||
|
this[bGutterSize]
|
||||||
|
this.start = aBounds[position]
|
||||||
|
this.end = aBounds[positionEnd]
|
||||||
|
}
|
||||||
|
|
||||||
|
function innerSize(element) {
|
||||||
|
// Return nothing if getComputedStyle is not supported (< IE9)
|
||||||
|
// Or if parent element has no layout yet
|
||||||
|
if (!getComputedStyle) return null
|
||||||
|
|
||||||
|
const computedStyle = getComputedStyle(element)
|
||||||
|
|
||||||
|
if (!computedStyle) return null
|
||||||
|
|
||||||
|
let size = element[clientSize]
|
||||||
|
|
||||||
|
if (size === 0) return null
|
||||||
|
|
||||||
|
if (direction === HORIZONTAL) {
|
||||||
|
size -=
|
||||||
|
parseFloat(computedStyle.paddingLeft) +
|
||||||
|
parseFloat(computedStyle.paddingRight)
|
||||||
|
} else {
|
||||||
|
size -=
|
||||||
|
parseFloat(computedStyle.paddingTop) +
|
||||||
|
parseFloat(computedStyle.paddingBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
// When specifying percentage sizes that are less than the computed
|
||||||
|
// size of the element minus the gutter, the lesser percentages must be increased
|
||||||
|
// (and decreased from the other elements) to make space for the pixels
|
||||||
|
// subtracted by the gutters.
|
||||||
|
function trimToMin(sizesToTrim) {
|
||||||
|
// Try to get inner size of parent element.
|
||||||
|
// If it's no supported, return original sizes.
|
||||||
|
const parentSize = innerSize(parent)
|
||||||
|
if (parentSize === null) {
|
||||||
|
return sizesToTrim
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minSizes.reduce((a, b) => a + b, 0) > parentSize) {
|
||||||
|
return sizesToTrim
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of the excess pixels, the amount of pixels over the desired percentage
|
||||||
|
// Also keep track of the elements with pixels to spare, to decrease after if needed
|
||||||
|
let excessPixels = 0
|
||||||
|
const toSpare = []
|
||||||
|
|
||||||
|
const pixelSizes = sizesToTrim.map((size, i) => {
|
||||||
|
// Convert requested percentages to pixel sizes
|
||||||
|
const pixelSize = (parentSize * size) / 100
|
||||||
|
const elementGutterSize = getGutterSize(
|
||||||
|
gutterSize,
|
||||||
|
i === 0,
|
||||||
|
i === sizesToTrim.length - 1,
|
||||||
|
gutterAlign,
|
||||||
|
)
|
||||||
|
const elementMinSize = minSizes[i] + elementGutterSize
|
||||||
|
|
||||||
|
// If element is too smal, increase excess pixels by the difference
|
||||||
|
// and mark that it has no pixels to spare
|
||||||
|
if (pixelSize < elementMinSize) {
|
||||||
|
excessPixels += elementMinSize - pixelSize
|
||||||
|
toSpare.push(0)
|
||||||
|
return elementMinSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, mark the pixels it has to spare and return it's original size
|
||||||
|
toSpare.push(pixelSize - elementMinSize)
|
||||||
|
return pixelSize
|
||||||
|
})
|
||||||
|
|
||||||
|
// If nothing was adjusted, return the original sizes
|
||||||
|
if (excessPixels === 0) {
|
||||||
|
return sizesToTrim
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixelSizes.map((pixelSize, i) => {
|
||||||
|
let newPixelSize = pixelSize
|
||||||
|
|
||||||
|
// While there's still pixels to take, and there's enough pixels to spare,
|
||||||
|
// take as many as possible up to the total excess pixels
|
||||||
|
if (excessPixels > 0 && toSpare[i] - excessPixels > 0) {
|
||||||
|
const takenPixels = Math.min(
|
||||||
|
excessPixels,
|
||||||
|
toSpare[i] - excessPixels,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Subtract the amount taken for the next iteration
|
||||||
|
excessPixels -= takenPixels
|
||||||
|
newPixelSize = pixelSize - takenPixels
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the pixel size adjusted as a percentage
|
||||||
|
return (newPixelSize / parentSize) * 100
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// stopDragging is very similar to startDragging in reverse.
|
||||||
|
function stopDragging() {
|
||||||
|
const self = this
|
||||||
|
const a = elements[self.a].element
|
||||||
|
const b = elements[self.b].element
|
||||||
|
|
||||||
|
if (self.dragging) {
|
||||||
|
getOption(options, 'onDragEnd', NOOP)(getSizes())
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dragging = false
|
||||||
|
|
||||||
|
// Remove the stored event listeners. This is why we store them.
|
||||||
|
global[removeEventListener]('mouseup', self.stop)
|
||||||
|
global[removeEventListener]('touchend', self.stop)
|
||||||
|
global[removeEventListener]('touchcancel', self.stop)
|
||||||
|
global[removeEventListener]('mousemove', self.move)
|
||||||
|
global[removeEventListener]('touchmove', self.move)
|
||||||
|
|
||||||
|
// Clear bound function references
|
||||||
|
self.stop = null
|
||||||
|
self.move = null
|
||||||
|
|
||||||
|
a[removeEventListener]('selectstart', NOOP)
|
||||||
|
a[removeEventListener]('dragstart', NOOP)
|
||||||
|
b[removeEventListener]('selectstart', NOOP)
|
||||||
|
b[removeEventListener]('dragstart', NOOP)
|
||||||
|
|
||||||
|
a.style.userSelect = ''
|
||||||
|
a.style.webkitUserSelect = ''
|
||||||
|
a.style.MozUserSelect = ''
|
||||||
|
a.style.pointerEvents = ''
|
||||||
|
|
||||||
|
b.style.userSelect = ''
|
||||||
|
b.style.webkitUserSelect = ''
|
||||||
|
b.style.MozUserSelect = ''
|
||||||
|
b.style.pointerEvents = ''
|
||||||
|
|
||||||
|
self.gutter.style.cursor = ''
|
||||||
|
self.parent.style.cursor = ''
|
||||||
|
document.body.style.cursor = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// startDragging calls `calculateSizes` to store the inital size in the pair object.
|
||||||
|
// It also adds event listeners for mouse/touch events,
|
||||||
|
// and prevents selection while dragging so avoid the selecting text.
|
||||||
|
function startDragging(e) {
|
||||||
|
// Right-clicking can't start dragging.
|
||||||
|
if ('button' in e && e.button !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alias frequently used variables to save space. 200 bytes.
|
||||||
|
const self = this
|
||||||
|
const a = elements[self.a].element
|
||||||
|
const b = elements[self.b].element
|
||||||
|
|
||||||
|
// Call the onDragStart callback.
|
||||||
|
if (!self.dragging) {
|
||||||
|
getOption(options, 'onDragStart', NOOP)(getSizes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't actually drag the element. We emulate that in the drag function.
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
// Set the dragging property of the pair object.
|
||||||
|
self.dragging = true
|
||||||
|
|
||||||
|
// Create two event listeners bound to the same pair object and store
|
||||||
|
// them in the pair object.
|
||||||
|
self.move = drag.bind(self)
|
||||||
|
self.stop = stopDragging.bind(self)
|
||||||
|
|
||||||
|
// All the binding. `window` gets the stop events in case we drag out of the elements.
|
||||||
|
global[addEventListener]('mouseup', self.stop)
|
||||||
|
global[addEventListener]('touchend', self.stop)
|
||||||
|
global[addEventListener]('touchcancel', self.stop)
|
||||||
|
global[addEventListener]('mousemove', self.move)
|
||||||
|
global[addEventListener]('touchmove', self.move)
|
||||||
|
|
||||||
|
// Disable selection. Disable!
|
||||||
|
a[addEventListener]('selectstart', NOOP)
|
||||||
|
a[addEventListener]('dragstart', NOOP)
|
||||||
|
b[addEventListener]('selectstart', NOOP)
|
||||||
|
b[addEventListener]('dragstart', NOOP)
|
||||||
|
|
||||||
|
a.style.userSelect = 'none'
|
||||||
|
a.style.webkitUserSelect = 'none'
|
||||||
|
a.style.MozUserSelect = 'none'
|
||||||
|
a.style.pointerEvents = 'none'
|
||||||
|
|
||||||
|
b.style.userSelect = 'none'
|
||||||
|
b.style.webkitUserSelect = 'none'
|
||||||
|
b.style.MozUserSelect = 'none'
|
||||||
|
b.style.pointerEvents = 'none'
|
||||||
|
|
||||||
|
// Set the cursor at multiple levels
|
||||||
|
self.gutter.style.cursor = cursor
|
||||||
|
self.parent.style.cursor = cursor
|
||||||
|
document.body.style.cursor = cursor
|
||||||
|
|
||||||
|
// Cache the initial sizes of the pair.
|
||||||
|
calculateSizes.call(self)
|
||||||
|
|
||||||
|
// Determine the position of the mouse compared to the gutter
|
||||||
|
self.dragOffset = getMousePosition(e) - self.end
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust sizes to ensure percentage is within min size and gutter.
|
||||||
|
sizes = trimToMin(sizes)
|
||||||
|
|
||||||
|
// 5. Create pair and element objects. Each pair has an index reference to
|
||||||
|
// elements `a` and `b` of the pair (first and second elements).
|
||||||
|
// Loop through the elements while pairing them off. Every pair gets a
|
||||||
|
// `pair` object and a gutter.
|
||||||
|
//
|
||||||
|
// Basic logic:
|
||||||
|
//
|
||||||
|
// - Starting with the second element `i > 0`, create `pair` objects with
|
||||||
|
// `a = i - 1` and `b = i`
|
||||||
|
// - Set gutter sizes based on the _pair_ being first/last. The first and last
|
||||||
|
// pair have gutterSize / 2, since they only have one half gutter, and not two.
|
||||||
|
// - Create gutter elements and add event listeners.
|
||||||
|
// - Set the size of the elements, minus the gutter sizes.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// | i=0 | i=1 | i=2 | i=3 |
|
||||||
|
// | | | | |
|
||||||
|
// | pair 0 pair 1 pair 2 |
|
||||||
|
// | | | | |
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
const pairs = []
|
||||||
|
elements = ids.map((id, i) => {
|
||||||
|
// Create the element object.
|
||||||
|
const element = {
|
||||||
|
element: elementOrSelector(id),
|
||||||
|
size: sizes[i],
|
||||||
|
minSize: minSizes[i],
|
||||||
|
maxSize: maxSizes[i],
|
||||||
|
snapOffset: snapOffsets[i],
|
||||||
|
i,
|
||||||
|
}
|
||||||
|
|
||||||
|
let pair
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
// Create the pair object with its metadata.
|
||||||
|
pair = {
|
||||||
|
a: i - 1,
|
||||||
|
b: i,
|
||||||
|
dragging: false,
|
||||||
|
direction,
|
||||||
|
parent,
|
||||||
|
}
|
||||||
|
|
||||||
|
pair[aGutterSize] = getGutterSize(
|
||||||
|
gutterSize,
|
||||||
|
i - 1 === 0,
|
||||||
|
false,
|
||||||
|
gutterAlign,
|
||||||
|
)
|
||||||
|
pair[bGutterSize] = getGutterSize(
|
||||||
|
gutterSize,
|
||||||
|
false,
|
||||||
|
i === ids.length - 1,
|
||||||
|
gutterAlign,
|
||||||
|
)
|
||||||
|
|
||||||
|
// if the parent has a reverse flex-direction, switch the pair elements.
|
||||||
|
if (
|
||||||
|
(direction === HORIZONTAL && rtl) ||
|
||||||
|
parentFlexDirection === 'row-reverse' ||
|
||||||
|
parentFlexDirection === 'column-reverse'
|
||||||
|
) {
|
||||||
|
const temp = pair.a
|
||||||
|
pair.a = pair.b
|
||||||
|
pair.b = temp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the size of the current element. IE8 is supported by
|
||||||
|
// staticly assigning sizes without draggable gutters. Assigns a string
|
||||||
|
// to `size`.
|
||||||
|
//
|
||||||
|
// Create gutter elements for each pair.
|
||||||
|
if (i > 0) {
|
||||||
|
const gutterElement = gutter(i, direction, element.element)
|
||||||
|
setGutterSize(gutterElement, gutterSize, i)
|
||||||
|
|
||||||
|
// Save bound event listener for removal later
|
||||||
|
pair[gutterStartDragging] = startDragging.bind(pair)
|
||||||
|
|
||||||
|
// Attach bound event listener
|
||||||
|
gutterElement[addEventListener](
|
||||||
|
'mousedown',
|
||||||
|
pair[gutterStartDragging],
|
||||||
|
)
|
||||||
|
gutterElement[addEventListener](
|
||||||
|
'touchstart',
|
||||||
|
pair[gutterStartDragging],
|
||||||
|
)
|
||||||
|
|
||||||
|
parent.insertBefore(gutterElement, element.element)
|
||||||
|
|
||||||
|
pair.gutter = gutterElement
|
||||||
|
}
|
||||||
|
|
||||||
|
setElementSize(
|
||||||
|
element.element,
|
||||||
|
element.size,
|
||||||
|
getGutterSize(
|
||||||
|
gutterSize,
|
||||||
|
i === 0,
|
||||||
|
i === ids.length - 1,
|
||||||
|
gutterAlign,
|
||||||
|
),
|
||||||
|
i,
|
||||||
|
)
|
||||||
|
|
||||||
|
// After the first iteration, and we have a pair object, append it to the
|
||||||
|
// list of pairs.
|
||||||
|
if (i > 0) {
|
||||||
|
pairs.push(pair)
|
||||||
|
}
|
||||||
|
|
||||||
|
return element
|
||||||
|
})
|
||||||
|
|
||||||
|
function adjustToMin(element) {
|
||||||
|
const isLast = element.i === pairs.length
|
||||||
|
const pair = isLast ? pairs[element.i - 1] : pairs[element.i]
|
||||||
|
|
||||||
|
calculateSizes.call(pair)
|
||||||
|
|
||||||
|
const size = isLast
|
||||||
|
? pair.size - element.minSize - pair[bGutterSize]
|
||||||
|
: element.minSize + pair[aGutterSize]
|
||||||
|
|
||||||
|
adjust.call(pair, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.forEach(element => {
|
||||||
|
const computedSize = element.element[getBoundingClientRect]()[dimension]
|
||||||
|
|
||||||
|
if (computedSize < element.minSize) {
|
||||||
|
if (expandToMin) {
|
||||||
|
adjustToMin(element)
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
element.minSize = computedSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function setSizes(newSizes) {
|
||||||
|
const trimmed = trimToMin(newSizes)
|
||||||
|
trimmed.forEach((newSize, i) => {
|
||||||
|
if (i > 0) {
|
||||||
|
const pair = pairs[i - 1]
|
||||||
|
|
||||||
|
const a = elements[pair.a]
|
||||||
|
const b = elements[pair.b]
|
||||||
|
|
||||||
|
a.size = trimmed[i - 1]
|
||||||
|
b.size = newSize
|
||||||
|
|
||||||
|
setElementSize(a.element, a.size, pair[aGutterSize], a.i)
|
||||||
|
setElementSize(b.element, b.size, pair[bGutterSize], b.i)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy(preserveStyles, preserveGutter) {
|
||||||
|
pairs.forEach(pair => {
|
||||||
|
if (preserveGutter !== true) {
|
||||||
|
pair.parent.removeChild(pair.gutter)
|
||||||
|
} else {
|
||||||
|
pair.gutter[removeEventListener](
|
||||||
|
'mousedown',
|
||||||
|
pair[gutterStartDragging],
|
||||||
|
)
|
||||||
|
pair.gutter[removeEventListener](
|
||||||
|
'touchstart',
|
||||||
|
pair[gutterStartDragging],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preserveStyles !== true) {
|
||||||
|
const style = elementStyle(
|
||||||
|
dimension,
|
||||||
|
pair.a.size,
|
||||||
|
pair[aGutterSize],
|
||||||
|
)
|
||||||
|
|
||||||
|
Object.keys(style).forEach(prop => {
|
||||||
|
elements[pair.a].element.style[prop] = ''
|
||||||
|
elements[pair.b].element.style[prop] = ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setSizes,
|
||||||
|
getSizes,
|
||||||
|
collapse(i) {
|
||||||
|
adjustToMin(elements[i])
|
||||||
|
},
|
||||||
|
destroy,
|
||||||
|
parent,
|
||||||
|
pairs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Split
|
||||||
20
packages/splitjs/test/SpecRunner.html
Normal file
20
packages/splitjs/test/SpecRunner.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Jasmine Spec Runner v3.5.0</title>
|
||||||
|
|
||||||
|
<link rel="shortcut icon" type="image/png" href="lib/jasmine-3.5.0/jasmine_favicon.png">
|
||||||
|
<link rel="stylesheet" href="lib/jasmine-3.5.0/jasmine.css">
|
||||||
|
|
||||||
|
<script src="lib/jasmine-3.5.0/jasmine.js"></script>
|
||||||
|
<script src="lib/jasmine-3.5.0/jasmine-html.js"></script>
|
||||||
|
<script src="lib/jasmine-3.5.0/boot.js"></script>
|
||||||
|
|
||||||
|
<script src="../dist/split.js"></script>
|
||||||
|
<script src="split.spec.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
136
packages/splitjs/test/lib/jasmine-3.5.0/boot.js
vendored
Normal file
136
packages/splitjs/test/lib/jasmine-3.5.0/boot.js
vendored
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
|
||||||
|
|
||||||
|
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
|
||||||
|
|
||||||
|
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
|
||||||
|
|
||||||
|
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## Require & Instantiate
|
||||||
|
*
|
||||||
|
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
|
||||||
|
*/
|
||||||
|
window.jasmine = jasmineRequire.core(jasmineRequire);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
|
||||||
|
*/
|
||||||
|
jasmineRequire.html(jasmine);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Jasmine environment. This is used to run all specs in a project.
|
||||||
|
*/
|
||||||
|
var env = jasmine.getEnv();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## The Global Interface
|
||||||
|
*
|
||||||
|
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
|
||||||
|
*/
|
||||||
|
var jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
|
||||||
|
*/
|
||||||
|
extend(window, jasmineInterface);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## Runner Parameters
|
||||||
|
*
|
||||||
|
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var queryString = new jasmine.QueryString({
|
||||||
|
getWindowLocation: function() { return window.location; }
|
||||||
|
});
|
||||||
|
|
||||||
|
var filterSpecs = !!queryString.getParam("spec");
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
failFast: queryString.getParam("failFast"),
|
||||||
|
oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"),
|
||||||
|
hideDisabled: queryString.getParam("hideDisabled")
|
||||||
|
};
|
||||||
|
|
||||||
|
var random = queryString.getParam("random");
|
||||||
|
|
||||||
|
if (random !== undefined && random !== "") {
|
||||||
|
config.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seed = queryString.getParam("seed");
|
||||||
|
if (seed) {
|
||||||
|
config.seed = seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## Reporters
|
||||||
|
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
|
||||||
|
*/
|
||||||
|
var htmlReporter = new jasmine.HtmlReporter({
|
||||||
|
env: env,
|
||||||
|
navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); },
|
||||||
|
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
|
||||||
|
getContainer: function() { return document.body; },
|
||||||
|
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||||
|
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
|
||||||
|
timer: new jasmine.Timer(),
|
||||||
|
filterSpecs: filterSpecs
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
|
||||||
|
*/
|
||||||
|
env.addReporter(jasmineInterface.jsApiReporter);
|
||||||
|
env.addReporter(htmlReporter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
|
||||||
|
*/
|
||||||
|
var specFilter = new jasmine.HtmlSpecFilter({
|
||||||
|
filterString: function() { return queryString.getParam("spec"); }
|
||||||
|
});
|
||||||
|
|
||||||
|
config.specFilter = function(spec) {
|
||||||
|
return specFilter.matches(spec.getFullName());
|
||||||
|
};
|
||||||
|
|
||||||
|
env.configure(config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
|
||||||
|
*/
|
||||||
|
window.setTimeout = window.setTimeout;
|
||||||
|
window.setInterval = window.setInterval;
|
||||||
|
window.clearTimeout = window.clearTimeout;
|
||||||
|
window.clearInterval = window.clearInterval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## Execution
|
||||||
|
*
|
||||||
|
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
|
||||||
|
*/
|
||||||
|
var currentWindowOnload = window.onload;
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
if (currentWindowOnload) {
|
||||||
|
currentWindowOnload();
|
||||||
|
}
|
||||||
|
htmlReporter.initialize();
|
||||||
|
env.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for readability above.
|
||||||
|
*/
|
||||||
|
function extend(destination, source) {
|
||||||
|
for (var property in source) destination[property] = source[property];
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
}());
|
||||||
817
packages/splitjs/test/lib/jasmine-3.5.0/jasmine-html.js
vendored
Normal file
817
packages/splitjs/test/lib/jasmine-3.5.0/jasmine-html.js
vendored
Normal file
@ -0,0 +1,817 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
jasmineRequire.html = function(j$) {
|
||||||
|
j$.ResultsNode = jasmineRequire.ResultsNode();
|
||||||
|
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
||||||
|
j$.QueryString = jasmineRequire.QueryString();
|
||||||
|
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmineRequire.HtmlReporter = function(j$) {
|
||||||
|
function ResultsStateBuilder() {
|
||||||
|
this.topResults = new j$.ResultsNode({}, '', null);
|
||||||
|
this.currentParent = this.topResults;
|
||||||
|
this.specsExecuted = 0;
|
||||||
|
this.failureCount = 0;
|
||||||
|
this.pendingSpecCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultsStateBuilder.prototype.suiteStarted = function(result) {
|
||||||
|
this.currentParent.addChild(result, 'suite');
|
||||||
|
this.currentParent = this.currentParent.last();
|
||||||
|
};
|
||||||
|
|
||||||
|
ResultsStateBuilder.prototype.suiteDone = function(result) {
|
||||||
|
this.currentParent.updateResult(result);
|
||||||
|
if (this.currentParent !== this.topResults) {
|
||||||
|
this.currentParent = this.currentParent.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.status === 'failed') {
|
||||||
|
this.failureCount++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ResultsStateBuilder.prototype.specStarted = function(result) {};
|
||||||
|
|
||||||
|
ResultsStateBuilder.prototype.specDone = function(result) {
|
||||||
|
this.currentParent.addChild(result, 'spec');
|
||||||
|
|
||||||
|
if (result.status !== 'excluded') {
|
||||||
|
this.specsExecuted++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.status === 'failed') {
|
||||||
|
this.failureCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.status == 'pending') {
|
||||||
|
this.pendingSpecCount++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function HtmlReporter(options) {
|
||||||
|
var config = function() {
|
||||||
|
return (options.env && options.env.configuration()) || {};
|
||||||
|
},
|
||||||
|
getContainer = options.getContainer,
|
||||||
|
createElement = options.createElement,
|
||||||
|
createTextNode = options.createTextNode,
|
||||||
|
navigateWithNewParam = options.navigateWithNewParam || function() {},
|
||||||
|
addToExistingQueryString =
|
||||||
|
options.addToExistingQueryString || defaultQueryString,
|
||||||
|
filterSpecs = options.filterSpecs,
|
||||||
|
htmlReporterMain,
|
||||||
|
symbols,
|
||||||
|
deprecationWarnings = [];
|
||||||
|
|
||||||
|
this.initialize = function() {
|
||||||
|
clearPrior();
|
||||||
|
htmlReporterMain = createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine_html-reporter' },
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-banner' },
|
||||||
|
createDom('a', {
|
||||||
|
className: 'jasmine-title',
|
||||||
|
href: 'http://jasmine.github.io/',
|
||||||
|
target: '_blank'
|
||||||
|
}),
|
||||||
|
createDom('span', { className: 'jasmine-version' }, j$.version)
|
||||||
|
),
|
||||||
|
createDom('ul', { className: 'jasmine-symbol-summary' }),
|
||||||
|
createDom('div', { className: 'jasmine-alert' }),
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-results' },
|
||||||
|
createDom('div', { className: 'jasmine-failures' })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
getContainer().appendChild(htmlReporterMain);
|
||||||
|
};
|
||||||
|
|
||||||
|
var totalSpecsDefined;
|
||||||
|
this.jasmineStarted = function(options) {
|
||||||
|
totalSpecsDefined = options.totalSpecsDefined || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
var summary = createDom('div', { className: 'jasmine-summary' });
|
||||||
|
|
||||||
|
var stateBuilder = new ResultsStateBuilder();
|
||||||
|
|
||||||
|
this.suiteStarted = function(result) {
|
||||||
|
stateBuilder.suiteStarted(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.suiteDone = function(result) {
|
||||||
|
stateBuilder.suiteDone(result);
|
||||||
|
|
||||||
|
if (result.status === 'failed') {
|
||||||
|
failures.push(failureDom(result));
|
||||||
|
}
|
||||||
|
addDeprecationWarnings(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.specStarted = function(result) {
|
||||||
|
stateBuilder.specStarted(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
var failures = [];
|
||||||
|
this.specDone = function(result) {
|
||||||
|
stateBuilder.specDone(result);
|
||||||
|
|
||||||
|
if (noExpectations(result)) {
|
||||||
|
var noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
|
||||||
|
if (result.status === 'failed') {
|
||||||
|
console.error(noSpecMsg);
|
||||||
|
} else {
|
||||||
|
console.warn(noSpecMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!symbols) {
|
||||||
|
symbols = find('.jasmine-symbol-summary');
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols.appendChild(
|
||||||
|
createDom('li', {
|
||||||
|
className: this.displaySpecInCorrectFormat(result),
|
||||||
|
id: 'spec_' + result.id,
|
||||||
|
title: result.fullName
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.status === 'failed') {
|
||||||
|
failures.push(failureDom(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
addDeprecationWarnings(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.displaySpecInCorrectFormat = function(result) {
|
||||||
|
return noExpectations(result) && result.status === 'passed'
|
||||||
|
? 'jasmine-empty'
|
||||||
|
: this.resultStatus(result.status);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.resultStatus = function(status) {
|
||||||
|
if (status === 'excluded') {
|
||||||
|
return config().hideDisabled
|
||||||
|
? 'jasmine-excluded-no-display'
|
||||||
|
: 'jasmine-excluded';
|
||||||
|
}
|
||||||
|
return 'jasmine-' + status;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.jasmineDone = function(doneResult) {
|
||||||
|
var banner = find('.jasmine-banner');
|
||||||
|
var alert = find('.jasmine-alert');
|
||||||
|
var order = doneResult && doneResult.order;
|
||||||
|
var i;
|
||||||
|
alert.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-duration' },
|
||||||
|
'finished in ' + doneResult.totalTime / 1000 + 's'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
banner.appendChild(optionsMenu(config()));
|
||||||
|
|
||||||
|
if (stateBuilder.specsExecuted < totalSpecsDefined) {
|
||||||
|
var skippedMessage =
|
||||||
|
'Ran ' +
|
||||||
|
stateBuilder.specsExecuted +
|
||||||
|
' of ' +
|
||||||
|
totalSpecsDefined +
|
||||||
|
' specs - run all';
|
||||||
|
var skippedLink = addToExistingQueryString('spec', '');
|
||||||
|
alert.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-bar jasmine-skipped' },
|
||||||
|
createDom(
|
||||||
|
'a',
|
||||||
|
{ href: skippedLink, title: 'Run all specs' },
|
||||||
|
skippedMessage
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
var statusBarMessage = '';
|
||||||
|
var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
|
||||||
|
var globalFailures = (doneResult && doneResult.failedExpectations) || [];
|
||||||
|
var failed = stateBuilder.failureCount + globalFailures.length > 0;
|
||||||
|
|
||||||
|
if (totalSpecsDefined > 0 || failed) {
|
||||||
|
statusBarMessage +=
|
||||||
|
pluralize('spec', stateBuilder.specsExecuted) +
|
||||||
|
', ' +
|
||||||
|
pluralize('failure', stateBuilder.failureCount);
|
||||||
|
if (stateBuilder.pendingSpecCount) {
|
||||||
|
statusBarMessage +=
|
||||||
|
', ' + pluralize('pending spec', stateBuilder.pendingSpecCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doneResult.overallStatus === 'passed') {
|
||||||
|
statusBarClassName += ' jasmine-passed ';
|
||||||
|
} else if (doneResult.overallStatus === 'incomplete') {
|
||||||
|
statusBarClassName += ' jasmine-incomplete ';
|
||||||
|
statusBarMessage =
|
||||||
|
'Incomplete: ' +
|
||||||
|
doneResult.incompleteReason +
|
||||||
|
', ' +
|
||||||
|
statusBarMessage;
|
||||||
|
} else {
|
||||||
|
statusBarClassName += ' jasmine-failed ';
|
||||||
|
}
|
||||||
|
|
||||||
|
var seedBar;
|
||||||
|
if (order && order.random) {
|
||||||
|
seedBar = createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-seed-bar' },
|
||||||
|
', randomized with seed ',
|
||||||
|
createDom(
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
title: 'randomized with seed ' + order.seed,
|
||||||
|
href: seedHref(order.seed)
|
||||||
|
},
|
||||||
|
order.seed
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: statusBarClassName },
|
||||||
|
statusBarMessage,
|
||||||
|
seedBar
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var errorBarClassName = 'jasmine-bar jasmine-errored';
|
||||||
|
var afterAllMessagePrefix = 'AfterAll ';
|
||||||
|
|
||||||
|
for (i = 0; i < globalFailures.length; i++) {
|
||||||
|
alert.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: errorBarClassName },
|
||||||
|
globalFailureMessage(globalFailures[i])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function globalFailureMessage(failure) {
|
||||||
|
if (failure.globalErrorType === 'load') {
|
||||||
|
var prefix = 'Error during loading: ' + failure.message;
|
||||||
|
|
||||||
|
if (failure.filename) {
|
||||||
|
return (
|
||||||
|
prefix + ' in ' + failure.filename + ' line ' + failure.lineno
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return afterAllMessagePrefix + failure.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addDeprecationWarnings(doneResult);
|
||||||
|
|
||||||
|
var warningBarClassName = 'jasmine-bar jasmine-warning';
|
||||||
|
for (i = 0; i < deprecationWarnings.length; i++) {
|
||||||
|
var warning = deprecationWarnings[i];
|
||||||
|
alert.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: warningBarClassName },
|
||||||
|
'DEPRECATION: ' + warning
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = find('.jasmine-results');
|
||||||
|
results.appendChild(summary);
|
||||||
|
|
||||||
|
summaryList(stateBuilder.topResults, summary);
|
||||||
|
|
||||||
|
if (failures.length) {
|
||||||
|
alert.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||||
|
createDom('span', {}, 'Spec List | '),
|
||||||
|
createDom(
|
||||||
|
'a',
|
||||||
|
{ className: 'jasmine-failures-menu', href: '#' },
|
||||||
|
'Failures'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
alert.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||||
|
createDom(
|
||||||
|
'a',
|
||||||
|
{ className: 'jasmine-spec-list-menu', href: '#' },
|
||||||
|
'Spec List'
|
||||||
|
),
|
||||||
|
createDom('span', {}, ' | Failures ')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
find('.jasmine-failures-menu').onclick = function() {
|
||||||
|
setMenuModeTo('jasmine-failure-list');
|
||||||
|
};
|
||||||
|
find('.jasmine-spec-list-menu').onclick = function() {
|
||||||
|
setMenuModeTo('jasmine-spec-list');
|
||||||
|
};
|
||||||
|
|
||||||
|
setMenuModeTo('jasmine-failure-list');
|
||||||
|
|
||||||
|
var failureNode = find('.jasmine-failures');
|
||||||
|
for (i = 0; i < failures.length; i++) {
|
||||||
|
failureNode.appendChild(failures[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
function failureDom(result) {
|
||||||
|
var failure = createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-spec-detail jasmine-failed' },
|
||||||
|
failureDescription(result, stateBuilder.currentParent),
|
||||||
|
createDom('div', { className: 'jasmine-messages' })
|
||||||
|
);
|
||||||
|
var messages = failure.childNodes[1];
|
||||||
|
|
||||||
|
for (var i = 0; i < result.failedExpectations.length; i++) {
|
||||||
|
var expectation = result.failedExpectations[i];
|
||||||
|
messages.appendChild(
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-result-message' },
|
||||||
|
expectation.message
|
||||||
|
)
|
||||||
|
);
|
||||||
|
messages.appendChild(
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-stack-trace' },
|
||||||
|
expectation.stack
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.failedExpectations.length === 0) {
|
||||||
|
messages.appendChild(
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-result-message' },
|
||||||
|
'Spec has no expectations'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
function summaryList(resultsTree, domParent) {
|
||||||
|
var specListNode;
|
||||||
|
for (var i = 0; i < resultsTree.children.length; i++) {
|
||||||
|
var resultNode = resultsTree.children[i];
|
||||||
|
if (filterSpecs && !hasActiveSpec(resultNode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (resultNode.type === 'suite') {
|
||||||
|
var suiteListNode = createDom(
|
||||||
|
'ul',
|
||||||
|
{ className: 'jasmine-suite', id: 'suite-' + resultNode.result.id },
|
||||||
|
createDom(
|
||||||
|
'li',
|
||||||
|
{
|
||||||
|
className:
|
||||||
|
'jasmine-suite-detail jasmine-' + resultNode.result.status
|
||||||
|
},
|
||||||
|
createDom(
|
||||||
|
'a',
|
||||||
|
{ href: specHref(resultNode.result) },
|
||||||
|
resultNode.result.description
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
summaryList(resultNode, suiteListNode);
|
||||||
|
domParent.appendChild(suiteListNode);
|
||||||
|
}
|
||||||
|
if (resultNode.type === 'spec') {
|
||||||
|
if (domParent.getAttribute('class') !== 'jasmine-specs') {
|
||||||
|
specListNode = createDom('ul', { className: 'jasmine-specs' });
|
||||||
|
domParent.appendChild(specListNode);
|
||||||
|
}
|
||||||
|
var specDescription = resultNode.result.description;
|
||||||
|
if (noExpectations(resultNode.result)) {
|
||||||
|
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
resultNode.result.status === 'pending' &&
|
||||||
|
resultNode.result.pendingReason !== ''
|
||||||
|
) {
|
||||||
|
specDescription =
|
||||||
|
specDescription +
|
||||||
|
' PENDING WITH MESSAGE: ' +
|
||||||
|
resultNode.result.pendingReason;
|
||||||
|
}
|
||||||
|
specListNode.appendChild(
|
||||||
|
createDom(
|
||||||
|
'li',
|
||||||
|
{
|
||||||
|
className: 'jasmine-' + resultNode.result.status,
|
||||||
|
id: 'spec-' + resultNode.result.id
|
||||||
|
},
|
||||||
|
createDom(
|
||||||
|
'a',
|
||||||
|
{ href: specHref(resultNode.result) },
|
||||||
|
specDescription
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function optionsMenu(config) {
|
||||||
|
var optionsMenuDom = createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-run-options' },
|
||||||
|
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-payload' },
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-stop-on-failure' },
|
||||||
|
createDom('input', {
|
||||||
|
className: 'jasmine-fail-fast',
|
||||||
|
id: 'jasmine-fail-fast',
|
||||||
|
type: 'checkbox'
|
||||||
|
}),
|
||||||
|
createDom(
|
||||||
|
'label',
|
||||||
|
{ className: 'jasmine-label', for: 'jasmine-fail-fast' },
|
||||||
|
'stop execution on spec failure'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-throw-failures' },
|
||||||
|
createDom('input', {
|
||||||
|
className: 'jasmine-throw',
|
||||||
|
id: 'jasmine-throw-failures',
|
||||||
|
type: 'checkbox'
|
||||||
|
}),
|
||||||
|
createDom(
|
||||||
|
'label',
|
||||||
|
{ className: 'jasmine-label', for: 'jasmine-throw-failures' },
|
||||||
|
'stop spec on expectation failure'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-random-order' },
|
||||||
|
createDom('input', {
|
||||||
|
className: 'jasmine-random',
|
||||||
|
id: 'jasmine-random-order',
|
||||||
|
type: 'checkbox'
|
||||||
|
}),
|
||||||
|
createDom(
|
||||||
|
'label',
|
||||||
|
{ className: 'jasmine-label', for: 'jasmine-random-order' },
|
||||||
|
'run tests in random order'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-hide-disabled' },
|
||||||
|
createDom('input', {
|
||||||
|
className: 'jasmine-disabled',
|
||||||
|
id: 'jasmine-hide-disabled',
|
||||||
|
type: 'checkbox'
|
||||||
|
}),
|
||||||
|
createDom(
|
||||||
|
'label',
|
||||||
|
{ className: 'jasmine-label', for: 'jasmine-hide-disabled' },
|
||||||
|
'hide disabled tests'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
|
||||||
|
failFastCheckbox.checked = config.failFast;
|
||||||
|
failFastCheckbox.onclick = function() {
|
||||||
|
navigateWithNewParam('failFast', !config.failFast);
|
||||||
|
};
|
||||||
|
|
||||||
|
var throwCheckbox = optionsMenuDom.querySelector(
|
||||||
|
'#jasmine-throw-failures'
|
||||||
|
);
|
||||||
|
throwCheckbox.checked = config.oneFailurePerSpec;
|
||||||
|
throwCheckbox.onclick = function() {
|
||||||
|
navigateWithNewParam('throwFailures', !config.oneFailurePerSpec);
|
||||||
|
};
|
||||||
|
|
||||||
|
var randomCheckbox = optionsMenuDom.querySelector(
|
||||||
|
'#jasmine-random-order'
|
||||||
|
);
|
||||||
|
randomCheckbox.checked = config.random;
|
||||||
|
randomCheckbox.onclick = function() {
|
||||||
|
navigateWithNewParam('random', !config.random);
|
||||||
|
};
|
||||||
|
|
||||||
|
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
|
||||||
|
hideDisabled.checked = config.hideDisabled;
|
||||||
|
hideDisabled.onclick = function() {
|
||||||
|
navigateWithNewParam('hideDisabled', !config.hideDisabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
|
||||||
|
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
|
||||||
|
isOpen = /\bjasmine-open\b/;
|
||||||
|
|
||||||
|
optionsTrigger.onclick = function() {
|
||||||
|
if (isOpen.test(optionsPayload.className)) {
|
||||||
|
optionsPayload.className = optionsPayload.className.replace(
|
||||||
|
isOpen,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
optionsPayload.className += ' jasmine-open';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return optionsMenuDom;
|
||||||
|
}
|
||||||
|
|
||||||
|
function failureDescription(result, suite) {
|
||||||
|
var wrapper = createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-description' },
|
||||||
|
createDom(
|
||||||
|
'a',
|
||||||
|
{ title: result.description, href: specHref(result) },
|
||||||
|
result.description
|
||||||
|
)
|
||||||
|
);
|
||||||
|
var suiteLink;
|
||||||
|
|
||||||
|
while (suite && suite.parent) {
|
||||||
|
wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild);
|
||||||
|
suiteLink = createDom(
|
||||||
|
'a',
|
||||||
|
{ href: suiteHref(suite) },
|
||||||
|
suite.result.description
|
||||||
|
);
|
||||||
|
wrapper.insertBefore(suiteLink, wrapper.firstChild);
|
||||||
|
|
||||||
|
suite = suite.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
function suiteHref(suite) {
|
||||||
|
var els = [];
|
||||||
|
|
||||||
|
while (suite && suite.parent) {
|
||||||
|
els.unshift(suite.result.description);
|
||||||
|
suite = suite.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addToExistingQueryString('spec', els.join(' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDeprecationWarnings(result) {
|
||||||
|
if (result && result.deprecationWarnings) {
|
||||||
|
for (var i = 0; i < result.deprecationWarnings.length; i++) {
|
||||||
|
var warning = result.deprecationWarnings[i].message;
|
||||||
|
if (!j$.util.arrayContains(warning)) {
|
||||||
|
deprecationWarnings.push(warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function find(selector) {
|
||||||
|
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearPrior() {
|
||||||
|
// return the reporter
|
||||||
|
var oldReporter = find('');
|
||||||
|
|
||||||
|
if (oldReporter) {
|
||||||
|
getContainer().removeChild(oldReporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDom(type, attrs, childrenVarArgs) {
|
||||||
|
var el = createElement(type);
|
||||||
|
|
||||||
|
for (var i = 2; i < arguments.length; i++) {
|
||||||
|
var child = arguments[i];
|
||||||
|
|
||||||
|
if (typeof child === 'string') {
|
||||||
|
el.appendChild(createTextNode(child));
|
||||||
|
} else {
|
||||||
|
if (child) {
|
||||||
|
el.appendChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var attr in attrs) {
|
||||||
|
if (attr == 'className') {
|
||||||
|
el[attr] = attrs[attr];
|
||||||
|
} else {
|
||||||
|
el.setAttribute(attr, attrs[attr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pluralize(singular, count) {
|
||||||
|
var word = count == 1 ? singular : singular + 's';
|
||||||
|
|
||||||
|
return '' + count + ' ' + word;
|
||||||
|
}
|
||||||
|
|
||||||
|
function specHref(result) {
|
||||||
|
return addToExistingQueryString('spec', result.fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function seedHref(seed) {
|
||||||
|
return addToExistingQueryString('seed', seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultQueryString(key, value) {
|
||||||
|
return '?' + key + '=' + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMenuModeTo(mode) {
|
||||||
|
htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function noExpectations(result) {
|
||||||
|
var allExpectations =
|
||||||
|
result.failedExpectations.length + result.passedExpectations.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
allExpectations === 0 &&
|
||||||
|
(result.status === 'passed' || result.status === 'failed')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasActiveSpec(resultNode) {
|
||||||
|
if (resultNode.type == 'spec' && resultNode.result.status != 'excluded') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultNode.type == 'suite') {
|
||||||
|
for (var i = 0, j = resultNode.children.length; i < j; i++) {
|
||||||
|
if (hasActiveSpec(resultNode.children[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return HtmlReporter;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmineRequire.HtmlSpecFilter = function() {
|
||||||
|
function HtmlSpecFilter(options) {
|
||||||
|
var filterString =
|
||||||
|
options &&
|
||||||
|
options.filterString() &&
|
||||||
|
options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||||
|
var filterPattern = new RegExp(filterString);
|
||||||
|
|
||||||
|
this.matches = function(specName) {
|
||||||
|
return filterPattern.test(specName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return HtmlSpecFilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmineRequire.ResultsNode = function() {
|
||||||
|
function ResultsNode(result, type, parent) {
|
||||||
|
this.result = result;
|
||||||
|
this.type = type;
|
||||||
|
this.parent = parent;
|
||||||
|
|
||||||
|
this.children = [];
|
||||||
|
|
||||||
|
this.addChild = function(result, type) {
|
||||||
|
this.children.push(new ResultsNode(result, type, this));
|
||||||
|
};
|
||||||
|
|
||||||
|
this.last = function() {
|
||||||
|
return this.children[this.children.length - 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.updateResult = function(result) {
|
||||||
|
this.result = result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultsNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmineRequire.QueryString = function() {
|
||||||
|
function QueryString(options) {
|
||||||
|
this.navigateWithNewParam = function(key, value) {
|
||||||
|
options.getWindowLocation().search = this.fullStringWithNewParam(
|
||||||
|
key,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fullStringWithNewParam = function(key, value) {
|
||||||
|
var paramMap = queryStringToParamMap();
|
||||||
|
paramMap[key] = value;
|
||||||
|
return toQueryString(paramMap);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getParam = function(key) {
|
||||||
|
return queryStringToParamMap()[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
function toQueryString(paramMap) {
|
||||||
|
var qStrPairs = [];
|
||||||
|
for (var prop in paramMap) {
|
||||||
|
qStrPairs.push(
|
||||||
|
encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '?' + qStrPairs.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryStringToParamMap() {
|
||||||
|
var paramStr = options.getWindowLocation().search.substring(1),
|
||||||
|
params = [],
|
||||||
|
paramMap = {};
|
||||||
|
|
||||||
|
if (paramStr.length > 0) {
|
||||||
|
params = paramStr.split('&');
|
||||||
|
for (var i = 0; i < params.length; i++) {
|
||||||
|
var p = params[i].split('=');
|
||||||
|
var value = decodeURIComponent(p[1]);
|
||||||
|
if (value === 'true' || value === 'false') {
|
||||||
|
value = JSON.parse(value);
|
||||||
|
}
|
||||||
|
paramMap[decodeURIComponent(p[0])] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QueryString;
|
||||||
|
};
|
||||||
128
packages/splitjs/test/lib/jasmine-3.5.0/jasmine.css
vendored
Normal file
128
packages/splitjs/test/lib/jasmine-3.5.0/jasmine.css
vendored
Normal file
File diff suppressed because one or more lines are too long
8218
packages/splitjs/test/lib/jasmine-3.5.0/jasmine.js
vendored
Normal file
8218
packages/splitjs/test/lib/jasmine-3.5.0/jasmine.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
packages/splitjs/test/lib/jasmine-3.5.0/jasmine_favicon.png
vendored
Normal file
BIN
packages/splitjs/test/lib/jasmine-3.5.0/jasmine_favicon.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
190
packages/splitjs/test/split.spec.js
Normal file
190
packages/splitjs/test/split.spec.js
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/* eslint-env jasmine */
|
||||||
|
/* global Split */
|
||||||
|
/* eslint-disable no-var, func-names, prefer-arrow-callback, object-shorthand, prefer-template */
|
||||||
|
|
||||||
|
function calcParts(expr) {
|
||||||
|
var re = /calc\(([\d]*\.?[\d]*?)%\s?-\s?([\d]+)px\)/
|
||||||
|
var m = re.exec(expr)
|
||||||
|
|
||||||
|
return {
|
||||||
|
percentage: parseFloat(m[1]),
|
||||||
|
pixels: parseInt(m[2], 10),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Split', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
document.body.style.width = '800px'
|
||||||
|
document.body.style.height = '600px'
|
||||||
|
|
||||||
|
this.a = document.createElement('div')
|
||||||
|
this.b = document.createElement('div')
|
||||||
|
this.c = document.createElement('div')
|
||||||
|
|
||||||
|
this.a.id = 'a'
|
||||||
|
this.b.id = 'b'
|
||||||
|
this.c.id = 'c'
|
||||||
|
|
||||||
|
document.body.appendChild(this.a)
|
||||||
|
document.body.appendChild(this.b)
|
||||||
|
document.body.appendChild(this.c)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
document.body.removeChild(this.a)
|
||||||
|
document.body.removeChild(this.b)
|
||||||
|
document.body.removeChild(this.c)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('splits in two when given two elements', function() {
|
||||||
|
Split(['#a', '#b'])
|
||||||
|
|
||||||
|
expect(this.a.style.width).toContain('calc(50% - 5px)')
|
||||||
|
expect(this.b.style.width).toContain('calc(50% - 5px)')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('splits in three when given three elements', function() {
|
||||||
|
Split(['#a', '#b', '#c'])
|
||||||
|
|
||||||
|
expect(calcParts(this.a.style.width).percentage).toBeCloseTo(33.33)
|
||||||
|
expect(calcParts(this.b.style.width).percentage).toBeCloseTo(33.33)
|
||||||
|
expect(calcParts(this.c.style.width).percentage).toBeCloseTo(33.33)
|
||||||
|
|
||||||
|
expect(calcParts(this.a.style.width).pixels).toBe(5)
|
||||||
|
expect(calcParts(this.b.style.width).pixels).toBe(10)
|
||||||
|
expect(calcParts(this.c.style.width).pixels).toBe(5)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('splits vertically when direction is vertical', function() {
|
||||||
|
Split(['#a', '#b'], {
|
||||||
|
direction: 'vertical',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(this.a.style.height).toContain('calc(50% - 5px)')
|
||||||
|
expect(this.b.style.height).toContain('calc(50% - 5px)')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('splits in percentages when given sizes', function() {
|
||||||
|
Split(['#a', '#b'], {
|
||||||
|
sizes: [25, 75],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(this.a.style.width).toContain('calc(25% - 5px)')
|
||||||
|
expect(this.b.style.width).toContain('calc(75% - 5px)')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('splits in percentages when given sizes', function() {
|
||||||
|
Split(['#a', '#b'], {
|
||||||
|
sizes: [25, 75],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(this.a.style.width).toContain('calc(25% - 5px)')
|
||||||
|
expect(this.b.style.width).toContain('calc(75% - 5px)')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accounts for gutter size', function() {
|
||||||
|
Split(['#a', '#b'], {
|
||||||
|
gutterSize: 20,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(this.a.style.width).toContain('calc(50% - 10px)')
|
||||||
|
expect(this.b.style.width).toContain('calc(50% - 10px)')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accounts for gutter size with more than two elements', function() {
|
||||||
|
Split(['#a', '#b', '#c'], {
|
||||||
|
gutterSize: 20,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(calcParts(this.a.style.width).percentage).toBeCloseTo(33.33)
|
||||||
|
expect(calcParts(this.b.style.width).percentage).toBeCloseTo(33.33)
|
||||||
|
expect(calcParts(this.c.style.width).percentage).toBeCloseTo(33.33)
|
||||||
|
|
||||||
|
expect(calcParts(this.a.style.width).pixels).toBe(10)
|
||||||
|
expect(calcParts(this.b.style.width).pixels).toBe(20)
|
||||||
|
expect(calcParts(this.c.style.width).pixels).toBe(10)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accounts for gutter size when direction is vertical', function() {
|
||||||
|
Split(['#a', '#b'], {
|
||||||
|
direction: 'vertical',
|
||||||
|
gutterSize: 20,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(this.a.style.height).toContain('calc(50% - 10px)')
|
||||||
|
expect(this.b.style.height).toContain('calc(50% - 10px)')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accounts for gutter size with more than two elements when direction is vertical', function() {
|
||||||
|
Split(['#a', '#b', '#c'], {
|
||||||
|
direction: 'vertical',
|
||||||
|
gutterSize: 20,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(calcParts(this.a.style.height).percentage).toBeCloseTo(33.33)
|
||||||
|
expect(calcParts(this.b.style.height).percentage).toBeCloseTo(33.33)
|
||||||
|
expect(calcParts(this.c.style.height).percentage).toBeCloseTo(33.33)
|
||||||
|
|
||||||
|
expect(calcParts(this.a.style.height).pixels).toBe(10)
|
||||||
|
expect(calcParts(this.b.style.height).pixels).toBe(20)
|
||||||
|
expect(calcParts(this.c.style.height).pixels).toBe(10)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('set size directly when given css values', function() {
|
||||||
|
Split(['#a', '#b'], {
|
||||||
|
sizes: ['150px', '640px'],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(this.a.style.width).toBe('150px')
|
||||||
|
expect(this.b.style.width).toBe('640px')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adjusts sizes using setSizes', function() {
|
||||||
|
var split = Split(['#a', '#b'])
|
||||||
|
|
||||||
|
split.setSizes([70, 30])
|
||||||
|
|
||||||
|
expect(this.a.style.width).toContain('calc(70% - 5px)')
|
||||||
|
expect(this.b.style.width).toContain('calc(30% - 5px)')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('collapse splits', function() {
|
||||||
|
var split = Split(['#a', '#b'])
|
||||||
|
|
||||||
|
split.collapse(0)
|
||||||
|
|
||||||
|
expect(this.a.getBoundingClientRect().width).toBeCloseTo(100, 0)
|
||||||
|
expect(this.b.getBoundingClientRect().width).toBeCloseTo(800 - 100 - 10, 0)
|
||||||
|
|
||||||
|
split.collapse(1)
|
||||||
|
|
||||||
|
expect(this.a.getBoundingClientRect().width).toBeCloseTo(800 - 100 - 10, 0)
|
||||||
|
expect(this.b.getBoundingClientRect().width).toBeCloseTo(100, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns sizes', function() {
|
||||||
|
var split = Split(['#a', '#b'])
|
||||||
|
var sizes = split.getSizes()
|
||||||
|
|
||||||
|
expect(sizes).toEqual([50, 50])
|
||||||
|
|
||||||
|
split.setSizes([70, 30])
|
||||||
|
|
||||||
|
sizes = split.getSizes()
|
||||||
|
|
||||||
|
expect(sizes).toEqual([70, 30])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets element styles using the elementStyle function', function() {
|
||||||
|
Split(['#a', '#b'], {
|
||||||
|
elementStyle: function(dimension, size) {
|
||||||
|
return {
|
||||||
|
width: size + '%',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(this.a.style.width).toBe('50%')
|
||||||
|
expect(this.b.style.width).toBe('50%')
|
||||||
|
})
|
||||||
|
})
|
||||||
543
pnpm-lock.yaml
generated
543
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
38
scripts/import-translations-from-weblate-csv.ts
Normal file
38
scripts/import-translations-from-weblate-csv.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { readFileSync, writeFileSync } from "fs";
|
||||||
|
import { parseString } from '@fast-csv/parse';
|
||||||
|
|
||||||
|
const csvPath = process.argv[2];
|
||||||
|
const translationPath = process.argv[3];
|
||||||
|
|
||||||
|
if (!csvPath || !translationPath) {
|
||||||
|
console.log("Usage: input.csv translation.json")
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const csvFile = readFileSync(csvPath, "utf-8");
|
||||||
|
const translationFile = readFileSync(translationPath, "utf-8");
|
||||||
|
const translation = JSON.parse(translationFile);
|
||||||
|
|
||||||
|
parseString(csvFile, { headers: true })
|
||||||
|
.on("error", error => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(2);
|
||||||
|
})
|
||||||
|
.on("data", data => {
|
||||||
|
replaceTranslation(data.context, data.target);
|
||||||
|
})
|
||||||
|
.on("end", () => {
|
||||||
|
writeFileSync(translationPath, JSON.stringify(translation, null, 2));
|
||||||
|
});
|
||||||
|
|
||||||
|
function replaceTranslation(path: string, value: string) {
|
||||||
|
let cursor = translation;
|
||||||
|
const segments = path.split(".");
|
||||||
|
const lastSegment = segments.pop();
|
||||||
|
for (const current of segments) {
|
||||||
|
if (!cursor[current]) cursor[current] = {};
|
||||||
|
cursor = cursor[current];
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor[lastSegment] = value;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user