1
0
Fork 0
mirror of synced 2024-06-03 03:14:50 +12:00
appwrite/public/scripts/views/service.js
2021-08-08 18:57:06 +03:00

439 lines
13 KiB
JavaScript

(function(window) {
"use strict";
window.ls.view.add({
selector: "data-service",
controller: function(element, view, container, form, alerts, expression, window) {
let action = element.dataset["service"];
let service = element.dataset["name"] || null;
let event = expression.parse(element.dataset["event"]); // load, click, change, submit
let confirm = element.dataset["confirm"] || ""; // Free text
let loading = element.dataset["loading"] || ""; // Free text
let loaderId = null;
let scope = element.dataset["scope"] || "sdk"; // Free text
let success = element.dataset["success"] || "";
let failure = element.dataset["failure"] || "";
let running = false;
let callbacks = {
hide: function() {
return function() {
return element.style.opacity = '0';
};
},
reset: function() {
return function() {
if ("FORM" === element.tagName) {
return element.reset();
}
throw new Error("This callback is only valid for forms");
};
},
alert: function(text, classname) {
return function(alerts) {
alerts.add({ text: text, class: classname || "success" }, 3000);
};
},
redirect: function(url) {
return function(router) {
//router.change(url || "/");
window.location = url || "/";
};
},
reload: function() {
return function(router) {
router.reload();
};
},
state: function(keys) {
let updateQueryString = function(key, value, url) {
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"),
hash;
if (re.test(url)) {
if (typeof value !== "undefined" && value !== null) {
return url.replace(re, "$1" + key + "=" + value + "$2$3");
} else {
hash = url.split("#");
url = hash[0].replace(re, "$1$3").replace(/(&|\?)$/, "");
if (typeof hash[1] !== "undefined" && hash[1] !== null) {
url += "#" + hash[1];
}
return url;
}
} else {
if (typeof value !== "undefined" && value !== null) {
var separator = url.indexOf("?") !== -1 ? "&" : "?";
hash = url.split("#");
url = hash[0] + separator + key + "=" + value;
if (typeof hash[1] !== "undefined" && hash[1] !== null) {
url += "#" + hash[1];
}
return url;
} else {
return url;
}
}
};
keys = keys.split(",").map(element => element.trim());
return function(serviceForm, router, window) {
let url = window.location.href;
keys.map(node => {
node = node.split("=");
let key = node[0] || "";
let name = node[1] || key;
let value = getValue(key, "param", serviceForm);
url = updateQueryString(name, value ? value : null, url);
});
if (url !== window.location.href) {
window.history.pushState({}, "", url);
router.reset();
}
};
},
trigger: function(events) {
return function(document) {
events = events.trim().split(",");
for (let i = 0; i < events.length; i++) {
if ("" === events[i]) {
continue;
}
document.dispatchEvent(new CustomEvent(events[i]));
}
};
},
setId: function name(params) {
},
default: function() {
let collection = container.get('project-collection');
let document = container.get('project-document');
if(collection && document && collection.$id === document.$id) {
for (const [key, value] of Object.entries(document)) {
delete document[key];
}
if(collection.rules) {
for (let index = 0; index < collection.rules.length; index++) {
const element = collection.rules[index];
switch (element.type) {
case 'text':
case 'email':
case 'url':
case 'ip':
document[element.key] = element.default || '';
break;
case 'numeric':
document[element.key] = element.default || '0';
break;
case 'boolean':
document[element.key] = element.default || false;
break;
case 'document':
document[element.key] = element.default || {'$id': '', '$collection': '', '$permissions': {}};
break;
default:
document[element.key] = null;
break;
}
if(element.array) {
document[element.key] = [];
}
}
}
}
}
};
/**
* Original Solution From:
* @see https://stackoverflow.com/a/41322698/2299554
* Notice: this version add support for $ sign in arg name.
*
* Retrieve a function's parameter names and default values
* Notes:
* - parameters with default values will not show up in transpiler code (Babel) because the parameter is removed from the function.
* - does NOT support inline arrow functions as default values
* to clarify: ( name = "string", add = defaultAddFunction ) - is ok
* ( name = "string", add = ( a )=> a + 1 ) - is NOT ok
* - does NOT support default string value that are appended with a non-standard ( word characters or $ ) variable name
* to clarify: ( name = "string" + b ) - is ok
* ( name = "string" + $b ) - is ok
* ( name = "string" + b + "!" ) - is ok
* ( name = "string" + λ ) - is NOT ok
* @param {function} func
* @returns {Array} - An array of the given function's parameter [key, default value] pairs.
*/
let getParams = function getParams(func) {
const REGEX_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
const REGEX_FUNCTION_PARAMS = /(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;
const REGEX_PARAMETERS_VALUES = /\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;
let functionAsString = func.toString();
let params = [];
let match;
functionAsString = functionAsString.replaceAll('={}', "");
functionAsString = functionAsString.replaceAll('=[]', "");
functionAsString = functionAsString.replace(REGEX_COMMENTS, "");
functionAsString = functionAsString.match(REGEX_FUNCTION_PARAMS)[1];
if (functionAsString.charAt(0) === "(") {
functionAsString = functionAsString.slice(1, -1);
}
while ((match = REGEX_PARAMETERS_VALUES.exec(functionAsString))) {
//params.push([match[1], match[2]]); // with default values
params.push(match[1]); // only with arg name
}
return params;
};
let getValue = function(key, prefix, data) {
let result = null;
if (!key) {
return null;
}
let attrKey = prefix + key.charAt(0).toUpperCase() + key.slice(1);
/**
* 1. Get from element data-param-* (expression supported)
* 2. Get from element form object-*
*/
if (element.dataset[attrKey]) {
result = expression.parse(element.dataset[attrKey]);
if (element.dataset[attrKey + "CastTo"] === "array") {
result = result.split(",");
}
}
if (typeof data[key] !== 'undefined') {
result = data[key];
}
if (typeof result === 'undefined') {
result = "";
}
return result;
};
let resolve = function(target, prefix = "param", data = {}) {
if (!target) {
return function() {};
}
let args = getParams(target);
return target.apply(
target,
args.map(function(value) {
let result = getValue(value, prefix, data);
return result ?? undefined;
})
);
};
let exec = function(event) {
let parsedSuccess = expression.parse(success);
let parsedFailure = expression.parse(failure);
let parsedAction = expression.parse(action);
parsedSuccess =
parsedSuccess && parsedSuccess != ""
? parsedSuccess.split(",").map(element => element.trim())
: [];
parsedFailure =
parsedFailure && parsedFailure != ""
? parsedFailure.split(",").map(element => element.trim())
: [];
element.$lsSkip = true;
element.classList.add("load-service-start");
if (!document.body.contains(element)) {
element = undefined;
return false;
}
if (event) {
event.preventDefault();
}
if(running) {
return false;
}
running = true;
element.style.backgroud = 'red';
if (confirm) {
if (window.confirm(confirm) !== true) {
element.classList.add("load-service-end");
element.$lsSkip = false;
running = false;
return false;
}
}
if (loading) {
loaderId = alerts.add({ text: loading, class: "" }, 0);
}
let method = container.path(scope + "." + parsedAction);
if (!method) {
throw new Error('Method "' + scope + "." + parsedAction + '" not found');
}
let formData = "FORM" === element.tagName ? form.toJson(element) : {};
let result = resolve(method, "param", formData);
if (!result) {
return;
}
if(Promise.resolve(result) != result) {
result = new Promise((resolve, reject) => {
resolve(result);
});
}
result.then(
function(data) {
if (loaderId !== null) {
// Remove loader if needed
alerts.remove(loaderId);
}
if (!element) {
return;
}
running = false;
element.style.backgroud = 'transparent';
element.classList.add("load-service-end");
if(service) {
container.set(service.replace(".", "-"), data, true, true);
}
container.set("serviceData", data, true, true);
container.set("serviceForm", formData, true, true);
for (let i = 0; i < parsedSuccess.length; i++) {
// Trigger success callbacks
container.resolve(
resolve(
callbacks[parsedSuccess[i]],
"successParam" +
parsedSuccess[i].charAt(0).toUpperCase() +
parsedSuccess[i].slice(1),
{}
)
);
}
container.set("serviceData", null, true, true);
container.set("serviceForm", null, true, true);
element.$lsSkip = false;
view.render(element);
},
function(exception) {
console.error(exception);
if (loaderId !== null) {
// Remove loader if needed
alerts.remove(loaderId);
}
if (!element) {
return;
}
running = false;
element.style.backgroud = 'transparent';
element.classList.add("load-service-end");
for (let i = 0; i < parsedFailure.length; i++) {
// Trigger failure callbacks
container.resolve(
resolve(
callbacks[parsedFailure[i]],
"failureParam" +
parsedFailure[i].charAt(0).toUpperCase() +
parsedFailure[i].slice(1),
{}
)
);
}
element.$lsSkip = false;
view.render(element);
}
);
};
let events = event.trim().split(",");
for (let y = 0; y < events.length; y++) {
if ("" === events[y]) {
continue;
}
switch (events[y].trim()) {
case "load":
exec();
break;
case "none":
break;
case "click":
case "change":
case "keypress":
case "keydown":
case "keyup":
case "input":
case "submit":
element.addEventListener(events[y], exec);
break;
default:
document.addEventListener(events[y], exec);
}
}
}
});
})(window);