Alex A. Naanou acc6d6f60c bugfixes and export filename info...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2017-11-13 23:38:16 +03:00

298 lines
6.7 KiB
JavaScript
Executable File

/**********************************************************************
*
*
*
**********************************************************************/
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
(function(require){ var module={} // make module AMD/node compatible...
/*********************************************************************/
var keyboard = require('../keyboard')
var object = require('../object')
/*********************************************************************/
// helpers...
var proxyToDom =
module.proxyToDom =
function(name){
return function(){
// proxy handler...
if(name in this.dom){
this.dom[name].apply(this.dom, arguments)
// on/trigger handlers...
} else {
arguments[0] instanceof Function ?
this.dom.on(name, arguments[0])
: this.dom.trigger(name, [].slice.call(arguments))
}
return this
}
}
var eventToDom =
module.eventToDom =
function(name, defaults){
return function(){
// register...
if(arguments[0] instanceof Function){
this.dom.trigger(name, [].slice.call(arguments))
// trigger...
} else {
var args = (arguments.length == 0 && defaults) ?
defaults.call(this)
: [].slice.call(arguments)
args = args instanceof Array ? args : [args]
this.dom.trigger(name, args)
}
return this
}
}
// 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
}
/*********************************************************************/
var WidgetClassPrototype = {
make: function(obj, client, options){
console.error('Widget must define a .make method.')
},
}
var WidgetPrototype = {
// NOTE: this must have .data('widget-controller', this) set...
dom: null,
client: null,
options: {
keyboardRepeatPause: 100,
nonPropagatedEvents: [
'start',
'click',
'keydown',
'close',
],
},
keybindings: null,
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'),
// custom events...
//
start: function(handler){
handler ?
this.on('start', handler)
:this.trigger('start')
return this
},
// NOTE: this can be passed a string that can be used as a reason
// for closing...
close: function(a){
// trigger...
if(a == null || typeof(a) == typeof('str')){
a = a || 'accept'
this.parent.close
&& this.parent.close(a)
this.trigger('close', a)
// register new handler...
} else {
this.on('close', a)
}
return this
},
// XXX this will not:
// - attach dom to parent... (???)
// - handle focus... (???)
// XXX same as ContainerPrototype.__init__ but skips client...
__init__: function(parent, options){
var that = this
parent = this.parent = $(parent || 'body')
options = options || {}
this.keybindings = JSON.parse(JSON.stringify(this.keybindings))
// 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){
this.dom = this.constructor.make(this, options)
this.dom.data('widget-controller', this)
}
// XXX do we do this here???
/*
if(parent && this.dom){
parent.append(this.dom)
}
*/
// add keyboard handler...
if(this.keybindings && this.dom){
this.keyboard =
this.keyboard || keyboard.KeyboardWithCSSModes(
function(){ return that.keybindings },
function(){ return that.dom })
this.dom
.keydown(
keyboard.makePausableKeyboardHandler(
this.keyboard,
options.logKeys,
this,
function(){ return this.options.keyboardRepeatPause }))
}
if(this.options.nonPropagatedEvents != null){
this.on(this.options.nonPropagatedEvents.join(' '),
function(evt){ evt.stopPropagation() })
}
return this
},
}
var Widget =
module.Widget =
object.makeConstructor('Widget',
WidgetClassPrototype,
WidgetPrototype)
/*********************************************************************/
var ContainerClassPrototype = {
}
var ContainerPrototype = {
// NOTE: this must have .data('widget-controller', this) set...
dom: null,
focus: function(handler){
if(handler != null){
this.on('focus', handler)
} else {
this.dom.focus()
this.client
&& this.client.focus
&& this.client.focus()
}
return this
},
// XXX this is the same as WidgetPrototype.__init__ but also handles
// the client...
__init__: function(parent, client, options){
var that = this
parent = this.parent = $(parent || 'body')
options = options || {}
this.keybindings = JSON.parse(JSON.stringify(this.keybindings))
this.client = client
client.parent = this
// 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){
this.dom = this.constructor
.make(this, client.dom || client, options)
this.dom.data('widget-controller', this)
}
// add keyboard handler...
if(this.keybindings && this.dom){
this.keyboard =
this.keyboard || keyboard.KeyboardWithCSSModes(
function(){ return that.keybindings },
function(){ return that.dom })
this.dom
.keydown(
keyboard.makePausableKeyboardHandler(
this.keyboard,
options.logKeys,
this,
function(){ return this.options.keyboardRepeatPause }))
}
if(this.options.nonPropagatedEvents != null){
this.on(this.options.nonPropagatedEvents.join(' '),
function(evt){ evt.stopPropagation() })
}
return this
},
}
var Container =
module.Container =
object.makeConstructor('Container',
ContainerClassPrototype,
ContainerPrototype)
Container.prototype.__proto__ = Widget.prototype
/**********************************************************************
* vim:set ts=4 sw=4 : */ return module })