svelte-gantt
Version:
Interactive JavaScript Gantt chart/resource booking component
1,770 lines (1,642 loc) • 276 kB
JavaScript
(function (exports) {
'use strict';
/** @returns {void} */
function noop() {}
/**
* @template T
* @template S
* @param {T} tar
* @param {S} src
* @returns {T & S}
*/
function assign(tar, src) {
// @ts-ignore
for (const k in src) tar[k] = src[k];
return /** @type {T & S} */ (tar);
}
function run(fn) {
return fn();
}
function blank_object() {
return Object.create(null);
}
/**
* @param {Function[]} fns
* @returns {void}
*/
function run_all(fns) {
fns.forEach(run);
}
/**
* @param {any} thing
* @returns {thing is Function}
*/
function is_function(thing) {
return typeof thing === 'function';
}
/** @returns {boolean} */
function safe_not_equal(a, b) {
return a != a ? b == b : a !== b || (a && typeof a === 'object') || typeof a === 'function';
}
let src_url_equal_anchor;
/**
* @param {string} element_src
* @param {string} url
* @returns {boolean}
*/
function src_url_equal(element_src, url) {
if (element_src === url) return true;
if (!src_url_equal_anchor) {
src_url_equal_anchor = document.createElement('a');
}
// This is actually faster than doing URL(..).href
src_url_equal_anchor.href = url;
return element_src === src_url_equal_anchor.href;
}
/** @returns {boolean} */
function is_empty(obj) {
return Object.keys(obj).length === 0;
}
function subscribe(store, ...callbacks) {
if (store == null) {
for (const callback of callbacks) {
callback(undefined);
}
return noop;
}
const unsub = store.subscribe(...callbacks);
return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;
}
/** @returns {void} */
function component_subscribe(component, store, callback) {
component.$$.on_destroy.push(subscribe(store, callback));
}
function create_slot(definition, ctx, $$scope, fn) {
if (definition) {
const slot_ctx = get_slot_context(definition, ctx, $$scope, fn);
return definition[0](slot_ctx);
}
}
function get_slot_context(definition, ctx, $$scope, fn) {
return definition[1] && fn ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx;
}
function get_slot_changes(definition, $$scope, dirty, fn) {
if (definition[2] && fn) {
const lets = definition[2](fn(dirty));
if ($$scope.dirty === undefined) {
return lets;
}
if (typeof lets === 'object') {
const merged = [];
const len = Math.max($$scope.dirty.length, lets.length);
for (let i = 0; i < len; i += 1) {
merged[i] = $$scope.dirty[i] | lets[i];
}
return merged;
}
return $$scope.dirty | lets;
}
return $$scope.dirty;
}
/** @returns {void} */
function update_slot_base(
slot,
slot_definition,
ctx,
$$scope,
slot_changes,
get_slot_context_fn
) {
if (slot_changes) {
const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
slot.p(slot_context, slot_changes);
}
}
/** @returns {any[] | -1} */
function get_all_dirty_from_scope($$scope) {
if ($$scope.ctx.length > 32) {
const dirty = [];
const length = $$scope.ctx.length / 32;
for (let i = 0; i < length; i++) {
dirty[i] = -1;
}
return dirty;
}
return -1;
}
/** @returns {{}} */
function exclude_internal_props(props) {
const result = {};
for (const k in props) if (k[0] !== '$') result[k] = props[k];
return result;
}
/** @returns {{}} */
function compute_rest_props(props, keys) {
const rest = {};
keys = new Set(keys);
for (const k in props) if (!keys.has(k) && k[0] !== '$') rest[k] = props[k];
return rest;
}
function null_to_empty(value) {
return value == null ? '' : value;
}
function set_store_value(store, ret, value) {
store.set(value);
return ret;
}
function action_destroyer(action_result) {
return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;
}
/**
* @param {Node} target
* @param {Node} node
* @returns {void}
*/
function append(target, node) {
target.appendChild(node);
}
/**
* @param {Node} target
* @param {Node} node
* @param {Node} [anchor]
* @returns {void}
*/
function insert(target, node, anchor) {
target.insertBefore(node, anchor || null);
}
/**
* @param {Node} node
* @returns {void}
*/
function detach(node) {
if (node.parentNode) {
node.parentNode.removeChild(node);
}
}
/**
* @returns {void} */
function destroy_each(iterations, detaching) {
for (let i = 0; i < iterations.length; i += 1) {
if (iterations[i]) iterations[i].d(detaching);
}
}
/**
* @template {keyof HTMLElementTagNameMap} K
* @param {K} name
* @returns {HTMLElementTagNameMap[K]}
*/
function element(name) {
return document.createElement(name);
}
/**
* @template {keyof SVGElementTagNameMap} K
* @param {K} name
* @returns {SVGElement}
*/
function svg_element(name) {
return document.createElementNS('http://www.w3.org/2000/svg', name);
}
/**
* @param {string} data
* @returns {Text}
*/
function text(data) {
return document.createTextNode(data);
}
/**
* @returns {Text} */
function space() {
return text(' ');
}
/**
* @returns {Text} */
function empty() {
return text('');
}
/**
* @param {EventTarget} node
* @param {string} event
* @param {EventListenerOrEventListenerObject} handler
* @param {boolean | AddEventListenerOptions | EventListenerOptions} [options]
* @returns {() => void}
*/
function listen(node, event, handler, options) {
node.addEventListener(event, handler, options);
return () => node.removeEventListener(event, handler, options);
}
/**
* @returns {(event: any) => any} */
function stop_propagation(fn) {
return function (event) {
event.stopPropagation();
// @ts-ignore
return fn.call(this, event);
};
}
/**
* @param {Element} node
* @param {string} attribute
* @param {string} [value]
* @returns {void}
*/
function attr(node, attribute, value) {
if (value == null) node.removeAttribute(attribute);
else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value);
}
/**
* @param {Element} element
* @returns {ChildNode[]}
*/
function children(element) {
return Array.from(element.childNodes);
}
/**
* @param {Text} text
* @param {unknown} data
* @returns {void}
*/
function set_data(text, data) {
data = '' + data;
if (text.data === data) return;
text.data = /** @type {string} */ (data);
}
/**
* @returns {void} */
function set_style(node, key, value, important) {
if (value == null) {
node.style.removeProperty(key);
} else {
node.style.setProperty(key, value, important ? 'important' : '');
}
}
// unfortunately this can't be a constant as that wouldn't be tree-shakeable
// so we cache the result instead
/**
* @type {boolean} */
let crossorigin;
/**
* @returns {boolean} */
function is_crossorigin() {
if (crossorigin === undefined) {
crossorigin = false;
try {
if (typeof window !== 'undefined' && window.parent) {
void window.parent.document;
}
} catch (error) {
crossorigin = true;
}
}
return crossorigin;
}
/**
* @param {HTMLElement} node
* @param {() => void} fn
* @returns {() => void}
*/
function add_iframe_resize_listener(node, fn) {
const computed_style = getComputedStyle(node);
if (computed_style.position === 'static') {
node.style.position = 'relative';
}
const iframe = element('iframe');
iframe.setAttribute(
'style',
'display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; ' +
'overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: -1;'
);
iframe.setAttribute('aria-hidden', 'true');
iframe.tabIndex = -1;
const crossorigin = is_crossorigin();
/**
* @type {() => void}
*/
let unsubscribe;
if (crossorigin) {
iframe.src = "data:text/html,<script>onresize=function(){parent.postMessage(0,'*')}</script>";
unsubscribe = listen(
window,
'message',
/** @param {MessageEvent} event */ (event) => {
if (event.source === iframe.contentWindow) fn();
}
);
} else {
iframe.src = 'about:blank';
iframe.onload = () => {
unsubscribe = listen(iframe.contentWindow, 'resize', fn);
// make sure an initial resize event is fired _after_ the iframe is loaded (which is asynchronous)
// see https://github.com/sveltejs/svelte/issues/4233
fn();
};
}
append(node, iframe);
return () => {
if (crossorigin) {
unsubscribe();
} else if (unsubscribe && iframe.contentWindow) {
unsubscribe();
}
detach(iframe);
};
}
/**
* @returns {void} */
function toggle_class(element, name, toggle) {
// The `!!` is required because an `undefined` flag means flipping the current state.
element.classList.toggle(name, !!toggle);
}
/**
* @template T
* @param {string} type
* @param {T} [detail]
* @param {{ bubbles?: boolean, cancelable?: boolean }} [options]
* @returns {CustomEvent<T>}
*/
function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) {
return new CustomEvent(type, { detail, bubbles, cancelable });
}
/** */
class HtmlTag {
/**
* @private
* @default false
*/
is_svg = false;
/** parent for creating node */
e = undefined;
/** html tag nodes */
n = undefined;
/** target */
t = undefined;
/** anchor */
a = undefined;
constructor(is_svg = false) {
this.is_svg = is_svg;
this.e = this.n = null;
}
/**
* @param {string} html
* @returns {void}
*/
c(html) {
this.h(html);
}
/**
* @param {string} html
* @param {HTMLElement | SVGElement} target
* @param {HTMLElement | SVGElement} anchor
* @returns {void}
*/
m(html, target, anchor = null) {
if (!this.e) {
if (this.is_svg)
this.e = svg_element(/** @type {keyof SVGElementTagNameMap} */ (target.nodeName));
/** #7364 target for <template> may be provided as #document-fragment(11) */ else
this.e = element(
/** @type {keyof HTMLElementTagNameMap} */ (
target.nodeType === 11 ? 'TEMPLATE' : target.nodeName
)
);
this.t =
target.tagName !== 'TEMPLATE'
? target
: /** @type {HTMLTemplateElement} */ (target).content;
this.c(html);
}
this.i(anchor);
}
/**
* @param {string} html
* @returns {void}
*/
h(html) {
this.e.innerHTML = html;
this.n = Array.from(
this.e.nodeName === 'TEMPLATE' ? this.e.content.childNodes : this.e.childNodes
);
}
/**
* @returns {void} */
i(anchor) {
for (let i = 0; i < this.n.length; i += 1) {
insert(this.t, this.n[i], anchor);
}
}
/**
* @param {string} html
* @returns {void}
*/
p(html) {
this.d();
this.h(html);
this.i(this.a);
}
/**
* @returns {void} */
d() {
this.n.forEach(detach);
}
}
function construct_svelte_component(component, props) {
return new component(props);
}
/**
* @typedef {Node & {
* claim_order?: number;
* hydrate_init?: true;
* actual_end_child?: NodeEx;
* childNodes: NodeListOf<NodeEx>;
* }} NodeEx
*/
/** @typedef {ChildNode & NodeEx} ChildNodeEx */
/** @typedef {NodeEx & { claim_order: number }} NodeEx2 */
/**
* @typedef {ChildNodeEx[] & {
* claim_info?: {
* last_index: number;
* total_claimed: number;
* };
* }} ChildNodeArray
*/
let current_component;
/** @returns {void} */
function set_current_component(component) {
current_component = component;
}
function get_current_component() {
if (!current_component) throw new Error('Function called outside component initialization');
return current_component;
}
/**
* The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM.
* It must be called during the component's initialisation (but doesn't need to live *inside* the component;
* it can be called from an external module).
*
* If a function is returned _synchronously_ from `onMount`, it will be called when the component is unmounted.
*
* `onMount` does not run inside a [server-side component](https://svelte.dev/docs#run-time-server-side-component-api).
*
* https://svelte.dev/docs/svelte#onmount
* @template T
* @param {() => import('./private.js').NotFunction<T> | Promise<import('./private.js').NotFunction<T>> | (() => any)} fn
* @returns {void}
*/
function onMount(fn) {
get_current_component().$$.on_mount.push(fn);
}
/**
* Schedules a callback to run immediately before the component is unmounted.
*
* Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the
* only one that runs inside a server-side component.
*
* https://svelte.dev/docs/svelte#ondestroy
* @param {() => any} fn
* @returns {void}
*/
function onDestroy(fn) {
get_current_component().$$.on_destroy.push(fn);
}
/**
* Creates an event dispatcher that can be used to dispatch [component events](https://svelte.dev/docs#template-syntax-component-directives-on-eventname).
* Event dispatchers are functions that can take two arguments: `name` and `detail`.
*
* Component events created with `createEventDispatcher` create a
* [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent).
* These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture).
* The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail)
* property and can contain any type of data.
*
* The event dispatcher can be typed to narrow the allowed event names and the type of the `detail` argument:
* ```ts
* const dispatch = createEventDispatcher<{
* loaded: never; // does not take a detail argument
* change: string; // takes a detail argument of type string, which is required
* optional: number | null; // takes an optional detail argument of type number
* }>();
* ```
*
* https://svelte.dev/docs/svelte#createeventdispatcher
* @template {Record<string, any>} [EventMap=any]
* @returns {import('./public.js').EventDispatcher<EventMap>}
*/
function createEventDispatcher() {
const component = get_current_component();
return (type, detail, { cancelable = false } = {}) => {
const callbacks = component.$$.callbacks[type];
if (callbacks) {
// TODO are there situations where events could be dispatched
// in a server (non-DOM) environment?
const event = custom_event(/** @type {string} */ (type), detail, { cancelable });
callbacks.slice().forEach((fn) => {
fn.call(component, event);
});
return !event.defaultPrevented;
}
return true;
};
}
/**
* Associates an arbitrary `context` object with the current component and the specified `key`
* and returns that object. The context is then available to children of the component
* (including slotted content) with `getContext`.
*
* Like lifecycle functions, this must be called during component initialisation.
*
* https://svelte.dev/docs/svelte#setcontext
* @template T
* @param {any} key
* @param {T} context
* @returns {T}
*/
function setContext(key, context) {
get_current_component().$$.context.set(key, context);
return context;
}
/**
* Retrieves the context that belongs to the closest parent component with the specified `key`.
* Must be called during component initialisation.
*
* https://svelte.dev/docs/svelte#getcontext
* @template T
* @param {any} key
* @returns {T}
*/
function getContext(key) {
return get_current_component().$$.context.get(key);
}
// TODO figure out if we still want to support
// shorthand events, or if we want to implement
// a real bubbling mechanism
/**
* @param component
* @param event
* @returns {void}
*/
function bubble(component, event) {
const callbacks = component.$$.callbacks[event.type];
if (callbacks) {
// @ts-ignore
callbacks.slice().forEach((fn) => fn.call(this, event));
}
}
const dirty_components = [];
const binding_callbacks = [];
let render_callbacks = [];
const flush_callbacks = [];
const resolved_promise = /* @__PURE__ */ Promise.resolve();
let update_scheduled = false;
/** @returns {void} */
function schedule_update() {
if (!update_scheduled) {
update_scheduled = true;
resolved_promise.then(flush);
}
}
/** @returns {Promise<void>} */
function tick() {
schedule_update();
return resolved_promise;
}
/** @returns {void} */
function add_render_callback(fn) {
render_callbacks.push(fn);
}
// flush() calls callbacks in this order:
// 1. All beforeUpdate callbacks, in order: parents before children
// 2. All bind:this callbacks, in reverse order: children before parents.
// 3. All afterUpdate callbacks, in order: parents before children. EXCEPT
// for afterUpdates called during the initial onMount, which are called in
// reverse order: children before parents.
// Since callbacks might update component values, which could trigger another
// call to flush(), the following steps guard against this:
// 1. During beforeUpdate, any updated components will be added to the
// dirty_components array and will cause a reentrant call to flush(). Because
// the flush index is kept outside the function, the reentrant call will pick
// up where the earlier call left off and go through all dirty components. The
// current_component value is saved and restored so that the reentrant call will
// not interfere with the "parent" flush() call.
// 2. bind:this callbacks cannot trigger new flush() calls.
// 3. During afterUpdate, any updated components will NOT have their afterUpdate
// callback called a second time; the seen_callbacks set, outside the flush()
// function, guarantees this behavior.
const seen_callbacks = new Set();
let flushidx = 0; // Do *not* move this inside the flush() function
/** @returns {void} */
function flush() {
// Do not reenter flush while dirty components are updated, as this can
// result in an infinite loop. Instead, let the inner flush handle it.
// Reentrancy is ok afterwards for bindings etc.
if (flushidx !== 0) {
return;
}
const saved_component = current_component;
do {
// first, call beforeUpdate functions
// and update components
try {
while (flushidx < dirty_components.length) {
const component = dirty_components[flushidx];
flushidx++;
set_current_component(component);
update(component.$$);
}
} catch (e) {
// reset dirty state to not end up in a deadlocked state and then rethrow
dirty_components.length = 0;
flushidx = 0;
throw e;
}
set_current_component(null);
dirty_components.length = 0;
flushidx = 0;
while (binding_callbacks.length) binding_callbacks.pop()();
// then, once components are updated, call
// afterUpdate functions. This may cause
// subsequent updates...
for (let i = 0; i < render_callbacks.length; i += 1) {
const callback = render_callbacks[i];
if (!seen_callbacks.has(callback)) {
// ...so guard against infinite loops
seen_callbacks.add(callback);
callback();
}
}
render_callbacks.length = 0;
} while (dirty_components.length);
while (flush_callbacks.length) {
flush_callbacks.pop()();
}
update_scheduled = false;
seen_callbacks.clear();
set_current_component(saved_component);
}
/** @returns {void} */
function update($$) {
if ($$.fragment !== null) {
$$.update();
run_all($$.before_update);
const dirty = $$.dirty;
$$.dirty = [-1];
$$.fragment && $$.fragment.p($$.ctx, dirty);
$$.after_update.forEach(add_render_callback);
}
}
/**
* Useful for example to execute remaining `afterUpdate` callbacks before executing `destroy`.
* @param {Function[]} fns
* @returns {void}
*/
function flush_render_callbacks(fns) {
const filtered = [];
const targets = [];
render_callbacks.forEach((c) => (fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c)));
targets.forEach((c) => c());
render_callbacks = filtered;
}
const outroing = new Set();
/**
* @type {Outro}
*/
let outros;
/**
* @returns {void} */
function group_outros() {
outros = {
r: 0,
c: [],
p: outros // parent group
};
}
/**
* @returns {void} */
function check_outros() {
if (!outros.r) {
run_all(outros.c);
}
outros = outros.p;
}
/**
* @param {import('./private.js').Fragment} block
* @param {0 | 1} [local]
* @returns {void}
*/
function transition_in(block, local) {
if (block && block.i) {
outroing.delete(block);
block.i(local);
}
}
/**
* @param {import('./private.js').Fragment} block
* @param {0 | 1} local
* @param {0 | 1} [detach]
* @param {() => void} [callback]
* @returns {void}
*/
function transition_out(block, local, detach, callback) {
if (block && block.o) {
if (outroing.has(block)) return;
outroing.add(block);
outros.c.push(() => {
outroing.delete(block);
if (callback) {
if (detach) block.d(1);
callback();
}
});
block.o(local);
} else if (callback) {
callback();
}
}
/** @typedef {1} INTRO */
/** @typedef {0} OUTRO */
/** @typedef {{ direction: 'in' | 'out' | 'both' }} TransitionOptions */
/** @typedef {(node: Element, params: any, options: TransitionOptions) => import('../transition/public.js').TransitionConfig} TransitionFn */
/**
* @typedef {Object} Outro
* @property {number} r
* @property {Function[]} c
* @property {Object} p
*/
/**
* @typedef {Object} PendingProgram
* @property {number} start
* @property {INTRO|OUTRO} b
* @property {Outro} [group]
*/
/**
* @typedef {Object} Program
* @property {number} a
* @property {INTRO|OUTRO} b
* @property {1|-1} d
* @property {number} duration
* @property {number} start
* @property {number} end
* @property {Outro} [group]
*/
// general each functions:
function ensure_array_like(array_like_or_iterator) {
return array_like_or_iterator?.length !== undefined
? array_like_or_iterator
: Array.from(array_like_or_iterator);
}
/** @returns {void} */
function outro_and_destroy_block(block, lookup) {
transition_out(block, 1, 1, () => {
lookup.delete(block.key);
});
}
/** @returns {any[]} */
function update_keyed_each(
old_blocks,
dirty,
get_key,
dynamic,
ctx,
list,
lookup,
node,
destroy,
create_each_block,
next,
get_context
) {
let o = old_blocks.length;
let n = list.length;
let i = o;
const old_indexes = {};
while (i--) old_indexes[old_blocks[i].key] = i;
const new_blocks = [];
const new_lookup = new Map();
const deltas = new Map();
const updates = [];
i = n;
while (i--) {
const child_ctx = get_context(ctx, list, i);
const key = get_key(child_ctx);
let block = lookup.get(key);
if (!block) {
block = create_each_block(key, child_ctx);
block.c();
} else if (dynamic) {
// defer updates until all the DOM shuffling is done
updates.push(() => block.p(child_ctx, dirty));
}
new_lookup.set(key, (new_blocks[i] = block));
if (key in old_indexes) deltas.set(key, Math.abs(i - old_indexes[key]));
}
const will_move = new Set();
const did_move = new Set();
/** @returns {void} */
function insert(block) {
transition_in(block, 1);
block.m(node, next);
lookup.set(block.key, block);
next = block.first;
n--;
}
while (o && n) {
const new_block = new_blocks[n - 1];
const old_block = old_blocks[o - 1];
const new_key = new_block.key;
const old_key = old_block.key;
if (new_block === old_block) {
// do nothing
next = new_block.first;
o--;
n--;
} else if (!new_lookup.has(old_key)) {
// remove old block
destroy(old_block, lookup);
o--;
} else if (!lookup.has(new_key) || will_move.has(new_key)) {
insert(new_block);
} else if (did_move.has(old_key)) {
o--;
} else if (deltas.get(new_key) > deltas.get(old_key)) {
did_move.add(new_key);
insert(new_block);
} else {
will_move.add(old_key);
o--;
}
}
while (o--) {
const old_block = old_blocks[o];
if (!new_lookup.has(old_block.key)) destroy(old_block, lookup);
}
while (n) insert(new_blocks[n - 1]);
run_all(updates);
return new_blocks;
}
/** @returns {{}} */
function get_spread_update(levels, updates) {
const update = {};
const to_null_out = {};
const accounted_for = { $$scope: 1 };
let i = levels.length;
while (i--) {
const o = levels[i];
const n = updates[i];
if (n) {
for (const key in o) {
if (!(key in n)) to_null_out[key] = 1;
}
for (const key in n) {
if (!accounted_for[key]) {
update[key] = n[key];
accounted_for[key] = 1;
}
}
levels[i] = n;
} else {
for (const key in o) {
accounted_for[key] = 1;
}
}
}
for (const key in to_null_out) {
if (!(key in update)) update[key] = undefined;
}
return update;
}
function get_spread_object(spread_props) {
return typeof spread_props === 'object' && spread_props !== null ? spread_props : {};
}
/** @returns {void} */
function create_component(block) {
block && block.c();
}
/** @returns {void} */
function mount_component(component, target, anchor) {
const { fragment, after_update } = component.$$;
fragment && fragment.m(target, anchor);
// onMount happens before the initial afterUpdate
add_render_callback(() => {
const new_on_destroy = component.$$.on_mount.map(run).filter(is_function);
// if the component was destroyed immediately
// it will update the `$$.on_destroy` reference to `null`.
// the destructured on_destroy may still reference to the old array
if (component.$$.on_destroy) {
component.$$.on_destroy.push(...new_on_destroy);
} else {
// Edge case - component was destroyed immediately,
// most likely as a result of a binding initialising
run_all(new_on_destroy);
}
component.$$.on_mount = [];
});
after_update.forEach(add_render_callback);
}
/** @returns {void} */
function destroy_component(component, detaching) {
const $$ = component.$$;
if ($$.fragment !== null) {
flush_render_callbacks($$.after_update);
run_all($$.on_destroy);
$$.fragment && $$.fragment.d(detaching);
// TODO null out other refs, including component.$$ (but need to
// preserve final state?)
$$.on_destroy = $$.fragment = null;
$$.ctx = [];
}
}
/** @returns {void} */
function make_dirty(component, i) {
if (component.$$.dirty[0] === -1) {
dirty_components.push(component);
schedule_update();
component.$$.dirty.fill(0);
}
component.$$.dirty[(i / 31) | 0] |= 1 << i % 31;
}
// TODO: Document the other params
/**
* @param {SvelteComponent} component
* @param {import('./public.js').ComponentConstructorOptions} options
*
* @param {import('./utils.js')['not_equal']} not_equal Used to compare props and state values.
* @param {(target: Element | ShadowRoot) => void} [append_styles] Function that appends styles to the DOM when the component is first initialised.
* This will be the `add_css` function from the compiled component.
*
* @returns {void}
*/
function init(
component,
options,
instance,
create_fragment,
not_equal,
props,
append_styles = null,
dirty = [-1]
) {
const parent_component = current_component;
set_current_component(component);
/** @type {import('./private.js').T$$} */
const $$ = (component.$$ = {
fragment: null,
ctx: [],
// state
props,
update: noop,
not_equal,
bound: blank_object(),
// lifecycle
on_mount: [],
on_destroy: [],
on_disconnect: [],
before_update: [],
after_update: [],
context: new Map(options.context || (parent_component ? parent_component.$$.context : [])),
// everything else
callbacks: blank_object(),
dirty,
skip_bound: false,
root: options.target || parent_component.$$.root
});
append_styles && append_styles($$.root);
let ready = false;
$$.ctx = instance
? instance(component, options.props || {}, (i, ret, ...rest) => {
const value = rest.length ? rest[0] : ret;
if ($$.ctx && not_equal($$.ctx[i], ($$.ctx[i] = value))) {
if (!$$.skip_bound && $$.bound[i]) $$.bound[i](value);
if (ready) make_dirty(component, i);
}
return ret;
})
: [];
$$.update();
ready = true;
run_all($$.before_update);
// `false` as a special case of no DOM component
$$.fragment = create_fragment ? create_fragment($$.ctx) : false;
if (options.target) {
if (options.hydrate) {
// TODO: what is the correct type here?
// @ts-expect-error
const nodes = children(options.target);
$$.fragment && $$.fragment.l(nodes);
nodes.forEach(detach);
} else {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
$$.fragment && $$.fragment.c();
}
if (options.intro) transition_in(component.$$.fragment);
mount_component(component, options.target, options.anchor);
flush();
}
set_current_component(parent_component);
}
/**
* Base class for Svelte components. Used when dev=false.
*
* @template {Record<string, any>} [Props=any]
* @template {Record<string, any>} [Events=any]
*/
class SvelteComponent {
/**
* ### PRIVATE API
*
* Do not use, may change at any time
*
* @type {any}
*/
$$ = undefined;
/**
* ### PRIVATE API
*
* Do not use, may change at any time
*
* @type {any}
*/
$$set = undefined;
/** @returns {void} */
$destroy() {
destroy_component(this, 1);
this.$destroy = noop;
}
/**
* @template {Extract<keyof Events, string>} K
* @param {K} type
* @param {((e: Events[K]) => void) | null | undefined} callback
* @returns {() => void}
*/
$on(type, callback) {
if (!is_function(callback)) {
return noop;
}
const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []);
callbacks.push(callback);
return () => {
const index = callbacks.indexOf(callback);
if (index !== -1) callbacks.splice(index, 1);
};
}
/**
* @param {Partial<Props>} props
* @returns {void}
*/
$set(props) {
if (this.$$set && !is_empty(props)) {
this.$$.skip_bound = true;
this.$$set(props);
this.$$.skip_bound = false;
}
}
}
/**
* @typedef {Object} CustomElementPropDefinition
* @property {string} [attribute]
* @property {boolean} [reflect]
* @property {'String'|'Boolean'|'Number'|'Array'|'Object'} [type]
*/
// generated during release, do not modify
const PUBLIC_VERSION = '4';
if (typeof window !== 'undefined')
// @ts-ignore
(window.__svelte || (window.__svelte = { v: new Set() })).v.add(PUBLIC_VERSION);
const subscriber_queue = [];
/**
* Creates a `Readable` store that allows reading by subscription.
*
* https://svelte.dev/docs/svelte-store#readable
* @template T
* @param {T} [value] initial value
* @param {import('./public.js').StartStopNotifier<T>} [start]
* @returns {import('./public.js').Readable<T>}
*/
function readable(value, start) {
return {
subscribe: writable(value, start).subscribe
};
}
/**
* Create a `Writable` store that allows both updating and reading by subscription.
*
* https://svelte.dev/docs/svelte-store#writable
* @template T
* @param {T} [value] initial value
* @param {import('./public.js').StartStopNotifier<T>} [start]
* @returns {import('./public.js').Writable<T>}
*/
function writable(value, start = noop) {
/** @type {import('./public.js').Unsubscriber} */
let stop;
/** @type {Set<import('./private.js').SubscribeInvalidateTuple<T>>} */
const subscribers = new Set();
/** @param {T} new_value
* @returns {void}
*/
function set(new_value) {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (stop) {
// store is ready
const run_queue = !subscriber_queue.length;
for (const subscriber of subscribers) {
subscriber[1]();
subscriber_queue.push(subscriber, value);
}
if (run_queue) {
for (let i = 0; i < subscriber_queue.length; i += 2) {
subscriber_queue[i][0](subscriber_queue[i + 1]);
}
subscriber_queue.length = 0;
}
}
}
}
/**
* @param {import('./public.js').Updater<T>} fn
* @returns {void}
*/
function update(fn) {
set(fn(value));
}
/**
* @param {import('./public.js').Subscriber<T>} run
* @param {import('./private.js').Invalidator<T>} [invalidate]
* @returns {import('./public.js').Unsubscriber}
*/
function subscribe(run, invalidate = noop) {
/** @type {import('./private.js').SubscribeInvalidateTuple<T>} */
const subscriber = [run, invalidate];
subscribers.add(subscriber);
if (subscribers.size === 1) {
stop = start(set, update) || noop;
}
run(value);
return () => {
subscribers.delete(subscriber);
if (subscribers.size === 0 && stop) {
stop();
stop = null;
}
};
}
return { set, update, subscribe };
}
/**
* Derived value store by synchronizing one or more readable stores and
* applying an aggregation function over its input values.
*
* https://svelte.dev/docs/svelte-store#derived
* @template {import('./private.js').Stores} S
* @template T
* @overload
* @param {S} stores - input stores
* @param {(values: import('./private.js').StoresValues<S>, set: (value: T) => void, update: (fn: import('./public.js').Updater<T>) => void) => import('./public.js').Unsubscriber | void} fn - function callback that aggregates the values
* @param {T} [initial_value] - initial value
* @returns {import('./public.js').Readable<T>}
*/
/**
* Derived value store by synchronizing one or more readable stores and
* applying an aggregation function over its input values.
*
* https://svelte.dev/docs/svelte-store#derived
* @template {import('./private.js').Stores} S
* @template T
* @overload
* @param {S} stores - input stores
* @param {(values: import('./private.js').StoresValues<S>) => T} fn - function callback that aggregates the values
* @param {T} [initial_value] - initial value
* @returns {import('./public.js').Readable<T>}
*/
/**
* @template {import('./private.js').Stores} S
* @template T
* @param {S} stores
* @param {Function} fn
* @param {T} [initial_value]
* @returns {import('./public.js').Readable<T>}
*/
function derived(stores, fn, initial_value) {
const single = !Array.isArray(stores);
/** @type {Array<import('./public.js').Readable<any>>} */
const stores_array = single ? [stores] : stores;
if (!stores_array.every(Boolean)) {
throw new Error('derived() expects stores as input, got a falsy value');
}
const auto = fn.length < 2;
return readable(initial_value, (set, update) => {
let started = false;
const values = [];
let pending = 0;
let cleanup = noop;
const sync = () => {
if (pending) {
return;
}
cleanup();
const result = fn(single ? values[0] : values, set, update);
if (auto) {
set(result);
} else {
cleanup = is_function(result) ? result : noop;
}
};
const unsubscribers = stores_array.map((store, i) =>
subscribe(
store,
(value) => {
values[i] = value;
pending &= ~(1 << i);
if (started) {
sync();
}
},
() => {
pending |= 1 << i;
}
)
);
started = true;
sync();
return function stop() {
run_all(unsubscribers);
cleanup();
// We need to set this to false because callbacks can still happen despite having unsubscribed:
// Callbacks might already be placed in the queue which doesn't know it should no longer
// invoke this derived store.
started = false;
};
});
}
function createEntityStore() {
const { subscribe, set, update } = writable({ ids: [], entities: {} });
return {
set,
_update: update,
subscribe,
add: (item) => update(({ ids, entities }) => ({
ids: [...ids, item.model.id],
entities: {
...entities,
[item.model.id]: item
}
})),
delete: (id) => update(state => {
const { [id]: _, ...entities } = state.entities;
return {
ids: state.ids.filter(i => i !== id),
entities
};
}),
deleteAll: (ids) => update(state => {
const entities = { ...state.entities };
const idSet = new Set(ids);
for (let i = 0; i < state.ids.length; i++) {
if (idSet.has(state.ids[i])) {
delete entities[state.ids[i]];
}
}
return {
ids: state.ids.filter(i => !idSet.has(i)),
entities
};
}),
update: (item) => update(({ ids, entities }) => ({
ids,
entities: {
...entities,
[item.model.id]: item
}
})),
upsert: (item) => update(({ ids, entities }) => {
const hasIndex = ids.indexOf(item.model.id) !== -1;
return {
ids: hasIndex ? ids : [...ids, item.model.id],
entities: {
...entities,
[item.model.id]: item
}
};
}),
upsertAll: (items) => update(state => {
const entities = { ...state.entities };
const ids = [...state.ids];
for (let i = 0; i < items.length; i++) {
if (ids.indexOf(items[i].model.id) === -1) {
ids.push(items[i].model.id);
}
entities[items[i].model.id] = items[i];
}
return {
ids,
entities
};
}),
addAll: (items) => {
const ids = [];
const entities = {};
for (let i = 0; i < items.length; i++) {
ids.push(items[i].model.id);
entities[items[i].model.id] = items[i];
}
set({ ids, entities });
},
refresh: () => update(store => ({ ...store }))
};
}
function all(store) {
return derived(store, ({ ids, entities }) => {
const results = [];
for (let i = 0; i < ids.length; i++) {
results.push(entities[ids[i]]);
}
return results;
});
}
function createDataStore() {
const taskStore = createEntityStore();
const rowStore = createEntityStore();
const timeRangeStore = createEntityStore();
const allTasks = all(taskStore);
const allRows = all(rowStore);
const allTimeRanges = all(timeRangeStore);
const rowTaskCache = derived(allTasks, $allTasks => {
const cache = {};
for (let i = 0; i < $allTasks.length; i++) {
const task = $allTasks[i];
if (!cache[task.model.resourceId]) {
cache[task.model.resourceId] = [];
}
cache[task.model.resourceId].push(task.model.id);
}
return cache;
});
return {
taskStore,
rowStore,
timeRangeStore,
allTasks,
allRows,
allTimeRanges,
rowTaskCache
};
}
function isLeftClick(event) {
return event.which === 1;
}
/**
* Gets mouse position within an element
* @param node
* @param event
*/
function getRelativePos(node, event) {
const rect = node.getBoundingClientRect();
const x = event.clientX - rect.left; //x position within the element.
const y = event.clientY - rect.top; //y position within the element.
return {
x: x,
y: y
};
}
function getRelativePosition(node, event) {
const rect = node.getBoundingClientRect();
const x = event.clientX - rect.left; //x position within the element.
const y = event.clientY - rect.top; //y position within the element.
return [x, y];
}
/**
* Adds an event listener that triggers once.
* @param target
* @param type
* @param listener
* @param addOptions
* @param removeOptions
*/
function addEventListenerOnce(target, type, listener, addOptions, removeOptions) {
target.addEventListener(type, function fn() {
target.removeEventListener(type, fn, removeOptions);
listener.apply(this, arguments, addOptions);
});
}
/**
* Sets the cursor on an element. Globally by default.
* @param cursor
* @param node
*/
function setCursor(cursor, node = document.body) {
node.style.cursor = cursor;
}
function normalizeClassAttr(classes) {
if (!classes) {
return '';
}
if (typeof classes === 'string') {
return classes;
}
if (Array.isArray(classes)) {
return classes.join(' ');
}
return '';
}
function throttle(func, limit) {
let wait = false;
return function () {
if (!wait) {
func.apply(null, arguments);
wait = true;
setTimeout(function () {
wait = false;
}, limit);
}
};
}
/** How much pixels near the bounds user has to drag to start scrolling */
const DRAGGING_TO_SCROLL_TRESHOLD = 40;
/** How much pixels does the view scroll when dragging */
const DRAGGING_TO_SCROLL_DELTA = 40;
function outOfBounds(event, rect) {
return {
left: event.clientX - rect.left < 0 + DRAGGING_TO_SCROLL_TRESHOLD,
top: event.clientY - rect.top < 0 + DRAGGING_TO_SCROLL_TRESHOLD,
right: event.clientX - rect.left > rect.width - DRAGGING_TO_SCROLL_TRESHOLD,
bottom: event.clientY - rect.top > rect.height - DRAGGING_TO_SCROLL_TRESHOLD
};
}
const scrollIfOutOfBounds = throttle((event, scrollable) => {
// throttle the following
const mainContainerRect = scrollable.getBoundingClientRect();
const bounds = outOfBounds(event, mainContainerRect);
if (bounds.left || bounds.right) {
// scroll left
scrollable.scrollTo({
left: scrollable.scrollLeft + (bounds.left ? -DRAGGING_TO_SCROLL_DELTA : DRAGGING_TO_SCROLL_DELTA),
behavior: 'smooth'
});
}
if (bounds.top || bounds.bottom) {
// scroll top
scrollable.scrollTo({
top: scrollable.scrollTop + (bounds.top ? -DRAGGING_TO_SCROLL_DELTA : DRAGGING_TO_SCROLL_DELTA),
behavior: 'smooth'
});
}
}, 250);
function getRowAtPoint(event) {
const elements = document.elementsFromPoint(event.clientX, event.clientY);
const rowElement = elements.find(element => !!element.getAttribute('data-row-id'));
if (rowElement !== undefined) {
const rowId = rowElement.getAttribute('data-row-id');
return rowId;
}
return null;
}
function whenEnterPress(callback) {
return (e) => {
if (e.key === 'Enter') {
callback(e);
}
};
}
function createUtils(params) {
return {
/**
* Returns position of date on a line if from and to represent length of width
* @param {*} date
*/
getPositionByDate(date) {
return getPositionByDate(date, params.from, params.to, params.width);
},
getDateByPosition(x) {
return getDateByPosition(x, params.from, params.to, params.width);
},
roundTo(date) {
if (params.dateAdapter) {
return params.dateAdapter.roundTo(date, params.magnetUnit, params.magnetOffset);
}
// this does not consider the timezone, rounds only to the UTC time
// let value = Math.round((date - 7200000) / params.magnetDuration) * params.magnetDuration;
// cases where rounding to day or timezone offset is not rounded, this won't work
return null;
}
};
}
function getPositionByDate(date, from, to, width) {
if (!date) {
return undefined;
}
const durationTo = date - from;
const durationToEnd = to - from;
return (durationTo / durationToEnd) * width;
}
function getDateByPosition(x, from, to, width) {
const durationTo = (x / width) * (to - from);
const dateAtPosition = from + durationTo;
return dateAtPosition;
}
// Returns the object on the left and right in an array using the given cmp function.
// The compare function defined which property of the value to compare (e.g.: c => c.left)
function getIndicesOnly(input, value, comparer, strict) {
let lo = -1;
let hi = input.length;
while (hi - lo > 1) {
const mid = Math.floor((lo + hi) / 2);
if (strict ? comparer(input[mid]) < value : comparer(input[mid]) <= value) {
lo = mid;
}
else {
hi = mid;
}
}
if (!strict && input[lo] !== undefined && comparer(input[lo]) === value) {
hi = lo;
}
return [lo, hi];
}
function get(input, value, comparer, strict) {
const res = getIndicesOnly(input, value, comparer, strict);
return [input[res[0]], input[res[1]]];
}
function isDraggable(item) {
return item.draggable ?? item.enableDragging ?? true;
}
function isResizable(item) {
return item.resizable ?? item.enableResize ?? true;
}
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z$e = ".sg-label-bottom.svelte-e1wt24.svelte-e1wt24{position:absolute;top:calc(100% + 10px);color:#888}.sg-task.svelte-e1wt24.svelte-e1wt24{position:absolute;border-radius:2px;white-space:nowrap;transition:background-color 0.2s,\n opacity 0.2s;pointer-events:all;touch-action:none}.sg-task-background.svelte-e1wt24.svelte-e1wt24{position:absolute;height:100%;top:0}.sg-task-content.svelte-e1wt24.svelte-e1wt24{position:absolute;height:100%;top:0;padding-left:14px;font-size:14px;display:flex;align-items:center;justify-content:flex-start;user-select:none}.sg-task.animating.svelte-e1wt24.svelte-e1wt24:not(.moving),.sg-task--sticky.svelte-e1wt24.svelte-e1wt24:not(.moving){transition:left 0.2s,\n top 0.2s,\n transform 0.2s,\n background-color 0.2s,\n width 0.2s,\n height 0.2s}.sg-task--sticky.svelte-e1wt24>.sg-task-content.svelte-e1wt24{position:sticky;left:0;max-width:100px}.sg-task.moving.svelte-e1wt24.svelte-e1wt24{z-index:10000;opacity:0.5}.sg-task.resize-enabled.svelte-e1wt24.svelte-e1wt24:hover::before,.sg-task.resize-enabled.svelte-e1wt24.svelte-e1wt24:hover::after{content:'';width:4px;height:50%;top:25%;position:absolute;border-style:solid;border-color:var(--sg-task-resize-color);cursor:ew-resize;border-width:0 1px;z-index:1}.sg-task.resize-enabled.svelte-e1wt24.svelte-e1wt24:hover::before{margin-left:3px;left:0}.sg-task.resize-enabled.svelte-e1wt24.svelte-e1wt24:hover::after{margin-right:3px;right:0}.sg-task-reflected.svelte-e1wt24.svelte-e1wt24{opacity:0.5}.sg-task-instant.svelte-e1wt24.svelte-e1wt24{width:2px !important;margin-left:-1px}.sg-task-background.svelte-e1wt24.svelte-e1wt24{background:rgba(0, 0, 0, 0.2)}.sg-task-default{color:white;background:rgb(116, 191, 255)}.sg-task-default:hover{background:rgb(98, 161, 216)}.sg-task-default.selected{background:rgb(69, 112, 150)}.sg-task-selected{outline:2px solid var(--sg-task-selected-outline-color);outline-offset:3px;z-index:1}.sg-milestone.svelte-e1wt24.svelte-e1wt24{width:20px !important;min-width:40px;margin-left:-20px}.sg-task.sg-milestone.svelte-e1wt24.svelte-e1wt24{background:transparent}.sg-milestone.svelte-e1wt24 .sg-milestone__diamond.svelte-e1wt24{position:relative}.sg-milestone.svelte-e1wt24 .sg-milestone__diamond.svelte-e1wt24:before{position:absolute;top:0;left:50%;content:' ';height:28px;width:28px;transform-origin:0 0;transform:rotate(45deg)}.sg-milestone__diamond:before{background:rgb(116, 191, 255)}";
styleInject(css_248z$e);
/* src/entities/Task.svelte generated by Svelte v4.2.19 */
function create_if_block_5$1(ctx) {
let div;
return {
c() {
div = element("div");
attr(div, "class", "sg-milestone__diamond svelte-e1wt24");
},
m(target, anchor) {
insert(target, div, anchor);
},
d(detaching) {
if (detaching) {
detach(div);
}
}
};
}
// (59:4) {#if model.amountDone}
function create_if_block_4$1(ctx) {
let div;
return {
c() {
div = element("div");
attr(div, "class", "sg-task-background svelte-e1wt24");
set_style(div, "width", /*model*/ ctx[0].amountDone + "%");
},
m(target, anchor) {
insert(target, div, anchor);
},
p(ctx, dirty) {
if (dirty & /*model*/ 1) {
set_style(div, "width", /*model*/ ctx[0].amountDone + "%");
}
},
d(detaching) {
if (detaching) {
detach(div);
}
}
};
}
// (67:8) {:else}
function create_else_block$3(ctx) {
let t_value = /*model*/ ctx[0].label + "";
let t;
return {
c() {
t = text(t_value);
},
m(target, anchor) {
insert(target, t, anchor);
},
p(ctx, dirty) {
if (dirty & /*model*/ 1 && t_value !== (t_value = /*model*/ ctx[0].label + "")) set_data(t, t_valu