2015-09-07 18:44:10 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
2016-08-21 02:19:24 +03:00
|
|
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
|
|
|
(function(require){ var module={} // make module AMD/node compatible...
|
|
|
|
|
/*********************************************************************/
|
2015-09-07 18:44:10 +03:00
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
var keyboard = require('../keyboard')
|
2015-12-08 07:42:07 +03:00
|
|
|
var object = require('../object')
|
2015-09-20 21:54:28 +03:00
|
|
|
|
|
|
|
|
|
2015-09-07 18:44:10 +03:00
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
// helpers...
|
|
|
|
|
|
|
|
|
|
var proxyToDom =
|
|
|
|
|
module.proxyToDom =
|
|
|
|
|
function(name){
|
2018-03-09 17:51:27 +03:00
|
|
|
return function(...args){
|
|
|
|
|
// bind functions to this...
|
|
|
|
|
// XXX is this the right way to go???
|
|
|
|
|
args = args
|
|
|
|
|
.map(function(a){
|
|
|
|
|
return a instanceof Function ?
|
|
|
|
|
a.bind(this)
|
|
|
|
|
: a
|
|
|
|
|
}.bind(this))
|
|
|
|
|
|
|
|
|
|
name in this.dom ?
|
|
|
|
|
// proxy handler...
|
|
|
|
|
this.dom[name].apply(this.dom, args)
|
|
|
|
|
// on/trigger handlers...
|
|
|
|
|
: this.dom.trigger(name, args)
|
2017-09-09 19:04:34 +03:00
|
|
|
|
2015-09-07 18:44:10 +03:00
|
|
|
return this
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-13 23:38:16 +03:00
|
|
|
var eventToDom =
|
|
|
|
|
module.eventToDom =
|
|
|
|
|
function(name, defaults){
|
|
|
|
|
return function(){
|
|
|
|
|
// register...
|
|
|
|
|
if(arguments[0] instanceof Function){
|
2018-11-12 23:04:00 +03:00
|
|
|
this.dom.trigger(name, [...arguments])
|
2017-11-13 23:38:16 +03:00
|
|
|
|
|
|
|
|
// trigger...
|
|
|
|
|
} else {
|
|
|
|
|
var args = (arguments.length == 0 && defaults) ?
|
|
|
|
|
defaults.call(this)
|
2018-11-12 23:04:00 +03:00
|
|
|
: [...arguments]
|
2017-11-13 23:38:16 +03:00
|
|
|
args = args instanceof Array ? args : [args]
|
|
|
|
|
|
|
|
|
|
this.dom.trigger(name, args)
|
|
|
|
|
}
|
|
|
|
|
return this
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-07 18:44:10 +03:00
|
|
|
|
|
|
|
|
// XXX triggering events from here and from jQuery/dom has a
|
|
|
|
|
// different effect...
|
|
|
|
|
var triggerEventWithSource =
|
|
|
|
|
module.triggerEventWithSource =
|
|
|
|
|
function(){
|
|
|
|
|
var args = args2array(arguments)
|
|
|
|
|
var evt = args.shift()
|
|
|
|
|
|
|
|
|
|
if(typeof(evt) == typeof('str')){
|
|
|
|
|
evt = $.Event(evt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
evt.source = this
|
|
|
|
|
|
|
|
|
|
args.splice(0, 0, evt)
|
|
|
|
|
|
|
|
|
|
this.dom.trigger.apply(this.dom, args)
|
|
|
|
|
return this
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
var WidgetClassPrototype = {
|
2015-11-09 22:48:13 +03:00
|
|
|
make: function(obj, client, options){
|
2015-09-20 21:54:28 +03:00
|
|
|
console.error('Widget must define a .make method.')
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var WidgetPrototype = {
|
2016-05-08 16:13:19 +03:00
|
|
|
// NOTE: this must have .data('widget-controller', this) set...
|
2015-09-20 21:54:28 +03:00
|
|
|
dom: null,
|
|
|
|
|
client: null,
|
|
|
|
|
|
|
|
|
|
options: {
|
2017-03-08 21:26:37 +03:00
|
|
|
keyboardRepeatPause: 100,
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
nonPropagatedEvents: [
|
2017-01-25 22:22:33 +03:00
|
|
|
'start',
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
'click',
|
|
|
|
|
'keydown',
|
2016-04-30 20:14:39 +03:00
|
|
|
|
|
|
|
|
'close',
|
2015-09-20 21:54:28 +03:00
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
|
2017-01-12 02:09:59 +03:00
|
|
|
keybindings: null,
|
2015-09-20 21:54:28 +03:00
|
|
|
keyboard: null,
|
|
|
|
|
|
|
|
|
|
// XXX triggering events from here and from jQuery/dom has a
|
|
|
|
|
// different effect...
|
|
|
|
|
trigger: triggerEventWithSource,
|
|
|
|
|
|
|
|
|
|
// proxy event api...
|
|
|
|
|
on: proxyToDom('on'),
|
|
|
|
|
one: proxyToDom('one'),
|
|
|
|
|
off: proxyToDom('off'),
|
|
|
|
|
bind: proxyToDom('bind'),
|
|
|
|
|
unbind: proxyToDom('unbind'),
|
|
|
|
|
deligate: proxyToDom('deligate'),
|
|
|
|
|
undeligate: proxyToDom('undeligate'),
|
|
|
|
|
|
2017-01-06 05:17:14 +03:00
|
|
|
// custom events...
|
2017-01-24 00:14:31 +03:00
|
|
|
//
|
2017-01-25 22:22:33 +03:00
|
|
|
start: function(handler){
|
|
|
|
|
handler ?
|
|
|
|
|
this.on('start', handler)
|
|
|
|
|
:this.trigger('start')
|
|
|
|
|
return this
|
|
|
|
|
},
|
2017-01-24 00:14:31 +03:00
|
|
|
// NOTE: this can be passed a string that can be used as a reason
|
|
|
|
|
// for closing...
|
|
|
|
|
close: function(a){
|
2017-01-06 05:17:14 +03:00
|
|
|
// trigger...
|
2017-01-24 00:14:31 +03:00
|
|
|
if(a == null || typeof(a) == typeof('str')){
|
|
|
|
|
a = a || 'accept'
|
2017-01-06 05:17:14 +03:00
|
|
|
this.parent.close
|
2017-01-24 00:14:31 +03:00
|
|
|
&& this.parent.close(a)
|
|
|
|
|
this.trigger('close', a)
|
2017-01-06 05:17:14 +03:00
|
|
|
|
|
|
|
|
// register new handler...
|
|
|
|
|
} else {
|
2017-01-24 00:14:31 +03:00
|
|
|
this.on('close', a)
|
2017-01-06 05:17:14 +03:00
|
|
|
}
|
|
|
|
|
return this
|
|
|
|
|
},
|
2015-09-20 21:54:28 +03:00
|
|
|
|
|
|
|
|
// XXX this will not:
|
2015-10-02 17:32:13 +03:00
|
|
|
// - attach dom to parent... (???)
|
|
|
|
|
// - handle focus... (???)
|
2015-09-20 21:54:28 +03:00
|
|
|
// XXX same as ContainerPrototype.__init__ but skips client...
|
|
|
|
|
__init__: function(parent, options){
|
|
|
|
|
var that = this
|
|
|
|
|
|
|
|
|
|
parent = this.parent = $(parent || 'body')
|
|
|
|
|
options = options || {}
|
|
|
|
|
|
2017-01-27 17:33:21 +03:00
|
|
|
this.keybindings = JSON.parse(JSON.stringify(this.keybindings))
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
// merge options...
|
|
|
|
|
var opts = Object.create(this.options)
|
|
|
|
|
Object.keys(options).forEach(function(n){ opts[n] = options[n] })
|
|
|
|
|
options = this.options = opts
|
|
|
|
|
|
|
|
|
|
// build the dom...
|
|
|
|
|
if(this.constructor.make){
|
2015-11-09 22:48:13 +03:00
|
|
|
this.dom = this.constructor.make(this, options)
|
2016-05-08 16:13:19 +03:00
|
|
|
|
|
|
|
|
this.dom.data('widget-controller', this)
|
2015-09-20 21:54:28 +03:00
|
|
|
}
|
|
|
|
|
|
2015-10-02 17:32:13 +03:00
|
|
|
// XXX do we do this here???
|
|
|
|
|
/*
|
|
|
|
|
if(parent && this.dom){
|
|
|
|
|
parent.append(this.dom)
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
// add keyboard handler...
|
2017-01-12 02:09:59 +03:00
|
|
|
if(this.keybindings && this.dom){
|
2017-01-12 02:41:03 +03:00
|
|
|
this.keyboard =
|
|
|
|
|
this.keyboard || keyboard.KeyboardWithCSSModes(
|
|
|
|
|
function(){ return that.keybindings },
|
|
|
|
|
function(){ return that.dom })
|
2017-01-06 05:17:14 +03:00
|
|
|
this.dom
|
|
|
|
|
.keydown(
|
2017-03-08 21:26:37 +03:00
|
|
|
keyboard.makePausableKeyboardHandler(
|
2017-01-06 05:17:14 +03:00
|
|
|
this.keyboard,
|
|
|
|
|
options.logKeys,
|
2017-03-08 21:26:37 +03:00
|
|
|
this,
|
|
|
|
|
function(){ return this.options.keyboardRepeatPause }))
|
2015-09-20 21:54:28 +03:00
|
|
|
}
|
|
|
|
|
|
2016-04-30 20:14:39 +03:00
|
|
|
if(this.options.nonPropagatedEvents != null){
|
|
|
|
|
this.on(this.options.nonPropagatedEvents.join(' '),
|
|
|
|
|
function(evt){ evt.stopPropagation() })
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
return this
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var Widget =
|
|
|
|
|
module.Widget =
|
|
|
|
|
object.makeConstructor('Widget',
|
|
|
|
|
WidgetClassPrototype,
|
|
|
|
|
WidgetPrototype)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
|
|
var ContainerClassPrototype = {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ContainerPrototype = {
|
2016-05-08 16:13:19 +03:00
|
|
|
// NOTE: this must have .data('widget-controller', this) set...
|
|
|
|
|
dom: null,
|
2015-09-22 23:55:49 +03:00
|
|
|
|
|
|
|
|
focus: function(handler){
|
|
|
|
|
if(handler != null){
|
|
|
|
|
this.on('focus', handler)
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
this.dom.focus()
|
|
|
|
|
this.client
|
|
|
|
|
&& this.client.focus
|
|
|
|
|
&& this.client.focus()
|
|
|
|
|
}
|
|
|
|
|
return this
|
|
|
|
|
},
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
// XXX this is the same as WidgetPrototype.__init__ but also handles
|
|
|
|
|
// the client...
|
|
|
|
|
__init__: function(parent, client, options){
|
|
|
|
|
var that = this
|
2017-01-27 17:33:21 +03:00
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
parent = this.parent = $(parent || 'body')
|
|
|
|
|
options = options || {}
|
|
|
|
|
|
2017-01-27 17:33:21 +03:00
|
|
|
this.keybindings = JSON.parse(JSON.stringify(this.keybindings))
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
this.client = client
|
2016-01-05 04:48:24 +03:00
|
|
|
client.parent = this
|
2015-09-20 21:54:28 +03:00
|
|
|
|
|
|
|
|
// merge options...
|
|
|
|
|
var opts = Object.create(this.options)
|
|
|
|
|
Object.keys(options).forEach(function(n){ opts[n] = options[n] })
|
|
|
|
|
options = this.options = opts
|
|
|
|
|
|
|
|
|
|
// build the dom...
|
|
|
|
|
if(this.constructor.make){
|
2015-09-22 23:55:49 +03:00
|
|
|
this.dom = this.constructor
|
2015-11-09 22:48:13 +03:00
|
|
|
.make(this, client.dom || client, options)
|
2016-05-08 16:13:19 +03:00
|
|
|
|
|
|
|
|
this.dom.data('widget-controller', this)
|
2015-09-20 21:54:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add keyboard handler...
|
2017-01-12 02:09:59 +03:00
|
|
|
if(this.keybindings && this.dom){
|
2017-01-12 02:41:03 +03:00
|
|
|
this.keyboard =
|
|
|
|
|
this.keyboard || keyboard.KeyboardWithCSSModes(
|
|
|
|
|
function(){ return that.keybindings },
|
|
|
|
|
function(){ return that.dom })
|
2017-01-12 02:09:59 +03:00
|
|
|
this.dom
|
|
|
|
|
.keydown(
|
2017-03-08 21:26:37 +03:00
|
|
|
keyboard.makePausableKeyboardHandler(
|
2017-01-12 02:09:59 +03:00
|
|
|
this.keyboard,
|
|
|
|
|
options.logKeys,
|
2017-03-08 21:26:37 +03:00
|
|
|
this,
|
|
|
|
|
function(){ return this.options.keyboardRepeatPause }))
|
2015-09-20 21:54:28 +03:00
|
|
|
}
|
|
|
|
|
|
2016-04-30 20:14:39 +03:00
|
|
|
if(this.options.nonPropagatedEvents != null){
|
|
|
|
|
this.on(this.options.nonPropagatedEvents.join(' '),
|
|
|
|
|
function(evt){ evt.stopPropagation() })
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-20 21:54:28 +03:00
|
|
|
return this
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var Container =
|
|
|
|
|
module.Container =
|
|
|
|
|
object.makeConstructor('Container',
|
|
|
|
|
ContainerClassPrototype,
|
|
|
|
|
ContainerPrototype)
|
|
|
|
|
|
|
|
|
|
Container.prototype.__proto__ = Widget.prototype
|
2015-09-07 18:44:10 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
2016-08-21 02:19:24 +03:00
|
|
|
* vim:set ts=4 sw=4 : */ return module })
|