mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
working canvas_note PoC save and load for one note
This commit is contained in:
parent
12185fbd32
commit
bd28ed07d7
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Returns a function, that, as long as it continues to be invoked, will not
|
||||||
|
* be triggered. The function will be called after it stops being called for
|
||||||
|
* N milliseconds. If `immediate` is passed, trigger the function on the
|
||||||
|
* leading edge, instead of the trailing. The function also has a property 'clear'
|
||||||
|
* that is a function which will clear the timer to prevent previously scheduled executions.
|
||||||
|
*
|
||||||
|
* @source underscore.js
|
||||||
|
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
|
||||||
|
* @param {Function} function to wrap
|
||||||
|
* @param {Number} timeout in ms (`100`)
|
||||||
|
* @param {Boolean} whether to execute at the beginning (`false`)
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
function debounce(func, wait_ms, immediate){
|
||||||
|
var timeout, args, context, timestamp, result;
|
||||||
|
if (null == wait_ms) wait_ms = 100;
|
||||||
|
|
||||||
|
function later() {
|
||||||
|
var last = Date.now() - timestamp;
|
||||||
|
|
||||||
|
if (last < wait_ms && last >= 0) {
|
||||||
|
timeout = setTimeout(later, wait_ms - last);
|
||||||
|
} else {
|
||||||
|
timeout = null;
|
||||||
|
if (!immediate) {
|
||||||
|
result = func.apply(context, args);
|
||||||
|
context = args = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var debounced = function(){
|
||||||
|
context = this;
|
||||||
|
args = arguments;
|
||||||
|
timestamp = Date.now();
|
||||||
|
var callNow = immediate && !timeout;
|
||||||
|
if (!timeout) timeout = setTimeout(later, wait_ms);
|
||||||
|
if (callNow) {
|
||||||
|
result = func.apply(context, args);
|
||||||
|
context = args = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
debounced.clear = function() {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debounced.flush = function() {
|
||||||
|
if (timeout) {
|
||||||
|
result = func.apply(context, args);
|
||||||
|
context = args = null;
|
||||||
|
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return debounced;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Adds compatibility for ES modules
|
||||||
|
debounce.debounce = debounce;
|
||||||
|
|
||||||
|
export default debounce;
|
@ -0,0 +1,439 @@
|
|||||||
|
/**
|
||||||
|
* lodash (Custom Build) <https://lodash.com/>
|
||||||
|
* Build: `lodash modularize exports="npm" -o ./`
|
||||||
|
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
||||||
|
* Released under MIT license <https://lodash.com/license>
|
||||||
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||||
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Used as the `TypeError` message for "Functions" methods. */
|
||||||
|
var FUNC_ERROR_TEXT = 'Expected a function';
|
||||||
|
|
||||||
|
/** Used as references for various `Number` constants. */
|
||||||
|
var NAN = 0 / 0;
|
||||||
|
|
||||||
|
/** `Object#toString` result references. */
|
||||||
|
var symbolTag = '[object Symbol]';
|
||||||
|
|
||||||
|
/** Used to match leading and trailing whitespace. */
|
||||||
|
var reTrim = /^\s+|\s+$/g;
|
||||||
|
|
||||||
|
/** Used to detect bad signed hexadecimal string values. */
|
||||||
|
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
|
||||||
|
|
||||||
|
/** Used to detect binary string values. */
|
||||||
|
var reIsBinary = /^0b[01]+$/i;
|
||||||
|
|
||||||
|
/** Used to detect octal string values. */
|
||||||
|
var reIsOctal = /^0o[0-7]+$/i;
|
||||||
|
|
||||||
|
/** Built-in method references without a dependency on `root`. */
|
||||||
|
var freeParseInt = parseInt;
|
||||||
|
|
||||||
|
/** Detect free variable `global` from Node.js. */
|
||||||
|
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
|
||||||
|
|
||||||
|
/** Detect free variable `self`. */
|
||||||
|
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
|
||||||
|
|
||||||
|
/** Used as a reference to the global object. */
|
||||||
|
var root = freeGlobal || freeSelf || Function('return this')();
|
||||||
|
|
||||||
|
/** Used for built-in method references. */
|
||||||
|
var objectProto = Object.prototype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to resolve the
|
||||||
|
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
||||||
|
* of values.
|
||||||
|
*/
|
||||||
|
var objectToString = objectProto.toString;
|
||||||
|
|
||||||
|
/* Built-in method references for those with the same name as other `lodash` methods. */
|
||||||
|
var nativeMax = Math.max,
|
||||||
|
nativeMin = Math.min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp of the number of milliseconds that have elapsed since
|
||||||
|
* the Unix epoch (1 January 1970 00:00:00 UTC).
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @since 2.4.0
|
||||||
|
* @category Date
|
||||||
|
* @returns {number} Returns the timestamp.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* _.defer(function(stamp) {
|
||||||
|
* console.log(_.now() - stamp);
|
||||||
|
* }, _.now());
|
||||||
|
* // => Logs the number of milliseconds it took for the deferred invocation.
|
||||||
|
*/
|
||||||
|
var now = function() {
|
||||||
|
return root.Date.now();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a debounced function that delays invoking `func` until after `wait`
|
||||||
|
* milliseconds have elapsed since the last time the debounced function was
|
||||||
|
* invoked. The debounced function comes with a `cancel` method to cancel
|
||||||
|
* delayed `func` invocations and a `flush` method to immediately invoke them.
|
||||||
|
* Provide `options` to indicate whether `func` should be invoked on the
|
||||||
|
* leading and/or trailing edge of the `wait` timeout. The `func` is invoked
|
||||||
|
* with the last arguments provided to the debounced function. Subsequent
|
||||||
|
* calls to the debounced function return the result of the last `func`
|
||||||
|
* invocation.
|
||||||
|
*
|
||||||
|
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
||||||
|
* invoked on the trailing edge of the timeout only if the debounced function
|
||||||
|
* is invoked more than once during the `wait` timeout.
|
||||||
|
*
|
||||||
|
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
||||||
|
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
|
||||||
|
*
|
||||||
|
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
||||||
|
* for details over the differences between `_.debounce` and `_.throttle`.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @since 0.1.0
|
||||||
|
* @category Function
|
||||||
|
* @param {Function} func The function to debounce.
|
||||||
|
* @param {number} [wait=0] The number of milliseconds to delay.
|
||||||
|
* @param {Object} [options={}] The options object.
|
||||||
|
* @param {boolean} [options.leading=false]
|
||||||
|
* Specify invoking on the leading edge of the timeout.
|
||||||
|
* @param {number} [options.maxWait]
|
||||||
|
* The maximum time `func` is allowed to be delayed before it's invoked.
|
||||||
|
* @param {boolean} [options.trailing=true]
|
||||||
|
* Specify invoking on the trailing edge of the timeout.
|
||||||
|
* @returns {Function} Returns the new debounced function.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* // Avoid costly calculations while the window size is in flux.
|
||||||
|
* jQuery(window).on('resize', _.debounce(calculateLayout, 150));
|
||||||
|
*
|
||||||
|
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
||||||
|
* jQuery(element).on('click', _.debounce(sendMail, 300, {
|
||||||
|
* 'leading': true,
|
||||||
|
* 'trailing': false
|
||||||
|
* }));
|
||||||
|
*
|
||||||
|
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
||||||
|
* var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
|
||||||
|
* var source = new EventSource('/stream');
|
||||||
|
* jQuery(source).on('message', debounced);
|
||||||
|
*
|
||||||
|
* // Cancel the trailing debounced invocation.
|
||||||
|
* jQuery(window).on('popstate', debounced.cancel);
|
||||||
|
*/
|
||||||
|
function debounce(func, wait, options) {
|
||||||
|
var lastArgs,
|
||||||
|
lastThis,
|
||||||
|
maxWait,
|
||||||
|
result,
|
||||||
|
timerId,
|
||||||
|
lastCallTime,
|
||||||
|
lastInvokeTime = 0,
|
||||||
|
leading = false,
|
||||||
|
maxing = false,
|
||||||
|
trailing = true;
|
||||||
|
|
||||||
|
if (typeof func != 'function') {
|
||||||
|
throw new TypeError(FUNC_ERROR_TEXT);
|
||||||
|
}
|
||||||
|
wait = toNumber(wait) || 0;
|
||||||
|
if (isObject(options)) {
|
||||||
|
leading = !!options.leading;
|
||||||
|
maxing = 'maxWait' in options;
|
||||||
|
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
|
||||||
|
trailing = 'trailing' in options ? !!options.trailing : trailing;
|
||||||
|
}
|
||||||
|
|
||||||
|
function invokeFunc(time) {
|
||||||
|
var args = lastArgs,
|
||||||
|
thisArg = lastThis;
|
||||||
|
|
||||||
|
lastArgs = lastThis = undefined;
|
||||||
|
lastInvokeTime = time;
|
||||||
|
result = func.apply(thisArg, args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function leadingEdge(time) {
|
||||||
|
// Reset any `maxWait` timer.
|
||||||
|
lastInvokeTime = time;
|
||||||
|
// Start the timer for the trailing edge.
|
||||||
|
timerId = setTimeout(timerExpired, wait);
|
||||||
|
// Invoke the leading edge.
|
||||||
|
return leading ? invokeFunc(time) : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function remainingWait(time) {
|
||||||
|
var timeSinceLastCall = time - lastCallTime,
|
||||||
|
timeSinceLastInvoke = time - lastInvokeTime,
|
||||||
|
result = wait - timeSinceLastCall;
|
||||||
|
|
||||||
|
return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldInvoke(time) {
|
||||||
|
var timeSinceLastCall = time - lastCallTime,
|
||||||
|
timeSinceLastInvoke = time - lastInvokeTime;
|
||||||
|
|
||||||
|
// Either this is the first call, activity has stopped and we're at the
|
||||||
|
// trailing edge, the system time has gone backwards and we're treating
|
||||||
|
// it as the trailing edge, or we've hit the `maxWait` limit.
|
||||||
|
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
|
||||||
|
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
|
||||||
|
}
|
||||||
|
|
||||||
|
function timerExpired() {
|
||||||
|
var time = now();
|
||||||
|
if (shouldInvoke(time)) {
|
||||||
|
return trailingEdge(time);
|
||||||
|
}
|
||||||
|
// Restart the timer.
|
||||||
|
timerId = setTimeout(timerExpired, remainingWait(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
function trailingEdge(time) {
|
||||||
|
timerId = undefined;
|
||||||
|
|
||||||
|
// Only invoke if we have `lastArgs` which means `func` has been
|
||||||
|
// debounced at least once.
|
||||||
|
if (trailing && lastArgs) {
|
||||||
|
return invokeFunc(time);
|
||||||
|
}
|
||||||
|
lastArgs = lastThis = undefined;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
if (timerId !== undefined) {
|
||||||
|
clearTimeout(timerId);
|
||||||
|
}
|
||||||
|
lastInvokeTime = 0;
|
||||||
|
lastArgs = lastCallTime = lastThis = timerId = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flush() {
|
||||||
|
return timerId === undefined ? result : trailingEdge(now());
|
||||||
|
}
|
||||||
|
|
||||||
|
function debounced() {
|
||||||
|
var time = now(),
|
||||||
|
isInvoking = shouldInvoke(time);
|
||||||
|
|
||||||
|
lastArgs = arguments;
|
||||||
|
lastThis = this;
|
||||||
|
lastCallTime = time;
|
||||||
|
|
||||||
|
if (isInvoking) {
|
||||||
|
if (timerId === undefined) {
|
||||||
|
return leadingEdge(lastCallTime);
|
||||||
|
}
|
||||||
|
if (maxing) {
|
||||||
|
// Handle invocations in a tight loop.
|
||||||
|
timerId = setTimeout(timerExpired, wait);
|
||||||
|
return invokeFunc(lastCallTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (timerId === undefined) {
|
||||||
|
timerId = setTimeout(timerExpired, wait);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
debounced.cancel = cancel;
|
||||||
|
debounced.flush = flush;
|
||||||
|
return debounced;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a throttled function that only invokes `func` at most once per
|
||||||
|
* every `wait` milliseconds. The throttled function comes with a `cancel`
|
||||||
|
* method to cancel delayed `func` invocations and a `flush` method to
|
||||||
|
* immediately invoke them. Provide `options` to indicate whether `func`
|
||||||
|
* should be invoked on the leading and/or trailing edge of the `wait`
|
||||||
|
* timeout. The `func` is invoked with the last arguments provided to the
|
||||||
|
* throttled function. Subsequent calls to the throttled function return the
|
||||||
|
* result of the last `func` invocation.
|
||||||
|
*
|
||||||
|
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
||||||
|
* invoked on the trailing edge of the timeout only if the throttled function
|
||||||
|
* is invoked more than once during the `wait` timeout.
|
||||||
|
*
|
||||||
|
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
||||||
|
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
|
||||||
|
*
|
||||||
|
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
||||||
|
* for details over the differences between `_.throttle` and `_.debounce`.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @since 0.1.0
|
||||||
|
* @category Function
|
||||||
|
* @param {Function} func The function to throttle.
|
||||||
|
* @param {number} [wait=0] The number of milliseconds to throttle invocations to.
|
||||||
|
* @param {Object} [options={}] The options object.
|
||||||
|
* @param {boolean} [options.leading=true]
|
||||||
|
* Specify invoking on the leading edge of the timeout.
|
||||||
|
* @param {boolean} [options.trailing=true]
|
||||||
|
* Specify invoking on the trailing edge of the timeout.
|
||||||
|
* @returns {Function} Returns the new throttled function.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* // Avoid excessively updating the position while scrolling.
|
||||||
|
* jQuery(window).on('scroll', _.throttle(updatePosition, 100));
|
||||||
|
*
|
||||||
|
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
|
||||||
|
* var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
|
||||||
|
* jQuery(element).on('click', throttled);
|
||||||
|
*
|
||||||
|
* // Cancel the trailing throttled invocation.
|
||||||
|
* jQuery(window).on('popstate', throttled.cancel);
|
||||||
|
*/
|
||||||
|
function throttle(func, wait, options) {
|
||||||
|
var leading = true,
|
||||||
|
trailing = true;
|
||||||
|
|
||||||
|
if (typeof func != 'function') {
|
||||||
|
throw new TypeError(FUNC_ERROR_TEXT);
|
||||||
|
}
|
||||||
|
if (isObject(options)) {
|
||||||
|
leading = 'leading' in options ? !!options.leading : leading;
|
||||||
|
trailing = 'trailing' in options ? !!options.trailing : trailing;
|
||||||
|
}
|
||||||
|
return debounce(func, wait, {
|
||||||
|
'leading': leading,
|
||||||
|
'maxWait': wait,
|
||||||
|
'trailing': trailing
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if `value` is the
|
||||||
|
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
||||||
|
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @since 0.1.0
|
||||||
|
* @category Lang
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* _.isObject({});
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* _.isObject([1, 2, 3]);
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* _.isObject(_.noop);
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* _.isObject(null);
|
||||||
|
* // => false
|
||||||
|
*/
|
||||||
|
function isObject(value) {
|
||||||
|
var type = typeof value;
|
||||||
|
return !!value && (type == 'object' || type == 'function');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if `value` is object-like. A value is object-like if it's not `null`
|
||||||
|
* and has a `typeof` result of "object".
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @since 4.0.0
|
||||||
|
* @category Lang
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* _.isObjectLike({});
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* _.isObjectLike([1, 2, 3]);
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* _.isObjectLike(_.noop);
|
||||||
|
* // => false
|
||||||
|
*
|
||||||
|
* _.isObjectLike(null);
|
||||||
|
* // => false
|
||||||
|
*/
|
||||||
|
function isObjectLike(value) {
|
||||||
|
return !!value && typeof value == 'object';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if `value` is classified as a `Symbol` primitive or object.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @since 4.0.0
|
||||||
|
* @category Lang
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* _.isSymbol(Symbol.iterator);
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* _.isSymbol('abc');
|
||||||
|
* // => false
|
||||||
|
*/
|
||||||
|
function isSymbol(value) {
|
||||||
|
return typeof value == 'symbol' ||
|
||||||
|
(isObjectLike(value) && objectToString.call(value) == symbolTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts `value` to a number.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @since 4.0.0
|
||||||
|
* @category Lang
|
||||||
|
* @param {*} value The value to process.
|
||||||
|
* @returns {number} Returns the number.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* _.toNumber(3.2);
|
||||||
|
* // => 3.2
|
||||||
|
*
|
||||||
|
* _.toNumber(Number.MIN_VALUE);
|
||||||
|
* // => 5e-324
|
||||||
|
*
|
||||||
|
* _.toNumber(Infinity);
|
||||||
|
* // => Infinity
|
||||||
|
*
|
||||||
|
* _.toNumber('3.2');
|
||||||
|
* // => 3.2
|
||||||
|
*/
|
||||||
|
function toNumber(value) {
|
||||||
|
if (typeof value == 'number') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (isSymbol(value)) {
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
if (isObject(value)) {
|
||||||
|
var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
|
||||||
|
value = isObject(other) ? (other + '') : other;
|
||||||
|
}
|
||||||
|
if (typeof value != 'string') {
|
||||||
|
return value === 0 ? value : +value;
|
||||||
|
}
|
||||||
|
value = value.replace(reTrim, '');
|
||||||
|
var isBinary = reIsBinary.test(value);
|
||||||
|
return (isBinary || reIsOctal.test(value))
|
||||||
|
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
|
||||||
|
: (reIsBadHex.test(value) ? NAN : +value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default throttle;
|
@ -0,0 +1,7 @@
|
|||||||
|
export const sleep = (time_ms) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, time_ms);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default sleep;
|
@ -1,6 +1,12 @@
|
|||||||
import libraryLoader from "../../services/library_loader.js";
|
import libraryLoader from "../../services/library_loader.js";
|
||||||
import TypeWidget from "./type_widget.js";
|
import TypeWidget from "./type_widget.js";
|
||||||
import appContext from "../../services/app_context.js";
|
import appContext from "../../services/app_context.js";
|
||||||
|
import _debounce from './canvas-note-utils/lodash.debounce.js';
|
||||||
|
import _throttle from './canvas-note-utils/lodash.throttle.js';
|
||||||
|
import sleep from './canvas-note-utils/sleep.js';
|
||||||
|
import froca from "../../services/froca.js";
|
||||||
|
import throttle from "./canvas-note-utils/lodash.throttle.js";
|
||||||
|
import debounce from "./canvas-note-utils/lodash.debounce.js";
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
<div
|
<div
|
||||||
@ -11,15 +17,6 @@ const TPL = `
|
|||||||
<div id="app" style="width:100%; height: 100%"></div>
|
<div id="app" style="width:100%; height: 100%"></div>
|
||||||
</div>
|
</div>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
.button-wrapper button {
|
|
||||||
z-index: 1;
|
|
||||||
height: 40px;
|
|
||||||
width: 100px;
|
|
||||||
margin: 10px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.excalidraw .App-menu_top .buttonList {
|
.excalidraw .App-menu_top .buttonList {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
@ -45,6 +42,12 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.ExcalidrawReactApp = this.ExcalidrawReactApp.bind(this);
|
this.ExcalidrawReactApp = this.ExcalidrawReactApp.bind(this);
|
||||||
|
this.doRefresh = this.doRefresh.bind(this);
|
||||||
|
this.getContent = this.getContent.bind(this);
|
||||||
|
this.saveData = this.saveData.bind(this);
|
||||||
|
this.refreshWithNote = this.refreshWithNote.bind(this);
|
||||||
|
this.onChangeHandler = this.onChangeHandler.bind(this);
|
||||||
|
window.triliumexcalidraw = this;
|
||||||
}
|
}
|
||||||
static getType() {
|
static getType() {
|
||||||
return "canvas-note";
|
return "canvas-note";
|
||||||
@ -69,34 +72,83 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
return this.$widget;
|
return this.$widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
// async doRefresh(note) {
|
async refreshWithNote(note) {
|
||||||
// // get note from backend and put into canvas
|
const noteComplement = await froca.getNoteComplement(note.noteId);
|
||||||
// const noteComplement = await this.tabContext.getNoteComplement();
|
const content = noteComplement.content || "";
|
||||||
// if (this.infiniteCanvas && noteComplement.content) {
|
console.log('refreshWithNote(note) called', content);
|
||||||
// const content = JSON.parse(noteComplement.content || "");
|
}
|
||||||
// await this.infiniteCanvas.setInfiniteCanvas(content);
|
|
||||||
// }
|
|
||||||
// console.log('doRefresh', note, noteComplement);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function gets data that will be sent via spacedUpdate.scheduleUpdate();
|
* called to populate the widget container with the note content
|
||||||
|
*
|
||||||
|
* @param {note} note
|
||||||
*/
|
*/
|
||||||
// getContent() {
|
async doRefresh(note) {
|
||||||
// const content = this.infiniteCanvas.getInfiniteCanvas();
|
console.log('doRefresh()', note);
|
||||||
// console.log('gC', content);
|
// get note from backend and put into canvas
|
||||||
// return JSON.stringify(content);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// saveData() {
|
console.log('sleep 1s...');
|
||||||
// this.spacedUpdate.scheduleUpdate();
|
await sleep(1000);
|
||||||
// }
|
|
||||||
|
const noteComplement = await froca.getNoteComplement(note.noteId);
|
||||||
|
console.log('doRefresh', note, noteComplement, noteComplement.content);
|
||||||
|
|
||||||
|
if (this.excalidrawRef.current && noteComplement.content) {
|
||||||
|
const content = JSON.parse(noteComplement.content || "");
|
||||||
|
const {elements, appState} = content;
|
||||||
|
|
||||||
|
console.log('doRefresh with this:', elements, appState);
|
||||||
|
|
||||||
|
const sceneData = {
|
||||||
|
elements,
|
||||||
|
appState,
|
||||||
|
collaborators: []
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("doRefresh(note) sceneData", sceneData);
|
||||||
|
this.excalidrawRef.current.updateScene(sceneData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets data from widget container that will be sent via spacedUpdate.scheduleUpdate();
|
||||||
|
*/
|
||||||
|
getContent() {
|
||||||
|
console.log('getContent()');
|
||||||
|
const time = new Date();
|
||||||
|
// const content = "hallöchen"+time.toUTCString();
|
||||||
|
|
||||||
|
const elements = this.excalidrawRef.current.getSceneElements();
|
||||||
|
const appState = this.excalidrawRef.current.getAppState();
|
||||||
|
|
||||||
|
const content = {
|
||||||
|
elements,
|
||||||
|
appState,
|
||||||
|
time
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('gC', content);
|
||||||
|
|
||||||
|
return JSON.stringify(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveData() {
|
||||||
|
console.log("saveData()");
|
||||||
|
this.spacedUpdate.scheduleUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeHandler() {
|
||||||
|
this.saveData();
|
||||||
|
}
|
||||||
|
|
||||||
ExcalidrawReactApp() {
|
ExcalidrawReactApp() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
const React = window.React;
|
const React = window.React;
|
||||||
const Excalidraw = window.Excalidraw;
|
const Excalidraw = window.Excalidraw;
|
||||||
|
|
||||||
const excalidrawRef = React.useRef(null);
|
const excalidrawRef = React.useRef(null);
|
||||||
|
self.excalidrawRef = excalidrawRef;
|
||||||
const excalidrawWrapperRef = React.useRef(null);
|
const excalidrawWrapperRef = React.useRef(null);
|
||||||
const [dimensions, setDimensions] = React.useState({
|
const [dimensions, setDimensions] = React.useState({
|
||||||
width: undefined,
|
width: undefined,
|
||||||
@ -106,56 +158,24 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
const [viewModeEnabled, setViewModeEnabled] = React.useState(false);
|
const [viewModeEnabled, setViewModeEnabled] = React.useState(false);
|
||||||
const [zenModeEnabled, setZenModeEnabled] = React.useState(false);
|
const [zenModeEnabled, setZenModeEnabled] = React.useState(false);
|
||||||
const [gridModeEnabled, setGridModeEnabled] = React.useState(false);
|
const [gridModeEnabled, setGridModeEnabled] = React.useState(false);
|
||||||
//
|
|
||||||
// React.useEffect(() => {
|
|
||||||
// setDimensions({
|
|
||||||
// width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
|
||||||
// height: excalidrawWrapperRef.current.getBoundingClientRect().height
|
|
||||||
// });
|
|
||||||
// const onResize = () => {
|
|
||||||
// setDimensions({
|
|
||||||
// width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
|
||||||
// height: excalidrawWrapperRef.current.getBoundingClientRect().height
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// window.addEventListener("resize", onResize);
|
|
||||||
//
|
|
||||||
// return () => window.removeEventListener("resize", onResize);
|
|
||||||
// }, [excalidrawWrapperRef]);
|
|
||||||
|
|
||||||
const updateScene = () => {
|
React.useEffect(() => {
|
||||||
const sceneData = {
|
setDimensions({
|
||||||
elements: [
|
width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
||||||
{
|
height: excalidrawWrapperRef.current.getBoundingClientRect().height
|
||||||
type: "rectangle",
|
});
|
||||||
version: 141,
|
const onResize = () => {
|
||||||
versionNonce: 361174001,
|
setDimensions({
|
||||||
isDeleted: false,
|
width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
||||||
id: "oDVXy8D6rom3H1-LLH2-f",
|
height: excalidrawWrapperRef.current.getBoundingClientRect().height
|
||||||
fillStyle: "hachure",
|
});
|
||||||
strokeWidth: 1,
|
|
||||||
strokeStyle: "solid",
|
|
||||||
roughness: 1,
|
|
||||||
opacity: 100,
|
|
||||||
angle: 0,
|
|
||||||
x: 100.50390625,
|
|
||||||
y: 93.67578125,
|
|
||||||
strokeColor: "#c92a2a",
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
width: 186.47265625,
|
|
||||||
height: 141.9765625,
|
|
||||||
seed: 1968410350,
|
|
||||||
groupIds: []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
appState: {
|
|
||||||
viewBackgroundColor: "#edf2ff"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
excalidrawRef.current.updateScene(sceneData);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.addEventListener("resize", onResize);
|
||||||
|
|
||||||
|
return () => window.removeEventListener("resize", onResize);
|
||||||
|
}, [excalidrawWrapperRef]);
|
||||||
|
|
||||||
return React.createElement(
|
return React.createElement(
|
||||||
React.Fragment,
|
React.Fragment,
|
||||||
null,
|
null,
|
||||||
@ -173,10 +193,18 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
onPaste: (data, event) => {
|
onPaste: (data, event) => {
|
||||||
console.log("tom", data, event);
|
console.log("tom", data, event);
|
||||||
},
|
},
|
||||||
onChange: (elements, state) =>
|
// onChange: (elements, state) => {
|
||||||
console.log("onChange Elements :", elements, "State : ", state),
|
// console.log("onChange Elements :", elements, "State : ", state)
|
||||||
|
// debounce(() => {
|
||||||
|
// console.log('called onChange via throttle');
|
||||||
|
// self.saveData();
|
||||||
|
// }, 400);
|
||||||
|
// },
|
||||||
|
onChange: debounce(self.onChangeHandler, 500),
|
||||||
// onPointerUpdate: (payload) => console.log(payload),
|
// onPointerUpdate: (payload) => console.log(payload),
|
||||||
onCollabButtonClick: () => window.alert("You clicked on collab button"),
|
onCollabButtonClick: () => {
|
||||||
|
window.alert("You clicked on collab button")
|
||||||
|
},
|
||||||
viewModeEnabled: viewModeEnabled,
|
viewModeEnabled: viewModeEnabled,
|
||||||
zenModeEnabled: zenModeEnabled,
|
zenModeEnabled: zenModeEnabled,
|
||||||
gridModeEnabled: gridModeEnabled,
|
gridModeEnabled: gridModeEnabled,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user