ourthings/Queueable/Elements.js
/** @module ourthings/Queueable/Elements */
import Queueable from "../Queueable";
import {Validate, ValidateEmail, ValidatePassword, ValidateText} from "../Validator";
/**
* @classdesc
*
* Dom Elements manipulations
*
* @author Richard Reynolds richard@nautoguide.com
*
* @example
* elements.removeClass({"targetId":".leftPanel","class":"hidden"});
*
*/
export default class Elements extends Queueable {
/**
* Add a class to a dom element
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.iframeId - iframe target
* @param {string} json.targetId - Dom target
* @param {string} json.class - Name of class to add
*
* @example
* elements.addClass({"targetId":".leftPanel","class":"hidden"});
*/
addClass(pid, json) {
let self = this;
let elements = self.queue.getIframeElements(json.iframeId, json.targetId);
self.set(pid, json);
if (elements !== false) {
elements.forEach(function (element) {
element.classList.add(json.class);
});
self.finished(pid, self.queue.DEFINE.FIN_OK);
} else {
self.finished(pid, self.queue.DEFINE.FIN_WARNING, 'Could not add class [' + json.class + '] to [' + json.targetId + ']');
}
}
/**
* Set style of a dom element
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.iframeId - iframe target
* @param {string} json.targetId - Dom target
* @param {array} json.style - style array of elements in format [{"name":"background","value":"red"}]
*
* @example
* elements.setStyle({"targetId":".leftPanel","style":[{"name":"background","value":"red"}]});
*/
setStyle(pid, json) {
let self = this;
let elements = self.queue.getIframeElements(json.iframeId, json.targetId);
self.set(pid, json);
if (elements !== false) {
elements.forEach(function (element) {
for (let i in json.style)
element.style[json.style[i].name] = json.style[i].value;
});
self.finished(pid, self.queue.DEFINE.FIN_OK);
} else {
self.finished(pid, self.queue.DEFINE.FIN_WARNING, 'Could not set style on [' + json.targetId + ']');
}
}
/**
* Set attribute of a dom element
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.iframeId - iframe target
* @param {string} json.targetId - Dom target
* @param {array} json.attribute - Attribute to set
* @param {array} json.value - Value to set
*
* @example
* elements.setAttribute({"targetId":".leftPanel","attribute":"src","value":"http://foo/bar.png"});
*/
setAttribute(pid, json) {
let self = this;
let elements = self.queue.getIframeElements(json.iframeId, json.targetId);
self.set(pid, json);
if (elements !== false) {
elements.forEach(function (element) {
element.setAttribute(json.attribute, json.value);
});
self.finished(pid, self.queue.DEFINE.FIN_OK);
} else {
self.finished(pid, self.queue.DEFINE.FIN_WARNING, 'Could not set attribute [' + json.attribute + '] on [' + json.targetId + ']');
}
}
/**
* Remove a class to a dom element
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.iframeId - iframe target
* @param {string} json.targetId - Dom target
* @param {string} json.class - Name of class to remove
*
* @example
* elements.removeClass({"targetId":".leftPanel","class":"hidden"});
*/
removeClass(pid, json) {
let self = this;
let elements = self.queue.getIframeElements(json.iframeId, json.targetId);
self.set(pid, json);
if (elements !== false) {
elements.forEach(function (element) {
element.classList.remove(json.class);
});
self.finished(pid, self.queue.DEFINE.FIN_OK);
} else {
self.finished(pid, self.queue.DEFINE.FIN_WARNING, 'Could not remove class [' + json.class + '] to [' + json.targetId + ']');
}
}
/**
* toggle a class on a dom element
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target
* @param {string} json.class - Name of class to toggle
*
* @example
* elements.toggleClass({"targetId":".leftPanel","class":"hidden"});
*/
toggleClass(pid, json) {
let self = this;
let elements = self.queue.getIframeElements(json.iframeId, json.targetId);
self.set(pid, json);
if (elements !== false) {
elements.forEach(function (element) {
if (element.classList.contains(json.class))
element.classList.remove(json.class);
else
element.classList.add(json.class);
});
self.finished(pid, self.queue.DEFINE.FIN_OK);
} else {
self.finished(pid, self.queue.DEFINE.FIN_WARNING, 'Could not remove class [' + json.class + '] to [' + json.targetId + ']');
}
}
/**
* Cut a dom element out and paste it somewhere
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target
* @param {string} json.sourceId - Source dom element
*
* @example
* elements.domCutPaste({"targetId":".leftPanel","sourceId":".thing"});
*/
domCutPaste(pid, json) {
let source = self.queue.getElement(json.sourceId);
let target = self.queue.getElement(json.targetId);
target.appendChild(source);
this.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Delete element from dom
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target to removce
*
* @example
* elements.domRemoveElement({"targetId":".leftPanel"});
*/
domRemoveElement(pid, json) {
let target = self.queue.getElement(json.targetId);
target.remove();
this.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Set the HTML of an element
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target
* @param {string} json.html - HTML to add
* @param {string} json.append - Append mode
*
* @example
* elements.innerHTML({"targetId":".leftPanel","html":"Hello World"});
*/
innerHTML(pid, json) {
let self = this;
let element = self.queue.getElement(json.targetId);
if(element) {
if (json.append)
element.insertAdjacentHTML('beforeend', json.html);
else
element.innerHTML = json.html;
}
self.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Set the value of an input field
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target
* @param {string} json.value - value to set
*
* @example
* elements.setInputValue({"targetId":"#username","value":"Hello World"});
*/
setInputValue(pid, json) {
let self = this;
let element = self.queue.getElement(json.targetId);
if(json.pre)
json.value=json.pre+json.value;
if(json.post)
json.value=json.value+json.post;
if(json.append===true)
element.value += json.value;
else
element.value = json.value;
self.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Get the values from checked input boxes
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target for check boxes
* @param {string} json.mode - array|string
* @param {string} json.separator - What seperator to use in string mode
* @param {string} json.name - Name of the memory element to set
*
*
* @example
* elements.getCheckBoxValues({"mode":"string","targetId":".functionGetTypes"});
*/
getCheckBoxValues(pid, json) {
let self = this;
let options = Object.assign({
"mode": "array",
"separator": ",",
"name": "checkboxes"
}, json);
let results = [];
let elements = self.queue.getElements(json.targetId + ':checked');
for (let element in elements) {
results.push(elements[element].value);
}
if (options.mode !== 'array') {
results = results.join(options.separator);
}
self.queue.setMemory(options.name, results, "Session");
self.finished(pid, self.queue.DEFINE.FIN_OK);
}
getMultiselectValues(pid,json) {
let self = this;
let options = Object.assign({
"mode": "array",
"name": "selectboxes"
}, json);
const results = Array.prototype.slice.call(document.querySelectorAll(`${options.targetId} option:checked`),0).map(function(v,i,a) {
return v.value;
});
self.queue.setMemory(options.name, results, "Session");
self.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Get the computed style for an element
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target
* @param {string} json.styles - value to get
* @param {string} json.name - memory name to use
*
* @example
* elements.getComputedStyle({"targetId":"#username","styles":"background"});
*/
getComputedStyle(pid, json) {
let self = this;
let options = Object.assign({
"name": "computedStyle"
}, json);
let element = self.queue.getElement(options.targetId);
let style = window.getComputedStyle(element).getPropertyValue(options.css);
self.queue.setMemory(options.name, style, "Session");
self.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Scroll to a dom target
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target
*
* @example
* elements.scrollIntoView({"targetId":"#ps_1"});
*/
scrollIntoView(pid, json) {
let self = this;
let element = self.queue.getElement(json.targetId);
element.scrollIntoView();
self.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Scroll to bottom of a dom target
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target
*
* @example
* elements.scrollToBottom({"targetId":"#ps_1"});
*/
scrollToBottom(pid, json) {
let objDiv = this.queue.getElement(json.targetId);
objDiv.scrollTop = objDiv.scrollHeight;
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* Accessible toggle visible on a target
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target to scroll to*
* @param {string} json.mode - toggle|add|remove
* @example
* elements.focus({"targetId":"#ps_1"});
*/
ariaHiddenToggle(pid, json) {
let self = this;
let options = Object.assign({
"class": "hidden",
"mode": "toggle"
}, json);
let elements = self.queue.getIframeElements(options.iframeId, options.targetId);
if (elements !== false) {
elements.forEach(function (element) {
if (options.mode === "toggle") {
if (element.classList.contains(options.class)) {
element.classList.remove(options.class);
element.setAttribute('aria-hidden', 'false');
} else {
element.classList.add(options.class);
element.setAttribute('aria-hidden', 'true');
}
} else {
if (options.mode === "add") {
element.setAttribute('aria-hidden', 'true');
element.classList.add(options.class);
}
if (options.mode === "remove") {
element.setAttribute('aria-hidden', 'false');
element.classList.remove(options.class);
}
}
});
self.finished(pid, self.queue.DEFINE.FIN_OK);
} else {
self.finished(pid, self.queue.DEFINE.FIN_WARNING, 'Could not remove class [' + options.class + '] to [' + options.targetId + ']');
}
}
/**
* Focus on a target
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target to scroll to*
* @example
* elements.focus({"targetId":"#ps_1"});
*/
focus(pid, json) {
let objDiv = this.queue.getElement(json.targetId);
objDiv.focus();
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* Scroll a dom container target to a dom target
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target to scroll to
* @param {string} json.containerId - Dom target container to scroll
*
* @example
* elements.scrollIntoView({"containerId":".map-elements-list","targetId":"#ps_1"});
*/
scrollContainerToElement(pid, json) {
let self = this;
let container = self.queue.getElement(json.containerId);
let element = self.queue.getElement(json.targetId);
container.scrollTop = element.offsetTop;
self.finished(pid, self.queue.DEFINE.FIN_OK);
}
/**
* Scroll a dom container to the top
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - Dom target to scroll to
*
* @example
* elements.scrollTop({"targetId":".map-elements-list"});
*/
scrollTop(pid, json) {
let container = self.queue.getElement(json.targetId);
container.scrollTop = 0;
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* Monitor element(s) in a form and add classes on change
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - elements(s) to monitor for change and add modifiedClass to
* @param {string} json.buttonId - Element to add modifiedClass to
* @param {string} json.modifiedClass - Class to add to modified elements
* @param {string} json.modifiedQueue - Prepared queue to run when element modified
*
* @example
* elements.formActivityMonitor({"targetId":".functionMonitor","buttonId":".form-save","modifiedClass":"modified"});
*/
formActivityMonitor(pid, json) {
let self = this;
let elements = this.queue.getElements(json.targetId);
let button;
if (json.buttonId)
button = this.queue.getElement(json.buttonId);
elements.forEach(function (element) {
element.addEventListener("change", function () {
if (json.modifiedQueue)
self.queue.execute(json.modifiedQueue, {});
if (json.modifiedClass) {
this.classList.add(json.modifiedClass);
if (button)
button.classList.add(json.modifiedClass);
}
});
element.addEventListener("keypress", function () {
if (json.modifiedQueue)
self.queue.execute(json.modifiedQueue, {});
if (json.modifiedClass) {
this.classList.add(json.modifiedClass);
if (button)
button.classList.add(json.modifiedClass);
}
});
});
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* Monitor element(s) in a form and validate
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.targetId - elements(s) to monitor for change and add modifiedClass to
* @param {string} json.buttonId - Element to add modifiedClass to
* @param {string} json.focusClass - Class to add to focuses elements
* @param {string} json.validClass - Prepared queue to run when element modified
* @param {string} json.errorClass - Prepared queue to run when element modified
* @param {string} json.timeout - Length of time after user has finished typing to update
*
* @example
* elements.formValidityMonitor({"targetId":".functionMonitor","buttonId":".submit-form","validClass":"valid","focusClass":"focus","errorClass":"error"},{"queueRun":"Instant"});
*/
formValidityMonitor(pid, json) {
let self = this;
let elements = this.queue.getElements(json.targetId);
let button;
if (json.buttonId)
button = this.queue.getElement(json.buttonId);
let modules = {};
let timerEvent;
let timerTimeout = json.timeout || 2000;
modules['email'] = new ValidateEmail();
modules['text'] = new ValidateText();
modules['password'] = new ValidatePassword();
elements.forEach(function (element) {
/*
* Focus is new, clear down focused classes and reclass
*/
element.addEventListener("focus", function () {
elements.forEach(function (element) {
element.classList.remove(json.focusClass);
});
this.classList.add(json.focusClass);
});
/*
* There is a change to the field (normally they exit the field
*/
element.addEventListener("change", function () {
if (timerEvent)
clearTimeout(timerEvent);
changeUpdate(element, this);
});
/*
* Key up so after the user has finishing typing
*/
element.addEventListener("keyup", function (e) {
if (e.which !== 9) {
if (timerEvent)
clearTimeout(timerEvent);
let ptr = this;
timerEvent = setTimeout(function () {
changeUpdate(element, ptr);
}, timerTimeout);
}
});
});
/*
* Function to actually update the fields
*/
function changeUpdate(element, ptr) {
if (element.getAttribute('data-validation')) {
let moduleName = element.getAttribute('data-validation').toLowerCase();
if (modules[moduleName].valid(element.value, {})) {
ptr.classList.remove(json.errorClass);
ptr.classList.add(json.validClass);
} else {
ptr.classList.add(json.errorClass);
ptr.classList.remove(json.validClass);
}
let needValidations = self.queue.getElements(json.targetId + '[data-validation]');
let isValidated = self.queue.getElements(json.targetId + '[data-validation].' + json.validClass);
if (needValidations.length === isValidated.length) {
button.classList.add(json.validClass);
} else {
button.classList.remove(json.validClass);
}
}
}
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* dragReset - Reset the drag item
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.drag - the drag item to reset
*
* @example
* -elements.dragReset({"drag":"mydraf"});
*/
dragReset(pid, json) {
let self = this;
let options = Object.assign({
"drag": "default",
"original":false
}, json);
let element = this.drags[options.drag].element;
if(options.original) {
element.style.removeProperty('top');
element.style.removeProperty('left');
self.drags[options.drag].pos= {x: element.offsetLeft, y: element.offsetTop,ox:0,oy:0};
} else {
if (this.drags[options.drag].mode) {
this.drags[options.drag].stored = {
x: element.offsetLeft,
y: element.offsetTop
}
element.style.removeProperty('top');
element.style.removeProperty('left');
element.style.removeProperty('position');
} else {
element.style.top = self.drags[options.drag].stored.y + "px";
element.style.left = self.drags[options.drag].stored.x + "px";
}
this.drags[options.drag].mode = !this.drags[options.drag].mode;
}
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* dragMoveIntoBounds - Force a drag back into bounds
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.drag - the drag item to reset
*
* @example
* -elements.dragBoundsUpdate({"drag":"mydraf"});
*/
dragMoveIntoBounds(pid,json) {
let self = this;
let options = Object.assign({
"drag": "default",
"original":false
}, json);
/*
* Check our X
*/
let element = this.drags[options.drag].element;
self.drags[options.drag].dimensions=element.getBoundingClientRect();
let bbox=this.drags[options.drag].boundsElement.getBoundingClientRect();
this.drags[options.drag].boundary={
x:0,
y:0,
x1:bbox.width,
y1:bbox.height
};
if((self.drags[options.drag].pos.x+self.drags[options.drag].buffer+self.drags[options.drag].dimensions.width)>self.drags[options.drag].boundary.x1)
{
self.drags[options.drag].pos.x=self.drags[options.drag].boundary.x1-(self.drags[options.drag].buffer+self.drags[options.drag].dimensions.width);
element.style.left = self.drags[options.drag].pos.x + "px";
}
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* dragBoundsUpdate - Reset the boundary area manually
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.drag - the drag item to reset
*
* @example
* -elements.dragBoundsUpdate({"drag":"mydraf"});
*/
dragBoundsUpdate(pid, json) {
let self = this;
let options = Object.assign({
"drag": "default"
}, json);
let bbox=this.drags[options.drag].boundsElement.getBoundingClientRect();
this.drags[options.drag].boundary={
x:0,
y:0,
x1:bbox.width,
y1:bbox.height
};
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
/**
* dragOn - Make an element dragable
* @param {number} pid - Process ID
* @param {object} json - queue arguments
* @param {string} json.drag - the drag item to use
* @param {string} json.targetId - element to be dragable
* @param {string} json.dragTargetId - element to be the area you can actually drag
* @param {string} json.bounds - element to be the area you cant drag out of
* @param {int} json.buffer - the amount of buffer in pixels to apply to the boundary
*
* @example
* -elements.dragOn({"targetId":"#functionDragAnalyticsTop","dragTargetId":"#functionDragAnalyticsTop .dragbar","drag":"analytics","bounds":".edit-scenario-map"});
*/
dragOn(pid, json) {
let self = this;
let options = Object.assign({
"drag": "default",
"buffer": 10
}, json);
if (this.drags === undefined) {
this.drags = {};
}
// The thing me move
let element = this.queue.getElement(json.targetId);
//make it position abs
element.style.position='absolute';
// The thing we target
let dragElement = this.queue.getElement(json.dragTargetId);
// Our bounds
let boundsElement = this.queue.getElement(json.bounds);
let bbox=boundsElement.getBoundingClientRect();
//console.log(element.offsetLeft, element.offsetTop);
this.drags[options.drag] = {
pos: {x: element.offsetLeft, y: element.offsetTop,ox:0,oy:0},
element: element,
dragElement: dragElement,
boundsElement: boundsElement,
mode: true,
boundary: {
x:0,
y:0,
x1:bbox.width,
y1:bbox.height
},
buffer:options.buffer
};
this.drags[options.drag].dimensions=element.getBoundingClientRect();
dragElement.addEventListener('mousedown', dragMouseDown);
window.addEventListener('resize', resize);
function resize(e) {
let bbox=boundsElement.getBoundingClientRect();
self.drags[options.drag].boundary.x1=bbox.width;
self.drags[options.drag].boundary.y1=bbox.height;
}
function dragMouseDown(e) {
if (self.drags[options.drag].mode) {
e = e || window.event;
e.preventDefault();
self.drags[options.drag].dimensions=element.getBoundingClientRect();
self.drags[options.drag].pos.ox = e.clientX - self.drags[options.drag].pos.x ;
self.drags[options.drag].pos.oy = e.clientY - self.drags[options.drag].pos.y;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
//console.log(`mouse: ${e.clientX}:${e.clientY}`);
let bboxX= e.clientX - self.drags[options.drag].pos.ox;
let bboxY= e.clientY - self.drags[options.drag].pos.oy;
// calculate the new cursor position:
if(
bboxX-options.buffer>=self.drags[options.drag].boundary.x
&&(bboxX+options.buffer+self.drags[options.drag].dimensions.width)<=self.drags[options.drag].boundary.x1
&&bboxY-options.buffer>=self.drags[options.drag].boundary.y
&&(bboxY+options.buffer+self.drags[options.drag].dimensions.height)<=self.drags[options.drag].boundary.y1)
{
self.drags[options.drag].pos.x = bboxX;
self.drags[options.drag].pos.y = bboxY;
element.style.top = self.drags[options.drag].pos.y + "px";
element.style.left = self.drags[options.drag].pos.x + "px";
}
}
function closeDragElement() {
/*
* End of drag so get rid of events
*/
document.onmouseup = null;
document.onmousemove = null;
}
this.finished(pid, this.queue.DEFINE.FIN_OK);
}
}