2017-05-23 03:20:15 +02:00
|
|
|
var noop = function () {};
|
|
|
|
|
|
|
|
var exports = {};
|
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
exports.make_zjquery = function () {
|
|
|
|
|
|
|
|
var elems = {};
|
|
|
|
|
|
|
|
function new_elem(selector) {
|
|
|
|
var html = 'never-been-set';
|
|
|
|
var text = 'never-been-set';
|
|
|
|
var value;
|
|
|
|
var shown = false;
|
|
|
|
var focused = false;
|
|
|
|
var children = new Dict();
|
|
|
|
var my_parent;
|
2017-06-16 14:45:02 +02:00
|
|
|
var properties = new Dict();
|
2017-06-16 20:55:07 +02:00
|
|
|
var attrs = new Dict();
|
2017-05-25 01:49:29 +02:00
|
|
|
var classes = new Dict();
|
2017-06-14 20:28:55 +02:00
|
|
|
var on_functions = new Dict();
|
2017-07-06 00:18:15 +02:00
|
|
|
var child_on_functions = new Dict();
|
2017-06-22 23:40:38 +02:00
|
|
|
|
|
|
|
function generic_event(event_name, arg) {
|
|
|
|
if (typeof(arg) === 'function') {
|
|
|
|
on_functions.set(event_name, arg);
|
|
|
|
} else {
|
|
|
|
var handler = on_functions.get(event_name);
|
|
|
|
assert(handler);
|
|
|
|
handler(arg);
|
|
|
|
}
|
|
|
|
}
|
2017-05-25 01:49:29 +02:00
|
|
|
|
|
|
|
var self = {
|
2017-06-27 22:02:51 +02:00
|
|
|
add_child: function (child_selector, child_elem) {
|
|
|
|
children.set(child_selector, child_elem);
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
addClass: function (class_name) {
|
|
|
|
classes.set(class_name, true);
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-06-16 20:55:07 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
attr: function (name, val) {
|
|
|
|
if (val === undefined) {
|
|
|
|
return attrs.get(name);
|
|
|
|
}
|
|
|
|
attrs.set(name, val);
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-06-14 20:28:55 +02:00
|
|
|
},
|
2017-05-25 01:49:29 +02:00
|
|
|
blur: function () {
|
|
|
|
focused = false;
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
click: function (arg) {
|
|
|
|
generic_event('click', arg);
|
2017-06-12 13:24:58 +02:00
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
css: noop,
|
|
|
|
data: noop,
|
2017-05-25 01:49:29 +02:00
|
|
|
debug: function () {
|
|
|
|
return {
|
|
|
|
value: value,
|
|
|
|
shown: shown,
|
|
|
|
selector: selector,
|
|
|
|
};
|
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
empty: noop,
|
|
|
|
expectOne: function () {
|
|
|
|
// silently do nothing
|
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:06:28 +02:00
|
|
|
fadeTo: noop,
|
2017-05-25 01:49:29 +02:00
|
|
|
find: function (child_selector) {
|
|
|
|
var child = children.get(child_selector);
|
|
|
|
if (child) {
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
2017-05-31 17:03:18 +02:00
|
|
|
throw Error("Cannot find " + child_selector + " in " + selector);
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
focus: function () {
|
|
|
|
focused = true;
|
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
get: function (idx) {
|
|
|
|
// We have some legacy code that does $('foo').get(0).
|
|
|
|
assert.equal(idx, 0);
|
|
|
|
return selector;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-07-06 01:38:28 +02:00
|
|
|
get_on_handler: function (name, child_selector) {
|
|
|
|
var funcs = self.get_on_handlers(name, child_selector);
|
|
|
|
assert.equal(funcs.length, 1, 'We expected to have exactly one handler here.');
|
|
|
|
return funcs[0];
|
|
|
|
},
|
2017-07-05 23:11:59 +02:00
|
|
|
get_on_handlers: function (name, child_selector) {
|
|
|
|
if (child_selector === undefined) {
|
|
|
|
return on_functions.get(name) || [];
|
|
|
|
}
|
|
|
|
|
|
|
|
var child_on = child_on_functions.get(child_selector) || {};
|
|
|
|
if (!child_on) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
return child_on.get(name) || [];
|
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
hasClass: function (class_name) {
|
|
|
|
return classes.has(class_name);
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
height: noop,
|
|
|
|
hide: function () {
|
|
|
|
shown = false;
|
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
html: function (arg) {
|
|
|
|
if (arg !== undefined) {
|
|
|
|
html = arg;
|
|
|
|
return self.wrapper;
|
|
|
|
}
|
|
|
|
return html;
|
|
|
|
},
|
|
|
|
is_focused: function () {
|
|
|
|
// is_focused is not a jQuery thing; this is
|
|
|
|
// for our testing
|
|
|
|
return focused;
|
|
|
|
},
|
|
|
|
keydown: function (arg) {
|
|
|
|
generic_event('keydown', arg);
|
|
|
|
return self.wrapper;
|
|
|
|
},
|
|
|
|
keyup: function (arg) {
|
|
|
|
generic_event('keyup', arg);
|
2017-06-12 13:43:04 +02:00
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-07-06 00:18:15 +02:00
|
|
|
on: function () {
|
|
|
|
// parameters will either be
|
|
|
|
// (event_name, handler) or
|
|
|
|
// (event_name, sel, handler)
|
|
|
|
var event_name;
|
|
|
|
var sel;
|
|
|
|
var handler;
|
|
|
|
|
|
|
|
// For each event_name (or event_name/sel combo), we will store an
|
|
|
|
// array of functions that are mapped to the event (or event/selector).
|
|
|
|
//
|
|
|
|
// Usually funcs is an array of just one element, but not always.
|
|
|
|
var funcs;
|
|
|
|
|
|
|
|
if (arguments.length === 2) {
|
|
|
|
event_name = arguments[0];
|
|
|
|
handler = arguments[1];
|
|
|
|
funcs = on_functions.setdefault(event_name, []);
|
|
|
|
funcs.push(handler);
|
|
|
|
} else if (arguments.length === 3) {
|
|
|
|
event_name = arguments[0];
|
|
|
|
sel = arguments[1];
|
|
|
|
handler = arguments[2];
|
|
|
|
assert.equal(typeof(sel), 'string', 'String selectors expected here.');
|
|
|
|
assert.equal(typeof(handler), 'function', 'An handler function expected here.');
|
|
|
|
var child_on = child_on_functions.setdefault(sel, new Dict());
|
|
|
|
funcs = child_on.setdefault(event_name, []);
|
|
|
|
funcs.push(handler);
|
|
|
|
}
|
2017-06-12 13:24:58 +02:00
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
parent: function () {
|
|
|
|
return my_parent;
|
2017-06-20 00:31:00 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
prop: function (name, val) {
|
|
|
|
if (val === undefined) {
|
|
|
|
return properties.get(name);
|
|
|
|
}
|
|
|
|
properties.set(name, val);
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-06-22 23:40:39 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
removeAttr: function (name) {
|
|
|
|
attrs.del(name);
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-06-22 23:40:39 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
removeClass: function (class_name) {
|
|
|
|
classes.del(class_name);
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-06-22 23:40:40 +02:00
|
|
|
},
|
2017-05-25 01:49:29 +02:00
|
|
|
remove: function () {
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-05-25 01:49:29 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
removeData: noop,
|
|
|
|
select: function (arg) {
|
|
|
|
generic_event('select', arg);
|
|
|
|
return self.wrapper;
|
2017-06-14 21:08:32 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
show: function () {
|
|
|
|
shown = true;
|
|
|
|
return self.wrapper;
|
|
|
|
},
|
|
|
|
set_parent: function (parent_elem) {
|
|
|
|
my_parent = parent_elem;
|
|
|
|
},
|
2017-06-27 22:08:11 +02:00
|
|
|
stop: function () {
|
|
|
|
return self.wrapper;
|
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
text: function (arg) {
|
|
|
|
if (arg !== undefined) {
|
|
|
|
text = arg;
|
|
|
|
return self.wrapper;
|
2017-06-16 20:55:07 +02:00
|
|
|
}
|
2017-06-27 22:02:51 +02:00
|
|
|
return text;
|
|
|
|
},
|
|
|
|
trigger: function (ev) {
|
|
|
|
var funcs = on_functions.get(ev.name) || [];
|
2017-07-06 15:47:25 +02:00
|
|
|
|
|
|
|
// The following assertion is temporary. It can be
|
|
|
|
// legitimate for code to trigger multiple handlers.
|
|
|
|
// But up until now, we haven't needed this, and if
|
|
|
|
// you come across this assertion, it's possible that
|
|
|
|
// you can simplify your tests by just doing your own
|
|
|
|
// mocking of trigger(). If you really know what you
|
|
|
|
// are doing, you can remove this limitation.
|
|
|
|
assert(funcs.length <= 1, 'multiple functions set up');
|
|
|
|
|
2017-06-27 22:02:51 +02:00
|
|
|
_.each(funcs, function (f) {
|
|
|
|
f(ev.data);
|
|
|
|
});
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-06-16 20:55:07 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
val: function () {
|
|
|
|
if (arguments.length === 0) {
|
|
|
|
return value || '';
|
2017-06-16 14:45:02 +02:00
|
|
|
}
|
2017-06-27 22:02:51 +02:00
|
|
|
value = arguments[0];
|
2017-06-22 23:40:41 +02:00
|
|
|
return self.wrapper;
|
2017-06-16 14:45:02 +02:00
|
|
|
},
|
2017-06-27 22:02:51 +02:00
|
|
|
visible: function () {
|
|
|
|
return shown;
|
|
|
|
},
|
2017-05-25 01:49:29 +02:00
|
|
|
};
|
2017-06-14 14:17:03 +02:00
|
|
|
|
|
|
|
if (selector[0] === '<') {
|
|
|
|
self.html(selector);
|
|
|
|
}
|
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
function jquery_array(elem) {
|
|
|
|
var result = [elem];
|
|
|
|
|
|
|
|
for (var attr in elem) {
|
|
|
|
if (Object.prototype.hasOwnProperty.call(elem, attr)) {
|
|
|
|
result[attr] = elem[attr];
|
2017-05-24 19:46:25 +02:00
|
|
|
}
|
2017-05-25 01:49:29 +02:00
|
|
|
}
|
2017-06-12 13:24:58 +02:00
|
|
|
elem.wrapper = result;
|
2017-05-24 19:46:25 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
return result;
|
|
|
|
}
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
var zjquery = function (arg) {
|
|
|
|
if (typeof arg === "function") {
|
|
|
|
// If somebody is passing us a function, we emulate
|
|
|
|
// jQuery's behavior of running this function after
|
|
|
|
// page load time. But there are no pages to load,
|
|
|
|
// so we just call it right away.
|
|
|
|
arg();
|
|
|
|
return;
|
2017-06-22 23:40:40 +02:00
|
|
|
} else if (typeof arg === "object") {
|
|
|
|
// If somebody is passing us an element, we return
|
|
|
|
// the element itself if it's been created with
|
|
|
|
// zjquery.
|
|
|
|
// This may happen in cases like $(this).
|
|
|
|
if (arg.debug) {
|
|
|
|
var this_selector = arg.debug().selector;
|
|
|
|
if (elems[this_selector]) {
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
}
|
2017-05-25 01:49:29 +02:00
|
|
|
}
|
2017-05-24 03:34:18 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
var selector = arg;
|
|
|
|
if (elems[selector] === undefined) {
|
|
|
|
var elem = new_elem(selector);
|
|
|
|
elems[selector] = jquery_array(elem);
|
2017-05-24 03:34:18 +02:00
|
|
|
}
|
2017-05-25 01:49:29 +02:00
|
|
|
return elems[selector];
|
|
|
|
};
|
2017-05-24 03:34:18 +02:00
|
|
|
|
2017-05-24 03:05:29 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
zjquery.stub_selector = function (selector, stub) {
|
|
|
|
elems[selector] = stub;
|
|
|
|
};
|
2017-05-24 22:31:12 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
zjquery.trim = function (s) { return s; };
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
zjquery.state = function () {
|
|
|
|
// useful for debugging
|
|
|
|
var res = _.map(elems, function (v) {
|
|
|
|
return v.debug();
|
|
|
|
});
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
res = _.map(res, function (v) {
|
|
|
|
return [v.selector, v.value, v.shown];
|
|
|
|
});
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
res.sort();
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
return res;
|
|
|
|
};
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-06-14 20:28:55 +02:00
|
|
|
zjquery.Event = function (name, data) {
|
|
|
|
return {
|
|
|
|
name: name,
|
|
|
|
data: data,
|
|
|
|
};
|
|
|
|
};
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-06-22 23:40:39 +02:00
|
|
|
zjquery.extend = function (content, container) {
|
|
|
|
return _.extend(content, container);
|
|
|
|
};
|
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
return zjquery;
|
|
|
|
};
|
2017-05-23 03:20:15 +02:00
|
|
|
|
2017-05-25 01:49:29 +02:00
|
|
|
module.exports = exports;
|