/**
* Modern Albufeira Prolog Interpreter
*
* Warranty & Liability
* To the extent permitted by applicable law and unless explicitly
* otherwise agreed upon, XLOG Technologies AG makes no warranties
* regarding the provided information. XLOG Technologies AG assumes
* no liability that any problems might be solved with the information
* provided by XLOG Technologies AG.
*
* Rights & License
* All industrial property rights regarding the information - copyright
* and patent rights in particular - are the sole property of XLOG
* Technologies AG. If the company was not the originator of some
* excerpts, XLOG Technologies AG has at least obtained the right to
* reproduce, change and translate the information.
*
* Reproduction is restricted to the whole unaltered document. Reproduction
* of the information is only allowed for non-commercial uses. Selling,
* giving away or letting of the execution of the library is prohibited.
* The library can be distributed as part of your applications and libraries
* for execution provided this comment remains unchanged.
*
* Restrictions
* Only to be distributed with programs that add significant and primary
* functionality to the library. Not to be distributed with additional
* software intended to replace any components of the library.
*
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
import {
set, check_atom, check_nonvar, Compound, check_integer,
copy_term, get_ctx, make_error, exec_build, callback,
norm_smallint, narrow_float, exec_unify, check_clause,
make_check, register_interrupt
} from "../../nova/core.mjs";
import {
check_element
} from "./../text/domlib.mjs";
/*****************************************************************/
/* DOM API II */
/*****************************************************************/
/**
* ir_cell_goto(I, E):
* The predicate succeeds in E with the element of id I.
*/
function test_ir_cell_goto(args) {
let id = exec_build(args[0]);
check_atom(id);
return exec_unify(args[1], document.getElementById(id));
}
/*****************************************************************/
/* Event Handling */
/*****************************************************************/
/**
* sys_cell_add_listener(E, T, N, F):
* The predicate adds a type T event handler compiled clause
* N to the element E with capture flag F.
*/
function test_sys_cell_add_listener(args) {
let at = exec_build(args[0]);
check_element(at);
let type = exec_build(args[1]);
check_atom(type);
let clause = exec_build(args[2]);
check_clause(clause);
let flag = exec_build(args[3]);
check_integer(flag);
let buf = get_ctx();
at.addEventListener(type, event => callback(clause, buf, [event]),
((flag & 1) !== 0));
return true;
}
/**
* sys_cell_wait_promise(E, T, N, F, Q):
* The predicate succeeds in Q with a promise that adds a type T
* event handler compiled clause N to the element E with capture
* flag F. If the event handler succeeds the promise resolves
* and then the event handler gets removed.
*/
function test_sys_cell_wait_promise(args) {
let buf = get_ctx();
let at = exec_build(args[0]);
check_element(at);
let type = exec_build(args[1]);
check_atom(type);
let clause = exec_build(args[2]);
check_clause(clause);
let flag = exec_build(args[3]);
check_integer(flag);
let prom = sys_cell_wait_promise(buf, at, type, clause, flag);
return exec_unify(args[4], prom);
}
function sys_cell_wait_promise(buf, at, type, clause, flag) {
return new Promise(resolve => {
function handler(event) {
if (callback(clause, buf, [event])) {
at.removeEventListener(type, handler);
register_interrupt(buf, () => {});
resolve();
}
}
at.addEventListener(type, handler, ((flag & 1) !== 0));
register_interrupt(buf, () => {
at.removeEventListener(type, handler);
register_interrupt(buf, () => {});
resolve();
});
});
}
/*****************************************************************/
/* Browser Behavior */
/*****************************************************************/
/**
* dom_prevent_default(E):
* The predicate prevents default behaviour and stops propagation of the event E.
*/
function test_dom_prevent_default(args) {
let event = exec_build(args[0]);
check_event(event);
event.preventDefault();
return true;
}
/**
* dom_stop_propagation(E):
* The predicate prevents default behaviour and stops propagation of the event E.
*/
function test_dom_stop_propagation(args) {
let event = exec_build(args[0]);
check_event(event);
event.stopPropagation();
return true;
}
function check_event(beta) {
if (!(beta instanceof Event)) {
check_nonvar(beta);
beta = copy_term(beta);
throw make_error(new Compound("type_error", ["event", beta]));
}
}
/*********************************************************************/
/* Window Selection */
/*********************************************************************/
/**
* ir_selection_current(E, A, F):
* The predicate succeeds in S with the anchor A and focus F.
*/
function test_ir_selection_current(args) {
let at = exec_build(args[0]);
check_element(at);
let sel = window.getSelection();
if (sel == null || !at.contains(sel.anchorNode) || !at.contains(sel.focusNode))
return false;
let anchor = get_offset(at, sel.anchorNode) + sel.anchorOffset;
let focus = get_offset(at, sel.focusNode) + sel.focusOffset;
return exec_unify(args[1], norm_smallint(anchor)) &&
exec_unify(args[2], norm_smallint(focus));
}
function get_offset(at, alpha) {
let offset = 0;
let walker = document.createTreeWalker(at, NodeFilter.SHOW_ALL);
let node = walker.nextNode();
while (node !== alpha) {
if (node instanceof Text)
offset += node.nodeValue.length;
node = walker.nextNode();
}
return offset;
}
/**
* ir_selection_set(E, A, F):
* The predicate succeeds. As a side effect it sets the anchor A and focus F in S.
*/
function test_ir_selection_set(args) {
let at = exec_build(args[0]);
check_element(at);
let anchor = exec_build(args[1]);
check_integer(anchor);
let focus = exec_build(args[2]);
check_integer(focus);
let first = get_point(at, narrow_float(anchor));
let second = get_point(at, narrow_float(focus));
try {
let sel = window.getSelection();
sel.collapse(first[0], first[1]);
sel.extend(second[0], second[1]);
} catch (err) {
throw make_error(new Compound("permission_error",
["selection", "modify", new Compound("-",
[anchor, focus])]));
}
return true;
}
function get_point(at, offset) {
let walker = document.createTreeWalker(at, NodeFilter.SHOW_TEXT);
let node = walker.nextNode();
while (node !== null) {
let len = node.nodeValue.length;
if (len >= offset)
return [node, offset];
offset -= len;
node = walker.nextNode();
}
return null;
}
/*********************************************************************/
/* Emit Lib Init */
/*********************************************************************/
export function main() {
set("ir_cell_goto", 2, make_check(test_ir_cell_goto));
set("sys_cell_add_listener", 4, make_check(test_sys_cell_add_listener));
set("sys_cell_wait_promise", 5, make_check(test_sys_cell_wait_promise));
set("dom_prevent_default", 1, make_check(test_dom_prevent_default));
set("dom_stop_propagation", 1, make_check(test_dom_stop_propagation));
set("ir_selection_current", 3, make_check(test_ir_selection_current));
set("ir_selection_set", 3, make_check(test_ir_selection_set));
}