catjs
Version:
(Mobile) Web Automation Framework
740 lines (576 loc) • 24.9 kB
JavaScript
var animation = false;
_cat.plugins.dom = function () {
var _module,
_eventdata = { dataTransfer: null };
function _findPosition(obj) {
function _native(obj) {
var left, top;
left = top = 0;
if (obj.offsetParent) {
do {
left += obj.offsetLeft;
top += obj.offsetTop;
} while (obj = obj.offsetParent);
} else {
left += (obj.offsetLeft || 0);
top += (obj.offsetTop || 0);
}
return {
left: left,
top: top,
right: 0,
bottom: 0
};
}
if (obj) {
if (typeof jQuery !== "undefined" && obj instanceof jQuery) {
obj = obj[0];
}
if (obj) {
//if (obj.getBoundingClientRect) {
// return obj.getBoundingClientRect();
//} else {
return _native(obj);
//}
}
}
return undefined;
}
/**
* Fire one or more DOM events according to a given element or coordinates {x, y}
*
* @param event {String} DOM event type name
* @param opt {Object} event options
* @returns {*}
* @private
*/
function _fireEvent(event, opt, callback) {
var eventObj,
position = false,
pos,
x = 0,
y = 0,
targetx,
targety,
steps,
stepx, stepy,
counter, index, delay,
offsetx = opt.offset.x,
offsety = opt.offset.y,
elt;
function _getSteps() {
var steps = opt.steps;
if (!("delay" in steps)) {
steps.delay = 0;
}
if (!("count" in steps)) {
steps.count = 1;
}
return steps;
}
function _createEvent(type, opt) {
var event,
x = opt.x, y = opt.y;
if (type in {"dragstart": 1, "drop": 1, "dragover": 1}) {
event = document.createEvent("CustomEvent");
event.initCustomEvent(type, true, true, null);
if (type === "dragstart" || !_eventdata.dataTransfer) {
_eventdata.dataTransfer = {
data: {
},
setData: function (type, val) {
_eventdata.dataTransfer.data[type] = val;
},
getData: function (type) {
return _eventdata.dataTransfer.data[type];
}
};
}
event.dataTransfer = _eventdata.dataTransfer;
} else {
_cat.core.log.info("[catjs dom fire] Event type:", type, " client cords [x, y]: ", x, y);
event = document.createEvent("MouseEvents");
event.initMouseEvent(type, true, true, window,
0, 0, 0, x, y, false, false, false, 0, null);
}
return event;
}
function _dispatch() {
var eletOffset, eltoffsetx, eltoffsety;
function isDocument(ele) {
var documenttest = /\[object (?:HTML)?Document\]/;
return documenttest.test(Object.prototype.toString.call(ele));
}
if (event) {
index++;
if (document.createEvent) {
if (isNaN(stepx)) {
stepx = 0;
}
if (isNaN(stepy)) {
stepy = 0;
}
eletOffset = _findPosition(opt.element);
if (event === "mousemove" || opt.cords) {
if (index === 1 && (_cat.utils.plugins.jqhelper.isjquery())) {
eletOffset = _findPosition(opt.element);
x -= eltoffsetx = (eletOffset.left || 0);
y -= eltoffsety = (eletOffset.top || 0);
}
x += stepx + (offsetx / counter);
y += stepy + (offsety / counter);
x = Math.round(x);
y = Math.round(y);
} else {
x = 0;
y = 0;
}
eventObj = _createEvent(event, {x: x, y: y});
elt.dispatchEvent(eventObj);
} else {
elt.fireEvent("on" + event);
}
if (index < counter) {
setTimeout(_dispatch, delay);
} else {
callback.call(this);
}
} else {
_cat.core.log.warn("[catjs dom fire event] No valid event was found");
}
}
if (!event) {
return undefined;
}
steps = _getSteps();
// resolve target element data
if (opt.target) {
if (_cat.utils.Utils.getType(opt.target) === "object") {
if ("x" in opt.target && "y" in opt.target) {
targetx = opt.target.x;
targety = opt.target.y;
}
} else {
pos = _findPosition(opt.target);
if (pos) {
targetx = pos.left;
targety = pos.top;
}
}
}
// resolve element data
if (_cat.utils.Utils.getType(opt.element) === "object") {
if ("x" in opt.element && "y" in opt.element) {
x = opt.element.x;
y = opt.element.y;
position = true;
}
} else if (opt.cords || targetx) {
if (typeof opt.cords === "object") {
pos = _findPosition(opt.cords);
} else if (typeof opt.cords === "boolean") {
pos = _findPosition(opt.element);
}
if (pos) {
x = pos.left;
y = pos.top;
position = true;
}
}
if (position) {
if (document.elementFromPoint) {
elt = document.elementFromPoint(x, y);
}
if (!elt) {
elt = opt.element;
}
} else {
elt = opt.element;
}
if (!elt) {
_cat.core.log.warn("[catjs dom fire event] No valid element was found");
return undefined;
}
index = 0;
delay = steps.delay;
counter = steps.count;
if (targetx !== undefined) {
stepx = (targetx - x) / counter;
stepy = (targety - y) / counter;
} else {
// TBD
}
_dispatch();
}
function _addEventListener(event, elem, fn) {
if (!elem) {
return undefined;
}
if (elem.addEventListener) {
elem.addEventListener(event, fn, false);
} else {
elem.attachEvent("on" + event, function () {
return(fn.call(elem, window.event));
});
}
}
function _getargs(parentargs, autodetect) {
var args = [].slice.call(parentargs);
args.push(autodetect);
return args;
}
function _getElt(val) {
var args = _getargs(arguments, "*");
return _cat.utils.plugins.jqhelper.getElt.apply(this, args);
}
_module = {
utils: function () {
var oldElement = "";
return {
$: function () {
return _cat.utils.plugins.jqhelper.$();
},
setBoarder: function (element) {
if (oldElement) {
oldElement.classList.remove("markedElement");
}
if (element) {
element.className = element.className + " markedElement";
}
oldElement = element;
},
findPosition: function (obj) {
return _findPosition(obj);
},
getElt: function (val) {
return _getElt(val);
},
trigger: function () {
var args = _getargs(arguments, "*");
return _cat.utils.plugins.jqhelper.trigger.apply(this, args);
},
setText: function () {
var args = _getargs(arguments, "*");
return _cat.utils.plugins.jqhelper.setText.apply(this, args);
}
};
}(),
actions: {
/**
* A basic compare a given base64 image to a snapshot
* TODO TBD support additional functionality: ignore colors, antialiasing, etc..
*
* @param config
* name {String} The snapshot name
* base64 {String} base64 encoded image string
* selector {String} snapshot query selector
* callback {Function} data rgument passed represent the compare result { analysis: .. , compare: }
*/
snapshotCompare: function(config) {
if (! config ) {
config = {};
}
_catjs.plugin.get("dom").actions.snapshot(config.selector, config.name , function(data){
var result = { analysis: null, compare: null},
deferred = Q.defer();
resemble( data ).onComplete(function(data){
result.analysis = data;
if (!config.base64) {
deferred.resolve(result);
}
});
if (config.base64) {
resemble(data).compareTo(config.base64).onComplete(function(data){
result.compare = data;
deferred.resolve(result);
});
}
deferred.promise.then(function(data) {
if (config.callback) {
config.callback.call(this, data);
}
});
});
},
/**
* Take a snapshot
*
* @param config
* selector {String} snapshot query selector
* overrideScrapName {String} Override the system name
* callback {Function} data argument passed represents the snapshot as base64 string
*/
snapshot: function (idName, overrideScrapName, callback) {
var elt,
me = this;
function _isCanvasSupported() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
function _outerHTML(node){
return node.outerHTML || (
function(n){
var div = document.createElement('div'), h;
div.appendChild( n.cloneNode(true) );
h = div.innerHTML;
div = null;
return h;
})(node);
}
function _getSVGTxt(elt) {
var str;
if (elt.parentNode.innerHTML) {
str = _outerHTML(elt);
}
return str;
}
function _createCanvasElement(elt) {
var canvaselt = document.createElement("canvas"),
bounds = elt.getBoundingClientRect();
canvaselt.width = bounds.width + "px";
canvaselt.height = bounds.height + "px";
return canvaselt;
}
/**
* capture canvas data
*
* @param elt
* @returns {undefined}
* @private
*/
function _captureCanvas(elt, callback) {
var nodeName, tagMethod,
serverURL = _cat.utils.Request.generate({service: "screenshot"}),
methods = {
"canvas": function(elt) {
_save(_getData(elt));
},
"svg": function(elt) {
var canelt = _createCanvasElement(elt),
svgtxt = _getSVGTxt(elt);
if (typeof canvg !== "undefined") {
canvg(canelt, svgtxt);
_save(_getData(canelt));
} else {
_cat.core.log.warn("[catjs dom plugin] SVG element was found nut no valid 'canvg' handle was found, consider adding it as a dependency in your catproject.json ");
}
},
"*": function(elt) {
if (typeof html2canvas !== "undefined") {
html2canvas(elt).then(function (canvas) {
_save(_getData(canvas));
}).catch(function(err) {
if (err) {
_cat.core.log.error("[catjs html2canvas] failed to render the given dom element, \nerror: " ,err);
}
});
} else {
_cat.core.log.warn("[catjs dom plugin] DOM element was found but no valid 'html2canvas' handle was found, consider adding it as a dependency in your catproject.json ");
}
}
};
function _getData(canvas) {
var data;
if (canvas.toDataURL) {
data = canvas.toDataURL("image/png");
}
return data;
}
function _save(data) {
var base64;
function _prepareImage(data) {
return data.replace(/^data:image\/png;base64,/, "");
}
if (data) {
if (overrideScrapName) {
overrideScrapName = "_$$_" + overrideScrapName;
}
base64 = _prepareImage(data);
_cat.utils.AJAX.sendRequestAsync({
url: serverURL,
method: "POST",
data: {
pic: base64,
scrapName: (overrideScrapName || ( "scrap" in me ? me.scrap.name : "temp" )),
deviceId: _cat.core.guid()
},
header: [
{name: "Content-Type", value: "application/json;charset=UTF-8"}
],
callback: function () {
if (this.responseText) {
_cat.core.log.info("[catjs dom snapshot] request processed successfully response: ", this.responseText);
}
}
});
if (callback) {
callback.call(this, data);
}
}
}
if (elt) {
// DOM element case
if (elt.nodeType && elt.nodeType === 1) {
// canvas element case
nodeName = elt.nodeName;
nodeName = (nodeName ? nodeName.toLowerCase() : undefined);
tagMethod = (nodeName && methods[nodeName] ? methods[nodeName] : methods["*"]);
if (tagMethod) {
tagMethod.call(this, elt);
}
}
}
}
// test if canvas supported
if (!_isCanvasSupported()) {
_cat.core.log.warn("[catjs dom plugin] Your browser doesn't support canvas element ");
return undefined;
}
elt = _module.utils.getElt(idName);
elt = _cat.utils.plugins.jqhelper.dom(elt);
if (elt) {
if (_cat.utils.Utils.getType(elt) === "array") {
} else {
_captureCanvas(elt, callback);
}
}
},
/**
* Listen to a DOM event
*
* @param event {*} a given event name or an array of names
* @param opt {Object} event's listener options
* element {*} The DOM element to be listen to or coordinates {x, y}
* listener {Function} Listener functionality
*/
listen: function (event, opt) {
_cat.utils.Utils.prepareProps(
{
global: {
obj: opt
},
props: [
{
key: "element",
require: true
},
{
key: "listener",
require: true
}
]
});
var elt = _module.utils.getElt(opt.element);
// todo a generic code please..
elt = _cat.utils.plugins.jqhelper.dom(elt);
if (elt) {
_addEventListener(event, elt, opt.listener);
}
},
/**
* Fire a DOM event
*
* @param event {*} a given event name or an array of names
* @param opt {Object} event's fire options
* element {*} The DOM element to be fired or coordinates {x, y}
* cords {Boolean} combined with the given element or target element, get its coordinates or else use the element
* repeat {Number} Number of calls
* delay {Number} delay in milliseconds between calls
*/
fire: function (event, opt, callback) {
var items, index = 0, size;
if (!event || !opt) {
_cat.core.log.warn("[catjs plugin dom fire] no valid event and/or element were found");
return undefined;
}
if (_cat.utils.Utils.getType(opt) === "string") {
opt = {element: opt};
}
_cat.utils.Utils.prepareProps(
{
global: {
obj: opt
},
props: [
{
key: "element",
require: true
},
{
key: "target"
},
{
key: "offset",
default: {x: 0, y: 0}
},
{
key: "cords",
default: false
},
{
key: "steps",
default: {delay: 0, count: 1}
}
]
});
if (_cat.utils.Utils.getType(event) === "array") {
items = event;
} else if (_cat.utils.Utils.getType(event) === "string") {
items = [event];
} else {
items = [];
}
opt.element = _module.utils.getElt(opt.element);
opt.target = (opt.target ? _module.utils.getElt(opt.target) : opt.target);
// todo a generic code please..
if ( _cat.utils.plugins.jqhelper.isdom()) {
opt.element = opt.element[0];
if (opt.target && opt.target[0]) {
opt.target = opt.target[0];
}
}
function firecallback() {
index++;
if (index < size) {
_fireEvent(items[index], opt, firecallback);
}
}
size = items.length;
_fireEvent(items[index], opt, firecallback);
},
select: function(opt, index) {
_cat.utils.Utils.prepareProps({
global: {
obj: opt
},
props: [
{
key: "element",
require: true
}
]
});
var elt = _module.utils.getElt(opt.element);
elt = _cat.utils.plugins.jqhelper.dom(elt);
if (elt) {
_module.actions.fire("mouseenter", {element: elt});
_module.actions.fire("mouseover", {element: elt});
_module.actions.fire("mousemove", {element: elt});
if (elt[index]) {
elt[index].selected = true;
}
_module.actions.fire("mousedown", {element: elt});
_module.actions.fire("focus", {element: elt});
_module.actions.fire("input", {element: elt});
_module.actions.fire("change", {element: elt});
setTimeout(function() {
_module.actions.fire("mouseup", {element: elt});
_module.actions.fire("click", {element: elt});
_module.actions.fire("blur", {element: elt});
}, 0);
}
}
}
};
return _module;
}();