add some more documentation, pass some more tests

This commit is contained in:
rlx 2011-10-01 02:21:55 +00:00
parent c6d67420a8
commit f2dbfbd1e5
9 changed files with 589 additions and 494 deletions

View file

@ -35,7 +35,7 @@ Ox.load('UI', {
}) })
.appendTo(Ox.UI.$body); .appendTo(Ox.UI.$body);
[ [
'anyclick', 'singleclick', 'doubleclick', 'mouserepeat', 'anyclick', 'singleclick', 'doubleclick', 'mousedown', 'mouserepeat',
'dragstart', 'drag', 'dragenter', 'dragleave', 'dragpause', 'dragend' 'dragstart', 'drag', 'dragenter', 'dragleave', 'dragpause', 'dragend'
].forEach(function(event) { ].forEach(function(event) {
$target.bindEvent(event, function(e) { $target.bindEvent(event, function(e) {
@ -44,13 +44,18 @@ Ox.load('UI', {
.html( .html(
Ox.formatDate(date, '%H:%M:%S') + '.' + (Ox.pad(date % 1000, 3)) + Ox.formatDate(date, '%H:%M:%S') + '.' + (Ox.pad(date % 1000, 3)) +
' <span style="font-weight: bold">' + event + '</span> ' + ' <span style="font-weight: bold">' + event + '</span> ' +
JSON.stringify(Ox.extend(e.clientX ? { JSON.stringify(
clientX: e.clientX, Ox.extend(e.clientX ? {
clientY: e.clientY, clientX: e.clientX,
} : {}, e.clientDX ? { clientY: e.clientY,
clientDX: e.clientDX, } : {}, e.clientDX ? {
clientDY: e.clientDY clientDX: e.clientDX,
} : {})) clientDY: e.clientDY
} : {})
)
.replace(/"/g, '')
.replace(/:/g, ': ')
.replace(/,/g, ', ')
) )
.prependTo($log.$element); .prependTo($log.$element);
event == 'anyclick' && Ox.print(e); event == 'anyclick' && Ox.print(e);

View file

@ -46,9 +46,9 @@ Ox.load.Geo = function(options, callback) {
}).length, }).length,
// Current independent countries without dependencies or disputes // Current independent countries without dependencies or disputes
Ox.COUNTRIES.filter(function(c) { Ox.COUNTRIES.filter(function(c) {
return !c.dependencies.length && !c.dependency.length && return !c.dependencies.length && !c.dependency.length
!c.disputes.length && !c.disputed.length && && !c.disputes.length && !c.disputed.length
!c.dissolved.length && !c.other; && !c.dissolved.length && !c.other;
}).length, }).length,
// Current dependent countries // Current dependent countries
Ox.COUNTRIES.filter(function(c) { Ox.COUNTRIES.filter(function(c) {
@ -68,9 +68,9 @@ Ox.load.Geo = function(options, callback) {
}).length, }).length,
// Former independent countries without dependencies or disputes // Former independent countries without dependencies or disputes
Ox.COUNTRIES.filter(function(c) { Ox.COUNTRIES.filter(function(c) {
return !c.dependencies.length && !c.dependency.length && return !c.dependencies.length && !c.dependency.length
!c.disputes.length && !c.disputed.length && && !c.disputes.length && !c.disputed.length
c.dissolved.length && !c.other; && c.dissolved.length && !c.other;
}).length, }).length,
// Former dependect countries // Former dependect countries
Ox.COUNTRIES.filter(function(c) { Ox.COUNTRIES.filter(function(c) {

View file

@ -3,23 +3,30 @@
/*@ /*@
Ox.Element <function:Ox.JQueryElement> Basic UI element object Ox.Element <function:Ox.JQueryElement> Basic UI element object
# Usage -------------------------------------------------------------------- # Usage --------------------------------------------------------------------
([options[, self]]) -> <object> UI element (element) -> <object> UI element
(options) -> <object> UI element
(options, self) -> <object> UI element
# Arguments ---------------------------------------------------------------- # Arguments ----------------------------------------------------------------
options <object> the options of the element element <string> Tagname or CSS selector
options <object> Options of the element
# Properties # Properties
element <string> tagname or CSS selector element <string> Tagname or CSS selector
tooltip <string|function> tooltip title or function that returns one tooltip <string|function> Tooltip title, or a function that returns one
(e) -> <string> tooltip title (e) -> <string> tooltip title
e <object> mouse event e <object> mouse event
options <string> tagname or CSS selector self <object> Shared private variable
self <object> shared private variable
# Events ------------------------------------------------------------------- # Events -------------------------------------------------------------------
anyclick <event> anyclick anyclick <event> anyclick
Fires on mouseup, but not on any subsequent mouseup within 250 ms Fires on mouseup, but not on any subsequent mouseup within 250 ms (this
is useful if one wants to listen for singleclicks, but not doubleclicks,
since it will fire immediately, and won't fire again in case of a
doubleclick)
* <*> original event properties * <*> original event properties
doubleclick <event> doubleclick doubleclick <event> doubleclick
Fires on the second mousedown within 250 ms Fires on the second mousedown within 250 ms (this is useful if one wants
* <*> original event properties to listen for both singleclicks and doubleclicks, since it will not
trigger a singleclick event)
* <*> original event properties
drag <event> drag drag <event> drag
Fires on mousemove after dragstart, stops firing on mouseup Fires on mousemove after dragstart, stops firing on mouseup
clientDX <number> horizontal drag delta in px clientDX <number> horizontal drag delta in px
@ -31,361 +38,391 @@ Ox.Element <function:Ox.JQueryElement> Basic UI element object
clientDY <number> vertical drag delta in px clientDY <number> vertical drag delta in px
* <*> original event properties * <*> original event properties
dragenter <event> dragenter dragenter <event> dragenter
Fires when entering an element during drag Fires when entering an element during drag (this fires on the element
dragleave <event> dragleave being dragged -- the target element is the event's target property)
Fires when leaving an element during drag
dragpause <event> dragpause
Fires once when the mouse doesn't move for 250 ms during drag
clientDX <number> horizontal drag delta in px clientDX <number> horizontal drag delta in px
clientDY <number> vertical drag delta in px clientDY <number> vertical drag delta in px
* <*> original event properties * <*> original event properties
dragleave <event> dragleave
Fires when leaving an element during drag (this fires on the element
being dragged -- the target element is the event's target property)
clientDX <number> horizontal drag delta in px
clientDY <number> vertical drag delta in px
* <*> original event properties
dragpause <event> dragpause
Fires once when the mouse doesn't move for 250 ms during drag (this is
useful in order to execute operations that are too expensive to be
attached to the drag event)
clientDX <number> horizontal drag delta in px
clientDY <number> vertical drag delta in px
* <*> original event properties
mousedown <event> mousedown
Fires on mousedown (this is useful if one wants to listen for
singleclicks, but not doubleclicks or drag events, and wants the event
to fire as early as possible)
* <*> original event properties
dragstart <event> dragstart dragstart <event> dragstart
Fires when the mouse is down for 250 ms Fires when the mouse is down for 250 ms
* <*> original event properties * <*> original event properties
mouserepeat <event> mouserepeat mouserepeat <event> mouserepeat
Fires every 50 ms after the mouse was down for 250 ms, stops firing on Fires every 50 ms after the mouse was down for 250 ms, stops firing on
mouseleave or mouseup mouseleave or mouseup (this fires like a key that is being pressed and
* <*> original event properties held, and is useful for buttons like scrollbars arrows that need to
react to both clicking and holding)
singleclick <event> singleclick singleclick <event> singleclick
Fires 250 ms after mouseup, if there was no subsequent mousedown Fires 250 ms after mouseup, if there was no subsequent mousedown (this
is useful if one wants to listen for both singleclicks and doubleclicks,
since it will not fire for doubleclicks)
* <*> original event properties * <*> original event properties
@*/ @*/
Ox.Element = function(options, self) { Ox.Element = function(options, self) {
// create private object // create private object
self = self || {}; self = self || {};
// create defaults and options objects // create defaults and options objects
self.defaults = {}; self.defaults = {};
self.options = options || {}; self.options = options || {};
// allow for Ox.TestElement('<tagname>') // allow for Ox.TestElement('<tagname>')
// or Ox.TestElement('cssSelector') // or Ox.TestElement('cssSelector')
if (Ox.isString(self.options)) { if (Ox.isString(self.options)) {
self.options = { self.options = {
element: self.options element: self.options
}; };
} }
// create event handler // create event handler
// (this can be passed as part of self) // (this can be passed as part of self)
if (!self.$eventHandler) { if (!self.$eventHandler) {
self.$eventHandler = $('<div>'); self.$eventHandler = $('<div>');
} }
// create public object // create public object
var that = new Ox.JQueryElement( var that = new Ox.JQueryElement(
$(self.options.element || '<div>') $(self.options.element || '<div>')
) )
.mousedown(mousedown); .mousedown(mousedown);
if (self.options.tooltip) { if (self.options.tooltip) {
if (Ox.isString(self.options.tooltip)) { if (Ox.isString(self.options.tooltip)) {
that.$tooltip = Ox.Tooltip({ that.$tooltip = Ox.Tooltip({
title: self.options.tooltip, title: self.options.tooltip,
}); });
that.bind({
mouseenter: mouseenter
});
} else {
that.$tooltip = Ox.Tooltip({
animate: false
});
that.bind({
mousemove: mousemove
});
}
that.bind({ that.bind({
mouseleave: mouseleave mouseenter: mouseenter
});
} else {
that.$tooltip = Ox.Tooltip({
animate: false
});
that.bind({
mousemove: mousemove
}); });
} }
that.bind({
mouseleave: mouseleave
});
}
function bind(action, event, callback) { function bind(action, event, callback) {
self.$eventHandler[action]('ox_' + event, function(event, data) { self.$eventHandler[action]('ox_' + event, function(event, data) {
callback(Ox.extend({ callback(Ox.extend({
_element: that.$element, _element: that.$element,
_event: event _event: event
}, data)); }, data));
}); });
} }
function mousedown(e) { function mousedown(e) {
/* /*
better mouse events better mouse events
mousedown: mousedown:
trigger mousedown trigger mousedown
within 250 msec: within 250 msec:
mouseup: trigger anyclick ("click" would collide with click events of certain widgets) mouseup: trigger anyclick
mouseup + mousedown: trigger doubleclick mouseup + mousedown: trigger doubleclick
after 250 msec: after 250 msec:
mouseup + no mousedown within 250 msec: trigger singleclick mouseup + no mousedown within 250 msec: trigger singleclick
no mouseup within 250 msec: no mouseup within 250 msec:
trigger mouserepeat every 50 msec trigger mouserepeat every 50 msec
trigger dragstart trigger dragstart
mousemove: trigger drag mousemove: trigger drag
no mousemove within 250 msec: no mousemove for 250 msec:
trigger dragpause trigger dragpause
mouseup: trigger dragend mouseup: trigger dragend
*/ "anyclick" is not called "click" since this would collide with the click
var clientX, clientY, events of some widgets
dragTimeout = 0, */
mouseInterval = 0; var clientX, clientY,
if (!self.mouseTimeout) { dragTimeout = 0,
// first mousedown mouseInterval = 0;
that.triggerEvent('mousedown', e); if (!self.mouseTimeout) {
self.mouseup = false; // first mousedown
self.mouseTimeout = setTimeout(function() { that.triggerEvent('mousedown', e);
self.mouseTimeout = 0; self.mouseup = false;
if (self.mouseup) { self.mouseTimeout = setTimeout(function() {
// singleclick // 250 ms later, no subsequent click
that.triggerEvent('singleclick', e);
} else {
// mouserepeat, drag
clientX = e.clientX;
clientY = e.clientY;
that.triggerEvent('dragstart', e);
$('*').bind({
mouseenter: dragenter,
mouseleave: dragleave
});
mouserepeat();
mouseInterval = setInterval(mouserepeat, 50);
Ox.UI.$window.unbind('mouseup', mouseup)
.mousemove(mousemove)
.one('mouseup', function(e) {
clearInterval(mouseInterval);
clearTimeout(dragTimeout);
Ox.UI.$window.unbind('mousemove', mousemove);
$('*').unbind({
mouseenter: dragenter,
mouseleave: dragleave
});
that.triggerEvent('dragend', extend(e));
});
that.one('mouseleave', function() {
clearInterval(mouseInterval);
});
}
}, 250);
} else {
// second mousedown
clearTimeout(self.mouseTimeout);
self.mouseTimeout = 0; self.mouseTimeout = 0;
that.triggerEvent('doubleclick', e); if (self.mouseup) {
} // mouse went up, trigger singleclick
Ox.UI.$window.one('mouseup', mouseup); that.triggerEvent('singleclick', e);
function dragenter(e) { } else {
that.triggerEvent('dragenter', e); // mouse is still down, trigger mouserepeat
} // every 50 ms until mouseleave or mouseup
function dragleave(e) { mouserepeat();
that.triggerEvent('dragleave', e); mouseInterval = setInterval(mouserepeat, 50);
} that.one('mouseleave', function() {
function extend(e) { clearInterval(mouseInterval);
return Ox.extend({ });
clientDX: e.clientX - clientX, // trigger dragstart, set up drag events
clientDY: e.clientY - clientY that.triggerEvent('dragstart', e);
}, e); $('*').bind({
} mouseenter: dragenter,
function mousemove(e) { mouseleave: dragleave
e = extend(e); });
clearTimeout(dragTimeout); clientX = e.clientX;
dragTimeout = setTimeout(function() { clientY = e.clientY;
that.triggerEvent('dragpause', e); Ox.UI.$window
}, 250); .unbind('mouseup', mouseup)
that.triggerEvent('drag', e); .mousemove(mousemove)
} .one('mouseup', function(e) {
function mouserepeat() { // stop checking for mouserepeat
that.triggerEvent('mouserepeat'); clearInterval(mouseInterval);
} // stop checking for dragpause
function mouseup(e) { clearTimeout(dragTimeout);
// only trigger on first mouseup // stop checking for drag
if (!self.mouseup) { Ox.UI.$window.unbind('mousemove', mousemove);
that.triggerEvent('anyclick', e); // stop checking for dragenter and dragleave
self.mouseup = true; $('*').unbind({
mouseenter: dragenter,
mouseleave: dragleave
});
// trigger dragend
that.triggerEvent('dragend', extend(e));
});
} }
} }, 250);
} else {
// second mousedown within 250 ms, trigger doubleclick
clearTimeout(self.mouseTimeout);
self.mouseTimeout = 0;
that.triggerEvent('doubleclick', e);
} }
Ox.UI.$window.one('mouseup', mouseup);
function mouseenter(e) { function dragenter(e) {
that.$tooltip.show(e); that.triggerEvent('dragenter', extend(e));
} }
function dragleave(e) {
function mouseleave(e) { that.triggerEvent('dragleave', extend(e));
that.$tooltip.hide(); }
function extend(e) {
return Ox.extend({
clientDX: e.clientX - clientX,
clientDY: e.clientY - clientY
}, e);
} }
function mousemove(e) { function mousemove(e) {
//Ox.print('mousemove!!') e = extend(e);
that.$tooltip.options({ clearTimeout(dragTimeout);
title: self.options.tooltip(e) dragTimeout = setTimeout(function() {
}).show(e); // mouse did not move for 250 ms, trigger dragpause
that.triggerEvent('dragpause', e);
}, 250);
that.triggerEvent('drag', e);
} }
function mouserepeat(e) {
self.setOption = function() { that.triggerEvent('mouserepeat', e);
// self.setOptions(key, value)
// is called when an option changes
// (to be implemented by widget)
};
that._self = self; // fixme: remove
/*@
bindEvent <function> Binds a function to an event
(event, callback) -> <o> This element
({event: callback, ...}) -> <o> This element
callback <f> Callback function
data <o> event data (key/value pairs)
event <s> Event name
Event names can be namespaced, like <code>'click.foo'</code>
@*/
that.bindEvent = function() {
Ox.forEach(Ox.makeObject(arguments), function(callback, event) {
bind('bind', event, callback);
});
return that;
} }
function mouseup(e) {
/*@ if (!self.mouseup) {
bindEventOnce <function> Binds a function to an event, once // mouse went up for the first time, trigger anyclick
(event, callback) -> <obj> This element object that.triggerEvent('anyclick', e);
({event: callback, ...}) -> <obj> This element object self.mouseup = true;
callback <f> Callback function
data <o> event data (key/value pairs)
event <s> Event name
Event names can be namespaced, like <code>'click.foo'</code>
@*/
that.bindEventOnce = function() {
Ox.forEach(Ox.makeObject(arguments), function(callback, event) {
bind('one', event, callback);
});
return that;
};
/*@
defaults <function> Sets the default options for an element object
({key: value, ...}) -> <obj> This element object
key <str> The name of the default option
value <val> The value of the default option
@*/
that.defaults = function(defaults) {
// sets the default options
self.defaults = defaults;
self.options = defaults;
return that;
};
/*@
gainFocus <function> Makes an element object gain focus
() -> <obj> This element object
@*/
that.gainFocus = function() {
Ox.Focus.focus(that.id);
return that;
};
/*@
hasFocus <function> Returns true if an element object has focus
() -> <boolean> True if the element has focus
@*/
that.hasFocus = function() {
return Ox.Focus.focused() == that.id;
};
/*@
loseFocus <function> Makes an element object lose focus
() -> <object> This element object
@*/
that.loseFocus = function() {
Ox.Focus.blur(that.id);
return that;
};
/*@
options <function> Gets or sets the options of an element object
# Usage
() -> <obj> all options
(key) -> <any> the value of option[key]
(key, value) -> <obj> this element
Sets options[key] to value and calls self.setOption(key, value)
if the key/value pair was added or modified
({key: value, ...}) -> <obj> this element
Sets multiple options and calls self.setOption(key, value)
for every key/value pair that was added or modified
# Arguments
key <str> the name of the option
value <val> the value of the option
@*/
that.options = function() {
return Ox.getset(self.options, arguments, self.setOption, that);
};
/*@
removeElement <function> Removes an element object and its event handler
() -> <obj> This element
@*/
that.removeElement = function() {
that.loseFocus();
delete self.$eventHandler;
that.remove();
// fixme: ok to comment out the following line?
delete Ox.UI.elements[that.id];
return that;
};
/*@
triggerEvent <function> Triggers an event
(event) -> <object> This element object
(event, data) -> <object> This element object
({event: data, ...}) -> <object> This element object
event <string> Event name
data <object> Event data (key/value pairs)
@*/
that.triggerEvent = function() {
Ox.forEach(Ox.makeObject(arguments), function(data, event) {
if ([
'mousedown', 'mouserepeat', 'anyclick', 'singleclick', 'doubleclick',
'dragstart', 'drag', 'dragenter', 'dragleave', 'dragpause', 'dragend',
'draganddropstart', 'draganddrop', 'draganddropenter', 'draganddropleave', 'draganddropend',
'playing', 'position', 'progress'
].indexOf(event) == -1) {
if (!/^pandora_/.test(event)) {
Ox.print(that.id, self.options.id, 'trigger', event, data);
}
}
// it is necessary to check if self.$eventHandler exists,
// since, for example, when removing the element on click,
// singleclick will fire after the removal of the event handler
self.$eventHandler && self.$eventHandler.trigger('ox_' + event, data);
});
return that;
};
/*@
unbindEvent <function> Unbinds all callbacks from an event
To unbind a specific handler, use namespaced events, like
<code>bindEvent('click.foo', callback)</code>, and then
<code>unbindEvent('click.foo')</code>.
() -> <object> This element object
Unbinds all events
(event) -> <object> This element object
Unbinds one event
(event, event, ...) -> <object> This element object
Unbinds multiple events
([event, event, ...]) -> <object> This element object
Unbinds multiple events
event <string> Event name
@*/
that.unbindEvent = function() {
if (arguments.length == 0) {
self.$eventHandler.unbind();
} else {
Ox.makeArray(arguments).forEach(function(event) {
self.$eventHandler.unbind('ox_' + event);
});
} }
return that; }
}; }
function mouseenter(e) {
that.$tooltip.show(e);
}
function mouseleave(e) {
that.$tooltip.hide();
}
function mousemove(e) {
//Ox.print('mousemove!!')
that.$tooltip.options({
title: self.options.tooltip(e)
}).show(e);
}
self.setOption = function() {
// self.setOptions(key, value)
// is called when an option changes
// (to be implemented by widget)
};
that._self = self; // fixme: remove
/*@
bindEvent <function> Binds a function to an event
(event, callback) -> <o> This element
({event: callback, ...}) -> <o> This element
callback <f> Callback function
data <o> event data (key/value pairs)
event <s> Event name
Event names can be namespaced, like <code>'click.foo'</code>
@*/
that.bindEvent = function() {
Ox.forEach(Ox.makeObject(arguments), function(callback, event) {
bind('bind', event, callback);
});
return that; return that;
}
/*@
bindEventOnce <function> Binds a function to an event, once
(event, callback) -> <obj> This element object
({event: callback, ...}) -> <obj> This element object
callback <f> Callback function
data <o> event data (key/value pairs)
event <s> Event name
Event names can be namespaced, like <code>'click.foo'</code>
@*/
that.bindEventOnce = function() {
Ox.forEach(Ox.makeObject(arguments), function(callback, event) {
bind('one', event, callback);
});
return that;
};
/*@
defaults <function> Sets the default options for an element object
({key: value, ...}) -> <obj> This element object
key <str> The name of the default option
value <val> The value of the default option
@*/
that.defaults = function(defaults) {
// sets the default options
self.defaults = defaults;
self.options = defaults;
return that;
};
/*@
gainFocus <function> Makes an element object gain focus
() -> <obj> This element object
@*/
that.gainFocus = function() {
Ox.Focus.focus(that.id);
return that;
};
/*@
hasFocus <function> Returns true if an element object has focus
() -> <boolean> True if the element has focus
@*/
that.hasFocus = function() {
return Ox.Focus.focused() == that.id;
};
/*@
loseFocus <function> Makes an element object lose focus
() -> <object> This element object
@*/
that.loseFocus = function() {
Ox.Focus.blur(that.id);
return that;
};
/*@
options <function> Gets or sets the options of an element object
# Usage
() -> <obj> all options
(key) -> <any> the value of option[key]
(key, value) -> <obj> this element
Sets options[key] to value and calls self.setOption(key, value)
if the key/value pair was added or modified
({key: value, ...}) -> <obj> this element
Sets multiple options and calls self.setOption(key, value)
for every key/value pair that was added or modified
# Arguments
key <str> the name of the option
value <val> the value of the option
@*/
that.options = function() {
return Ox.getset(self.options, arguments, self.setOption, that);
};
/*@
removeElement <function> Removes an element object and its event handler
() -> <obj> This element
@*/
that.removeElement = function() {
that.loseFocus();
delete self.$eventHandler;
that.remove();
// fixme: ok to comment out the following line?
delete Ox.UI.elements[that.id];
return that;
};
/*@
triggerEvent <function> Triggers an event
(event) -> <object> This element object
(event, data) -> <object> This element object
({event: data, ...}) -> <object> This element object
event <string> Event name
data <object> Event data (key/value pairs)
@*/
that.triggerEvent = function() {
Ox.forEach(Ox.makeObject(arguments), function(data, event) {
if ([
'mousedown', 'mouserepeat', 'anyclick', 'singleclick', 'doubleclick',
'dragstart', 'drag', 'dragenter', 'dragleave', 'dragpause', 'dragend',
'draganddropstart', 'draganddrop', 'draganddropenter', 'draganddropleave', 'draganddropend',
'playing', 'position', 'progress'
].indexOf(event) == -1) {
if (!/^pandora_/.test(event)) {
Ox.print(that.id, self.options.id, 'trigger', event, data);
}
}
// it is necessary to check if self.$eventHandler exists,
// since, for example, when removing the element on click,
// singleclick will fire after the removal of the event handler
self.$eventHandler && self.$eventHandler.trigger('ox_' + event, data);
});
return that;
};
/*@
unbindEvent <function> Unbinds all callbacks from an event
To unbind a specific handler, use namespaced events, like
<code>bindEvent('click.foo', callback)</code>, and then
<code>unbindEvent('click.foo')</code>.
() -> <object> This element object
Unbinds all events
(event) -> <object> This element object
Unbinds one event
(event, event, ...) -> <object> This element object
Unbinds multiple events
([event, event, ...]) -> <object> This element object
Unbinds multiple events
event <string> Event name
@*/
that.unbindEvent = function() {
if (arguments.length == 0) {
self.$eventHandler.unbind();
} else {
Ox.makeArray(arguments).forEach(function(event) {
self.$eventHandler.unbind('ox_' + event);
});
}
return that;
};
return that;
}; };

View file

@ -60,8 +60,8 @@ view List or item view, like "clips" or "map". Both list and item views are
per type. per type.
span Position or selection in a view, either one or two coordinates or one span Position or selection in a view, either one or two coordinates or one
id, like in "video/01:00", "video/-01:00", "video/01:00,-01:00", id, like in "video/01:00", "video/-01:00", "video/01:00,-01:00",
"video/annotationABC", "video/subtitles:23", "text/chapter42", "video/@annotationABC", "video/@subtitles:23", "text/@chapter42",
"map/0,0", "map/-45,-90,45,90", "map/Barcelona", "image/100,100" etc. "map/0,0", "map/-45,-90,45,90", "map/@barcelona", "image/100,100" etc.
Testing id is asynchronous. Testing id is asynchronous.
sort Sort, like "title" or "-director" or "country,year,-language,+runtime" sort Sort, like "title" or "-director" or "country,year,-language,+runtime"
find Query, like a=x or a=x&b=y or a=x&(b=y|c=z). A query object has the form find Query, like a=x or a=x&b=y or a=x&(b=y|c=z). A query object has the form
@ -85,8 +85,8 @@ k<v k v < is less than (number)
k!<v k v !< is not less than (number) k!<v k v !< is not less than (number)
k>v k v > is more than (number) k>v k v > is more than (number)
k!>v k v !> is not more than (number) k!>v k v !> is not more than (number)
k=v:w k [v,w] = is between (number), is (string) k=v:w k [v,w] - is between (number), is (string)
k!=v:w k [v,w] != is not between (number), is not (string) k!=v:w k [v,w] !- is not between (number), is not (string)
All parts of the URL can be omitted, as long as the order is preserved. All parts of the URL can be omitted, as long as the order is preserved.
@ -504,7 +504,7 @@ Ox.URL = function(options) {
} }
if (!state.span && /^[A-Z@]/.test(parts[0])) { if (!state.span && /^[A-Z@]/.test(parts[0])) {
// test for span id or name // test for span id or name
self.options.getSpan(state.item, state.view, parts[0], function(span, view) { self.options.getSpan(state.item, state.view, parts[0].replace(/%20/g, ' '), function(span, view) {
if (span) { if (span) {
if (!state.view) { if (!state.view) {
// set list or item view // set list or item view

View file

@ -14,6 +14,7 @@ Ox.Map <function> Basic map object
options <o|{}> options options <o|{}> options
clickable <b|false> If true, clicking on the map finds a place clickable <b|false> If true, clicking on the map finds a place
editable <b|false> If true, places are editable editable <b|false> If true, places are editable
find <s|""> Initial query
findPlaceholder <s|"Find"> Placeholder text for the find input element findPlaceholder <s|"Find"> Placeholder text for the find input element
maxMarkers <n|100> Maximum number of markers to be displayed maxMarkers <n|100> Maximum number of markers to be displayed
places <[o]|f|null> Array of, or function that returns, place objects places <[o]|f|null> Array of, or function that returns, place objects
@ -97,6 +98,7 @@ Ox.Map = function(options, self) {
// fixme: isClickable? hasZoombar? // fixme: isClickable? hasZoombar?
clickable: false, clickable: false,
editable: false, editable: false,
find: '',
findPlaceholder: 'Find', findPlaceholder: 'Find',
maxMarkers: 100, maxMarkers: 100,
places: null, places: null,
@ -570,15 +572,9 @@ Ox.Map = function(options, self) {
} }
function getMetersPerPixel() { function getMetersPerPixel() {
// fixme: this is wrong when resizing the map horizontally // m/px = m/deg * deg/px
var mapWidth = self.$map.width(), var degreesPerPixel = 360 / (Ox.MAP_TILE_SIZE * Math.pow(2, self.map.getZoom()));
span = self.map.getBounds().toSpan().lng(); return Ox.getMetersPerDegree(self.map.getCenter().lat()) * degreesPerPixel;
/*
if (span >= 360) {
span = 360 * mapWidth / Ox.MAP_TILE_SIZE;
}
*/
return Ox.getMetersPerDegree(self.map.getCenter().lat()) * span / mapWidth;
} }
function getMinZoom() { function getMinZoom() {
@ -726,9 +722,18 @@ Ox.Map = function(options, self) {
google.maps.event.addListener(self.map, 'zoom_changed', zoomChanged); google.maps.event.addListener(self.map, 'zoom_changed', zoomChanged);
google.maps.event.addListenerOnce(self.map, 'tilesloaded', tilesLoaded); google.maps.event.addListenerOnce(self.map, 'tilesloaded', tilesLoaded);
mapBounds && self.map.fitBounds(mapBounds); if (self.options.find) {
if (self.map.getZoom() < self.minZoom) { self.$findInput.options({value: self.options.find})
self.map.setZoom(self.minZoom); .triggerEvent('submit', {value: self.options.find});
} else if (self.options.selected) {
selectPlace(self.options.selected);
} else {
mapBounds && self.map.fitBounds(mapBounds);
///*
if (self.map.getZoom() < self.minZoom) {
self.map.setZoom(self.minZoom);
}
//*/
} }
self.places = []; self.places = [];
@ -754,6 +759,11 @@ Ox.Map = function(options, self) {
} }
} }
function crossesDateline() {
var bounds = self.map.getBounds();
return bounds.getSouthWest().lng() > bounds.getNorthEast().lng();
}
function mapChanged() { function mapChanged() {
// gets called after panning or zooming // gets called after panning or zooming
Ox.print('mapChanged'); Ox.print('mapChanged');
@ -765,8 +775,7 @@ Ox.Map = function(options, self) {
south = southWest.lat(), south = southWest.lat(),
west = southWest.lng(), west = southWest.lng(),
north = northEast.lat(), north = northEast.lat(),
east = northEast.lng(), east = northEast.lng();
crossesDateline = west > east;
if (!self.isAsync) { if (!self.isAsync) {
self.places.sort(function(a, b) { self.places.sort(function(a, b) {
var sort = { var sort = {
@ -784,31 +793,18 @@ Ox.Map = function(options, self) {
} }
}); });
} else { } else {
Ox.print('QUERY', { Ox.print ('sG cD', spansGlobe(), crossesDateline())
conditions: Ox.merge([
{key: 'lat', value: [south, north], operator: '-'}
], !crossesDateline ? [
{key: 'lng', value: [west, east], operator: '-'}
] : [
{
conditions: [
{key: 'lng', value: west, operator: '<'},
{key: 'lng', value: east, operator: '>'}
],
operator: '|'
}
]),
operator: '&'
});
self.options.places({ self.options.places({
keys: self.placeKeys, keys: self.placeKeys,
query: { query: {
conditions: Ox.merge([ conditions: Ox.merge([
{key: 'lat', value: [south, north], operator: '-'} {key: 'lat', value: [south, north], operator: '-'}
], !crossesDateline ? [ ], spansGlobe() ? [
{key: 'lng', value: [west, east], operator: '-'} {key: 'lng', value: [-180, 180], operator: '-'}
] : [ ] : crossesDateline() ? [
{key: 'lng', value: [east, west], operator: '!-'} {key: 'lng', value: [east, west], operator: '!-'}
] : [
{key: 'lng', value: [west, east], operator: '-'}
]), ]),
operator: '&' operator: '&'
}, },
@ -1033,16 +1029,19 @@ Ox.Map = function(options, self) {
keys: self.placeKeys, keys: self.placeKeys,
query: { query: {
conditions: [ conditions: [
{key: 'id', value: id, operator: '='} {key: 'id', value: id, operator: '=='}
] ],
operator: '&'
}
}, function(result) {
if (result.data.items.length) {
place = new Ox.MapPlace(Ox.extend({
map: that
}, result.data.items[0])).add();
self.places.push(place);
select();
that.zoomToPlace();
} }
}, function(results) {
place = new Ox.MapPlace(Ox.extend({
map: that
}, results.data.items[0])).add();
self.places.push(place);
select();
that.panToPlace();
}); });
} }
} else { } else {
@ -1110,6 +1109,11 @@ Ox.Map = function(options, self) {
//Ox.print('STATUS DONE'); //Ox.print('STATUS DONE');
} }
function spansGlobe() {
// fixme: or self.options.width ??
return self.$map.width() > Ox.MAP_TILE_SIZE * Math.pow(2, self.map.getZoom());
};
function submitFind(data) { function submitFind(data) {
that.findPlace(data.value, function(place) { that.findPlace(data.value, function(place) {
setStatus(place); setStatus(place);

View file

@ -145,7 +145,6 @@ Ox.SplitPanel = function(options, self) {
css[self.edges[1]] = ( css[self.edges[1]] = (
self.length == 3 ? getVisibleSize(self.options.elements[2]) : 0 self.length == 3 ? getVisibleSize(self.options.elements[2]) : 0
) + 'px'; ) + 'px';
Ox.print('i==1 CSS', css)
} else { } else {
if (element.size == 'auto') { if (element.size == 'auto') {
css[self.edges[0]] = getVisibleSize(self.options.elements[0]) css[self.edges[0]] = getVisibleSize(self.options.elements[0])

View file

@ -20,7 +20,7 @@ Ox.VideoPlayer <f> Generic Video Player
enableFind <b|false> If true, enable find enableFind <b|false> If true, enable find
enableFullscreen <b|false> If true, enable fullscreen enableFullscreen <b|false> If true, enable fullscreen
enableKeyboard <b|false> If true, enable keyboard controls enableKeyboard <b|false> If true, enable keyboard controls
enableMouse <b|false> If true, click toggles paused enableMouse <b|false> If true, click toggles paused and drag changes position
externalControls <b|false> If true, controls are outside the video externalControls <b|false> If true, controls are outside the video
find <s|''> Query string find <s|''> Query string
focus <s|'click'> focus on 'click', 'load' or 'mouseover' focus <s|'click'> focus on 'click', 'load' or 'mouseover'
@ -34,7 +34,7 @@ Ox.VideoPlayer <f> Generic Video Player
keepLogoVisible <b|false> If true, logo stays visible after mouseleave keepLogoVisible <b|false> If true, logo stays visible after mouseleave
logo <s|''> Logo image URL logo <s|''> Logo image URL
logoLink <s|''> Logo link URL logoLink <s|''> Logo link URL
logoTitle <s|''> Text for tooltip logoTitle <s|''> Text for Logo tooltip // fixme: shouldn't this be logoTooltip then?s
muted <b|false> If true, video is muted muted <b|false> If true, video is muted
paused <b|false> If true, video is paused paused <b|false> If true, video is paused
playInToOut <b|false> If true, video plays only from in to out playInToOut <b|false> If true, video plays only from in to out

View file

@ -6,11 +6,12 @@
Some conventions: Some conventions:
Functions Functions
- only one var statement, in the first line of the function - only one var statement, in the first line of the function
- return only once, from the last line of the function body - return only once, from the last line of the function
Variable names Variable names
arg argument arg argument
args arguments args arguments
arr array arr array
canFoo boolean
callback callback function callback callback function
col collection (array, string or object) col collection (array, string or object)
date date date date
@ -29,18 +30,48 @@ Some conventions:
v value (of a key/value pair) v value (of a key/value pair)
val value (of a key/value pair) val value (of a key/value pair)
Indentation Indentation
var a = 1, Variable definitions
b = 2, var a = {
c = 3; key: value,
Obj.fn1() key: value,
.fn2() key: value
.fn3(); },
b = {key: value},
c = {key: value};
Method chaining
Obj.fnA({
key: value,
key: value,
key: value
})
.fnB({key: val})
.fnC({key: val});
Simple conditionals
condition && expression;
Conditionals
if (condition) {
expression;
}
Conditionals with long conditions
if (
condition
&& condition
&& condition
) {
expression;
}
Ternary operator
condition ? expression : expression;
Ternary operator with long conditions or expressions
condition ? expression
: condition ? expression
: expression;
*/ */
// todo: check http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ // todo: check http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
// also see https://github.com/tlrobinson/narwhal/blob/master/lib/util.js // also see https://github.com/tlrobinson/narwhal/blob/master/lib/util.js
// Fallbacks -------------------------------------------------------------------
// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter // see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
if (!Array.prototype.filter) { if (!Array.prototype.filter) {
@ -176,11 +207,17 @@ Ox = function(val) {
/*@ /*@
Ox.load <f> Loads a module Ox.load <f> Loads a module
A module named "Test" provides <code>Ox.Test/Ox.Test.js</code>, in which it
defines one method, <code>Ox.load.Test</code>, that takes two arguments,
<code>options</code> and <code>callback</code>, and calls
<code>callback</code> with one argument, <code>true</code> for success or
<code>false</code> if an error occurred. Generally, the module should
define <code>Ox.Test</code> and attach its own methods there.
(module, callback) -> <u> undefined (module, callback) -> <u> undefined
(module, options, callback) -> <u> undefined (module, options, callback) -> <u> undefined
(modules, callback) -> <u> undefined (modules, callback) -> <u> undefined
module <s> Module name module <s> Module name
modules <o> Multiple modules {name: options} modules <o> Multiple modules {name: options, ...}
options <o> Module options options <o> Module options
callback <f> Callback function callback <f> Callback function
success <b> If true, the module has been loaded successfully success <b> If true, the module has been loaded successfully
@ -235,6 +272,7 @@ Ox.uid <f> Returns a unique id
> Ox.uid() != Ox.uid() > Ox.uid() != Ox.uid()
true true
@*/ @*/
Ox.uid = (function() { Ox.uid = (function() {
var uid = 0; var uid = 0;
return function() { return function() {
@ -244,13 +282,14 @@ Ox.uid = (function() {
/*@ /*@
Ox.wrap <f> Wraps a value so that one can directly call any Ox function on it Ox.wrap <f> Wraps a value so that one can directly call any Ox function on it
<code>Ox(value)</code> is a shorthand for <code>Ox.wrap(value)</code>.
(value) -> <o> wrapped value (value) -> <o> wrapped value
chain <f> wrap the return value to allow chaining chain <f> Wrap return values to allow chaining
value <f> unwrap the value wrapped by <code>chain()</chain> value <f> Unwrap the value wrapped by <code>chain()</chain>
value <*> Any value value <*> Any value
> Ox.wrap("foobar").repeat(2) > Ox("foobar").repeat(2)
"foobarfoobar" "foobarfoobar"
> Ox.wrap("foobar").chain().reverse().toTitleCase().value() > Ox("foobar").chain().reverse().toTitleCase().value()
"Raboof" "Raboof"
> Ox.wrap("foobar").value() > Ox.wrap("foobar").value()
"foobar" "foobar"
@ -425,32 +464,6 @@ Ox.avg = function(obj) {
return Ox.sum(obj) / Ox.len(obj); return Ox.sum(obj) / Ox.len(obj);
}; };
/*@
Ox.clone <f> Returns a (shallow or deep) copy of an object or array
> (function() { a = ['val']; b = Ox.clone(a); a[0] = null; return b[0]; }())
'val'
> (function() { a = {key: 'val'}; b = Ox.clone(a); a.key = null; return b.key; }())
'val'
> Ox.clone(0)
0
@*/
Ox.clone = function(col, deep) {
// fixme: is there any use case for shallow copy?
var ret = Ox.isArray(col) ? [] : {};
if (deep) {
Ox.forEach(col, function(val, key) {
ret[key] = ['array', 'object'].indexOf(Ox.typeOf(val)) > -1
? Ox.clone(val, true) : val;
});
} else {
ret = Ox.isArray(col) ? col.slice()
: Ox.isObject(col) ? Ox.extend({}, col)
: col;
}
return ret;
};
/*@ /*@
Ox.contains <f> Tests if a collection contains a value Ox.contains <f> Tests if a collection contains a value
> Ox.contains(['foo', 'bar'], 'foo') > Ox.contains(['foo', 'bar'], 'foo')
@ -470,6 +483,33 @@ Ox.contains = function(col, val) {
return (Ox.isObject(col) ? Ox.values(col) : col).indexOf(val) > -1; return (Ox.isObject(col) ? Ox.values(col) : col).indexOf(val) > -1;
}; };
/*@
Ox.copy <f> Returns a (shallow or deep) copy of an object or array
> (function() { a = ['v']; b = Ox.copy(a); a[0] = null; return b[0]; }())
'v'
> (function() { a = {k: 'v'}; b = Ox.copy(a); a.k = null; return b.k; }())
'v'
> Ox.clone(0)
0
@*/
Ox.copy = Ox.clone = function(col, deep) {
// fixme: remove references to Ox.clone
// fixme: is there any use case for shallow copy?
var ret = Ox.isArray(col) ? [] : {};
if (deep) {
Ox.forEach(col, function(val, key) {
ret[key] = ['array', 'object'].indexOf(Ox.typeOf(val)) > -1
? Ox.clone(val, true) : val;
});
} else {
ret = Ox.isArray(col) ? col.slice()
: Ox.isObject(col) ? Ox.extend({}, col)
: col;
}
return ret;
};
/*@ /*@
Ox.count <f> Counts the occurences of values in a collection Ox.count <f> Counts the occurences of values in a collection
> Ox.count(['f', 'o', 'o']) > Ox.count(['f', 'o', 'o'])
@ -600,7 +640,7 @@ Ox.getObjectById <f> Returns an array element with a given id
> Ox.getObjectById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "foo") > Ox.getObjectById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "foo")
{id: "foo", title: "Foo"} {id: "foo", title: "Foo"}
@*/ @*/
// fixme: shouldn't this be getElementById() ? // fixme: should this be getElementById() ?
Ox.getObjectById = function(arr, id) { Ox.getObjectById = function(arr, id) {
var ret = null; var ret = null;
Ox.forEach(arr, function(v) { Ox.forEach(arr, function(v) {
@ -617,7 +657,7 @@ Ox.getPositionById <f> Returns the index of an array element with a given id
> Ox.getPositionById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "foo") > Ox.getPositionById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "foo")
0 0
@*/ @*/
// fixme: shouldn't this be getIndexById() ? // fixme: this should be getIndexById()
Ox.getPositionById = function(arr, id) { Ox.getPositionById = function(arr, id) {
var ret = -1; var ret = -1;
Ox.forEach(arr, function(v, i) { Ox.forEach(arr, function(v, i) {
@ -656,7 +696,9 @@ Ox.getset <f> Generic getter and setter function
<script> <script>
Ox.test.object = new function() { Ox.test.object = new function() {
var options = {}, var options = {},
setOption = function(key, value) {}, setOption = function(key, value) {
// handle added or modified options
},
that = this; that = this;
that.options = function() { that.options = function() {
return Ox.getset(options, arguments, setOption, that); return Ox.getset(options, arguments, setOption, that);
@ -673,13 +715,13 @@ Ox.getset <f> Generic getter and setter function
Ox.getset = function(obj, args, callback, context) { Ox.getset = function(obj, args, callback, context) {
var obj_ = Ox.clone(obj), ret; var obj_ = Ox.clone(obj), ret;
if (args.length == 0) { if (args.length == 0) {
// getset([]) // []
ret = obj_; ret = obj_;
} else if (args.length == 1 && !Ox.isObject(args[0])) { } else if (args.length == 1 && !Ox.isObject(args[0])) {
// getset([key]) // [key]
ret = Ox.clone(obj[args[0]]); ret = Ox.clone(obj[args[0]]);
} else { } else {
// getset([key, val]) or getset([{key: val, ...}]) // [key, val] or [{key: val, ...}]
args = Ox.makeObject(args); args = Ox.makeObject(args);
obj = Ox.extend(obj, args); obj = Ox.extend(obj, args);
Ox.forEach(args, function(val, key) { Ox.forEach(args, function(val, key) {
@ -710,7 +752,6 @@ Ox.isEmpty <f> Returns true if a collection is empty
false false
@*/ @*/
Ox.isEmpty = function(val) { Ox.isEmpty = function(val) {
// fixme: what about deep isEmpty?
return Ox.len(val) == 0; return Ox.len(val) == 0;
}; };
@ -783,8 +824,7 @@ Ox.len <f> Returns the length of an array, function, object or string
@*/ @*/
Ox.len = function(col) { Ox.len = function(col) {
var type = Ox.typeOf(col); var type = Ox.typeOf(col);
return ['array', 'function', 'string'].indexOf(type) > -1 return ['array', 'function', 'string'].indexOf(type) > -1 ? col.length
? col.length
: type == 'object' ? Ox.values(col).length : void 0; : type == 'object' ? Ox.values(col).length : void 0;
}; };
@ -809,10 +849,10 @@ Ox.loop <f> For-loop, functional-style
step <n> Step value step <n> Step value
callback <f> Iterator function callback <f> Iterator function
i <n> Counter value i <n> Counter value
> Ox.loop(0, 3, 2, function() {})
4
> Ox.loop(10, function(i) { return i != 4; }) > Ox.loop(10, function(i) { return i != 4; })
4 4
> Ox.loop(0, 3, 2, function() {})
4
@*/ @*/
Ox.loop = function() { Ox.loop = function() {
var len = arguments.length, var len = arguments.length,
@ -842,21 +882,23 @@ Ox.makeArray <f> Takes an array-like object and returns a true array
["f", "o", "o"] ["f", "o", "o"]
@*/ @*/
Ox.makeArray = /MSIE/.test(navigator.userAgent) ? function(col) { Ox.makeArray = /MSIE/.test(navigator.userAgent)
var i, len, ret = []; ? function(col) {
try { var i, len, ret = [];
ret = Array.prototype.slice.call(col); try {
} catch(e) { ret = Array.prototype.slice.call(col);
// handle MSIE NodeLists } catch(e) {
len = col.length; // handle MSIE NodeLists
for (i = 0; i < len; i++) { len = col.length;
ret[i] = col[i]; for (i = 0; i < len; i++) {
ret[i] = col[i];
}
} }
} return ret;
return ret; }
} : function(col) { : function(col) {
return Array.prototype.slice.call(col); return Array.prototype.slice.call(col);
} };
/*@ /*@
Ox.makeObject <f> Takes an array and returns an object Ox.makeObject <f> Takes an array and returns an object
@ -867,7 +909,7 @@ Ox.makeObject <f> Takes an array and returns an object
> (function() { return Ox.makeObject(arguments); }('foo', 1)) > (function() { return Ox.makeObject(arguments); }('foo', 1))
{foo: 1} {foo: 1}
> (function() { return Ox.makeObject(arguments); }('foo')) > (function() { return Ox.makeObject(arguments); }('foo'))
{} {foo: void 0}
> (function() { return Ox.makeObject(arguments); }()) > (function() { return Ox.makeObject(arguments); }())
{} {}
@*/ @*/
@ -902,7 +944,7 @@ Ox.map <f> Transforms the values of an array, object or string
@*/ @*/
Ox.map = function(obj, fn) { Ox.map = function(obj, fn) {
// fixme: return null to filter out is a bit esoteric // fixme: return null to filter out may be a bit esoteric
var isObject = Ox.isObject(obj), var isObject = Ox.isObject(obj),
ret = isObject ? {} : []; ret = isObject ? {} : [];
Ox.forEach(obj, function(val, key) { Ox.forEach(obj, function(val, key) {
@ -3300,16 +3342,24 @@ Ox.parseHTML <f> Takes HTML from an untrusted source and returns something sane
> Ox.parseHTML('<a href="http://foo.com" onmouseover="alert()">foo</a>') > Ox.parseHTML('<a href="http://foo.com" onmouseover="alert()">foo</a>')
'<a href="http://foo.com" title="http://foo.com">foo</a>' '<a href="http://foo.com" title="http://foo.com">foo</a>'
> Ox.parseHTML('<a href="javascript:alert()">foo</a>') > Ox.parseHTML('<a href="javascript:alert()">foo</a>')
'&lt;a href=&quot;javascript:alert()&quot;&gt;foo&lt;/a&gt;' '&lt;a href="javascript:alert()"&gt;foo'
> Ox.parseHTML('[http://foo.com foo]') > Ox.parseHTML('[http://foo.com foo]')
'<a href="http://foo.com" title="http://foo.com">foo</a>' '<a href="http://foo.com" title="http://foo.com">foo</a>'
> Ox.parseHTML('<rtl>foo</rtl>') > Ox.parseHTML('<rtl>foo</rtl>')
'<div style="direction: rtl">foo</div>' '<div style="direction: rtl">foo</div>'
> Ox.parseHTML('<script>alert()</script>') > Ox.parseHTML('<script>alert()</script>')
'&lt;script&gt;alert()&lt;/script&gt;' '&lt;script&gt;alert()&lt;/script&gt;'
> Ox.parseHTML('\'foo\' < \'bar\' && "foo" > "bar"')
'\'foo\' &lt; \'bar\' &amp;&amp; "foo" &gt; "bar"'
> Ox.parseHTML('<b>foo')
'<b>foo</b>'
> Ox.parseHTML('<b>foo</b></b>')
'<b>foo</b>'
@*/ @*/
Ox.parseHTML = (function() { Ox.parseHTML = (function() {
var defaultTags = [ var defaultTags = [
// fixme: why not p?
'a', 'b', 'blockquote', 'cite', 'code', 'a', 'b', 'blockquote', 'cite', 'code',
'del', 'em', 'i', 'img', 'ins', 'del', 'em', 'i', 'img', 'ins',
'li', 'ol', 'q', 'rtl', 's', 'li', 'ol', 'q', 'rtl', 's',
@ -3357,13 +3407,13 @@ Ox.parseHTML = (function() {
html = Ox.encodeHTML(html); html = Ox.encodeHTML(html);
html = Ox.parseURLs(html); html = Ox.parseURLs(html);
html = Ox.parseEmailAddresses(html); html = Ox.parseEmailAddresses(html);
Ox.print(html, 'matches', matches);
matches.forEach(function(match, i) { matches.forEach(function(match, i) {
html = html.replace(new RegExp(tab + i + tab, 'gi'), match); html = html.replace(new RegExp(tab + i + tab, 'gi'), match);
}); });
html = html.replace(/\n/g, '<br/>\n') html = html.replace(/\n/g, '<br/>\n')
// close extra opening (and remove extra closing) tags // close extra opening (and remove extra closing) tags
// return $('<div>').html(html).html(); // note: this converts '&quot;' to '"'
// fixme: this converts '&quot;' to '"'
return Ox.element('<div>').html(html).html(); return Ox.element('<div>').html(html).html();
} }
@ -3952,7 +4002,7 @@ Ox.tokenize = (function() {
'global', 'ignoreCase', 'lastIndex', 'multiline', 'source', 'global', 'ignoreCase', 'lastIndex', 'multiline', 'source',
// Window // Window
'applicationCache', 'applicationCache',
'closed', 'content', 'crypto', 'closed', 'console', 'content', 'crypto',
'defaultStatus', 'document', 'defaultStatus', 'document',
'frameElement', 'frames', 'frameElement', 'frames',
'history', 'history',
@ -3966,7 +4016,6 @@ Ox.tokenize = (function() {
'self', 'sessionStorage', 'status', 'statusbar', 'self', 'sessionStorage', 'status', 'statusbar',
'toolbar', 'top' 'toolbar', 'top'
] ]
// Window stuff? 'atob', 'btoa', 'console', 'document' ...
}; };
return function(source) { return function(source) {
@ -4269,10 +4318,10 @@ Ox.extend = function() {
Ox.serialize <f> Parses an object into query parameters Ox.serialize <f> Parses an object into query parameters
> Ox.serialize({a: 1, b: 2, c: 3}) > Ox.serialize({a: 1, b: 2, c: 3})
'a=1&b=2&c=3' 'a=1&b=2&c=3'
> Ox.serialize({a: 1, b: 2.3, c: [4, 5]}) > Ox.serialize({a: -1, b: 2.3, c: [4, 5]})
'a=1&b=2.3&c=4,5' 'a=-1&b=2.3&c=4,5'
> Ox.serialize({string: 'foo', empty: {}, null: null, undefined: void 0}) > Ox.serialize({string: 'foo', empty: {}, null: null, undefined: void 0})
'string=bar' 'string=foo'
@*/ @*/
Ox.serialize = function(obj) { Ox.serialize = function(obj) {
var arr = []; var arr = [];
@ -4288,8 +4337,8 @@ Ox.serialize = function(obj) {
Ox.unserialize <f> Parses query parameters into an object Ox.unserialize <f> Parses query parameters into an object
> Ox.unserialize('a=1&b=2&c=3') > Ox.unserialize('a=1&b=2&c=3')
{a: '1', b: '2', c: '3'} {a: '1', b: '2', c: '3'}
> Ox.unserialize('a=1&b=2.3&c=4,5', true) > Ox.unserialize('a=-1&b=2.3&c=4,5', true)
{a: 1, b: 2.3, c: [4, 5]} {a: -1, b: 2.3, c: [4, 5]}
@*/ @*/
Ox.unserialize = function(str, toNumber) { Ox.unserialize = function(str, toNumber) {
var obj = {}; var obj = {};
@ -4774,8 +4823,8 @@ Ox.truncate = function(str, len, pad, pos) {
Ox.words <f> Splits a string into words, removing punctuation Ox.words <f> Splits a string into words, removing punctuation
(string) -> <[s]> Array of words (string) -> <[s]> Array of words
string <s> Any string string <s> Any string
> Ox.words('Let\'s "walk" a tree-like key/value store--okay?') > Ox.words('Let\'s "split" array-likes into key/value pairs--okay?')
["let's", "walk", "a", "tree-like", "key", "value", "store", "okay"] ["let's", "split", "array-likes", "into", "key", "value", "pairs", "okay"]
@*/ @*/
Ox.words = function(str) { Ox.words = function(str) {
var arr = str.toLowerCase().split(/\b/), var arr = str.toLowerCase().split(/\b/),
@ -4783,12 +4832,11 @@ Ox.words = function(str) {
len = arr.length, len = arr.length,
startsWithWord = /\w/.test(arr[0]); startsWithWord = /\w/.test(arr[0]);
arr.forEach(function(v, i) { arr.forEach(function(v, i) {
// find single occurrences of "-" or "-" // find single occurrences of "-" or "'" that are not at the beginning
// that are not at the beginning or end of the string // or end of the string, and join the surrounding words with them
// and join the surrounding words with them
if ( if (
i > 0 && i < len - 1 && i > 0 && i < len - 1
v.length == 1 && chr.indexOf(v) > -1 && v.length == 1 && chr.indexOf(v) > -1
) { ) {
arr[i + 1] = arr[i - 1] + arr[i] + arr[i + 1]; arr[i + 1] = arr[i - 1] + arr[i] + arr[i + 1];
arr[i - 1] = arr[i] = ''; arr[i - 1] = arr[i] = '';
@ -4986,18 +5034,17 @@ Ox.isEqual = function(a, b) {
isEqual = true; isEqual = true;
} else if (type == 'date') { } else if (type == 'date') {
isEqual = a.getTime() == b.getTime(); isEqual = a.getTime() == b.getTime();
/* toString doesn't do it } else if (type == 'element') {
} else if (['element', 'function'].indexOf(type) > -1) { isEqual = a.isEqualNode(b);
} else if (type == 'function') {
// fixme: this doesn't do it
isEqual = a.toString() == b.toString(); isEqual = a.toString() == b.toString();
*/
} else if (type == 'regexp') { } else if (type == 'regexp') {
isEqual = a.global == b.global && isEqual = a.global == b.global && a.ignore == b.ignore
a.ignore == b.ignore && && a.multiline == b.multiline && a.source == b.source;
a.multiline == b.multiline &&
a.source == b.source;
} else if ( } else if (
['arguments', 'array', 'object'].indexOf(type) > -1 && ['arguments', 'array', 'object'].indexOf(type) > -1
Ox.len(a) == Ox.len(b) && Ox.len(a) == Ox.len(b)
) { ) {
isEqual = true; isEqual = true;
Ox.forEach(a, function(v, k) { Ox.forEach(a, function(v, k) {
@ -5018,7 +5065,7 @@ Ox.isFunction <f> Tests if a value is a function
> Ox.isFunction(/ /) > Ox.isFunction(/ /)
false false
@*/ @*/
Ox.isFunction = function(val) { // is in jQuery Ox.isFunction = function(val) {
return typeof val == 'function' && !Ox.isRegExp(val); return typeof val == 'function' && !Ox.isRegExp(val);
}; };
@ -5090,11 +5137,14 @@ Ox.isObject <f> Tests if a value is a an object
false false
> Ox.isObject(null) > Ox.isObject(null)
false false
> Ox.isObject(/ /)
false
@*/ @*/
Ox.isObject = function(val) { Ox.isObject = function(val) {
return typeof val == 'object' && !Ox.isArguments(val) return typeof val == 'object' && !Ox.isArguments(val)
&& !Ox.isArray(val) && !Ox.isDate(val) && !Ox.isNull(val); && !Ox.isArray(val) && !Ox.isDate(val)
&& !Ox.isNull(val) && !Ox.isRegExp(val);
}; };
/*@ /*@

View file

@ -1,4 +1,4 @@
Ox.load('UI', function() { Ox.load({UI: {}, Geo: {}}, function() {
//Ox.UI.ready(function() { //Ox.UI.ready(function() {
@ -23,7 +23,7 @@ Ox.load('UI', function() {
setBackground($tests, true); setBackground($tests, true);
tests(['../build/Ox.js'/*, '../build/js/ox.data.js'*/]); tests(['../build/Ox.js', '../build/Ox.Geo/Ox.Geo.js']);
function tests() { function tests() {
var passed = 0, failed = 0, var passed = 0, failed = 0,