allow menu item to trigger native file dialog (see demo, fixes #691)

This commit is contained in:
rlx 2012-03-24 10:13:33 +00:00
parent 1c3e257bc8
commit df03bf1841
6 changed files with 246 additions and 97 deletions

View file

@ -1,42 +1,155 @@
Ox.load('UI', function() { Ox.load('UI', function() {
//Ox.Theme('modern'); var files,
Ox.FileInput({ $menu = Ox.MainMenu({
maxFiles: 1, menus: [
width: 256 {
id: 'file', title: 'File', items: [
{id: 'mount', title: 'Mount Volume...', icon: Ox.UI.getImageURL('symbolMount'), checked: true, disabled: true, keyboard: 'control m'},
{id: 'select', title: 'Select Files...', icon: Ox.UI.getImageURL('symbolVolume'), file: {maxFiles: -1, maxSize: -1, width: 96}, keyboard: 'control f'},
{id: 'unmount', title: 'Unmount Volume', icon: Ox.UI.getImageURL('symbolUnmount'), keyboard: 'control u'}
]
}
]
})
.bindEvent({
click: function(data) {
if (data.id == 'select') {
files = data.files;
openDialog();
}
}
}),
$main = Ox.Element()
.append(
Ox.Label({
textAlign: 'center',
title: 'File Button',
width: 128
}) })
.css({ .css({
position: 'absolute', position: 'absolute',
left: '16px', left: '16px',
top: '16px' top: '16px'
}) })
.appendTo(Ox.$body); )
.append(
Ox.FileButton({ Ox.FileButton({
title: 'Select Files...', maxFiles: 1,
width: 256 title: 'Select File...',
}) width: 128
.bindEvent({
click: function(data) {
this.options({disabled: true});
Ox.FileInput({
value: data.files,
width: 256
}) })
.css({ .css({
position: 'absolute', position: 'absolute',
left: '16px', left: '160px',
top: '80px' top: '16px'
}) })
.appendTo(Ox.$body); )
} .append(
Ox.Label({
textAlign: 'center',
title: 'File Input',
width: 128
}) })
.css({ .css({
position: 'absolute', position: 'absolute',
left: '16px', left: '16px',
top: '48px' top: '48px'
}) })
)
.append(
Ox.FileInput({
maxFiles: 1,
width: 256
})
.css({
position: 'absolute',
left: '160px',
top: '48px'
})
)
.append(
Ox.FileInput({
width: 256
})
.css({
position: 'absolute',
left: '160px',
top: '80px'
})
),
$panel = Ox.SplitPanel({
elements: [
{
element: $menu,
size: 20
},
{
element: $main
}
],
orientation: 'vertical'
})
.appendTo(Ox.$body); .appendTo(Ox.$body);
function openDialog() {
var $content,
$dialog = Ox.Dialog({
buttons: [
Ox.Button({
id: 'cancel',
title: 'Cancel'
})
.bindEvent({
click: function() {
$dialog.close();
}
}),
Ox.Button({
id: 'upload',
title: 'Upload'
})
.bindEvent({
click: function() {
$dialog.close();
}
})
],
content: $content = Ox.Element()
.css(getContentCSS())
.append(
Ox.FileInput({
value: files,
width: 256
})
.css({
position: 'absolute',
left: '16px',
top: '16px',
marginBottom: '16px'
})
.bindEvent({
change: function(data) {
files = data.value;
$content.css(getContentCSS())
}
})
),
title: 'Files',
width: 288 + Ox.UI.SCROLLBAR_SIZE,
height: 129
})
.open();
}
function getContentCSS() {
return {height: 49 + files.length * 16 + 'px'}
}
}); });

View file

@ -733,6 +733,18 @@ input.OxCheckbox {
} }
/* /*
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
OxFileButton
--------------------------------------------------------------------------------
*/
.OxMenu .OxFileButton > .OxButton {
height: 16px;
margin: -1px 0 0 -6px;
border-width: 0;
background: transparent;
text-align: left;
}
/*
--------------------------------------------------------------------------------
OxFileInput OxFileInput
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
*/ */

View file

@ -32,26 +32,7 @@ Ox.FileButton = function(options, self) {
}) })
.appendTo(that); .appendTo(that);
self.$input = $('<input>') self.$input = renderInput();
.attr(
Ox.extend({
title: self.multiple ? 'Add Files' : 'Select File',
type: 'file'
}, self.multiple ? {
multiple: true
} : {})
)
.css({
float: 'left',
width: self.options.width + 'px',
height: '16px',
marginLeft: -self.options.width + 'px',
opacity: 0
})
.bind({
change: selectFiles
})
.appendTo(that);
self.options.disabled && self.$input.hide(); self.options.disabled && self.$input.hide();
function selectFiles(e) { function selectFiles(e) {
@ -71,7 +52,7 @@ Ox.FileButton = function(options, self) {
}).forEach(function(file) { }).forEach(function(file) {
if (( if ((
self.options.maxFiles == -1 self.options.maxFiles == -1
|| self.options.value.length < self.options.maxFiles || self.files.length < self.options.maxFiles
) && ( ) && (
self.options.maxSize == -1 self.options.maxSize == -1
|| self.size + file.size < self.options.maxSize || self.size + file.size < self.options.maxSize
@ -80,11 +61,36 @@ Ox.FileButton = function(options, self) {
self.size += file.size; self.size += file.size;
} }
}); });
self.$input = renderInput();
if (self.files.length) { if (self.files.length) {
that.triggerEvent('click', {files: self.files}); that.triggerEvent('click', {files: self.files});
} }
} }
function renderInput() {
self.$input && self.$input.remove();
return $('<input>')
.attr(
Ox.extend({
title: self.multiple ? 'Add Files' : 'Select File',
type: 'file'
}, self.multiple ? {
multiple: true
} : {})
)
.css({
float: 'left',
width: self.options.width + 'px',
height: '16px',
marginLeft: -self.options.width + 'px',
opacity: 0
})
.bind({
change: selectFiles
})
.appendTo(that);
}
self.setOption = function(key, value) { self.setOption = function(key, value) {
if (key == 'disabled') { if (key == 'disabled') {
self.$button.options({disabled: value}); self.$button.options({disabled: value});

View file

@ -65,29 +65,7 @@ Ox.FileInput = function(options, self) {
}) })
.appendTo(self.$bar); .appendTo(self.$bar);
self.$input = Ox.Element({ self.$input = renderInput();
element: '<input>'
//tooltip: self.multiple ? 'Add Files' : 'Select File'
})
.attr(
Ox.extend({
title: self.multiple ? 'Add Files' : 'Select File',
type: 'file'
}, self.multiple ? {
multiple: true
} : {})
)
.css({
float: 'left',
width: '16px',
height: '14px',
margin: '-1px -7px 0 -16px',
opacity: 0
})
.bind({
change: addFiles
})
.appendTo(self.$bar);
if (self.multiple) { if (self.multiple) {
self.$files = $('<div>') self.$files = $('<div>')
@ -128,11 +106,6 @@ Ox.FileInput = function(options, self) {
click: function() { click: function() {
self.$list.options({selected: [value]}); self.$list.options({selected: [value]});
removeFiles([value]); removeFiles([value]);
/*
setTimeout(function() {
self.$list.options({selected: []});
}, 25);
*/
} }
}); });
}, },
@ -174,6 +147,7 @@ Ox.FileInput = function(options, self) {
// try to add small files first // try to add small files first
return a.size - b.size; return a.size - b.size;
}).forEach(function(file) { }).forEach(function(file) {
Ox.print('::', file, exists(file), self.options.value)
if (!exists(file) && ( if (!exists(file) && (
self.options.maxFiles == -1 self.options.maxFiles == -1
|| self.options.value.length < self.options.maxFiles || self.options.value.length < self.options.maxFiles
@ -200,9 +174,10 @@ Ox.FileInput = function(options, self) {
) { ) {
self.$button.options({disabled: true}); self.$button.options({disabled: true});
} }
self.$input = renderInput();
} else { } else {
self.$button.options({title: 'close'}).attr({title: 'Clear'}); self.$button.options({title: 'close'}).attr({title: 'Clear'});
self.$input.hide(); self.$input.remove();
} }
that.triggerEvent('change', {value: self.options.value}); that.triggerEvent('change', {value: self.options.value});
} }
@ -213,7 +188,7 @@ Ox.FileInput = function(options, self) {
self.$title.html(getTitleText()); self.$title.html(getTitleText());
self.$size.html(getSizeText()); self.$size.html(getSizeText());
self.$button.options({title: 'add'}).attr({title: ''}); self.$button.options({title: 'add'}).attr({title: ''});
self.$input.show(); self.$input = renderInput();
that.triggerEvent('change', {value: self.options.value}); that.triggerEvent('change', {value: self.options.value});
} }
@ -277,5 +252,29 @@ Ox.FileInput = function(options, self) {
that.triggerEvent('change', {value: self.options.value}); that.triggerEvent('change', {value: self.options.value});
} }
function renderInput() {
self.$input && self.$input.remove();
return $('<input>')
.attr(
Ox.extend({
title: self.multiple ? 'Add Files' : 'Select File',
type: 'file'
}, self.multiple ? {
multiple: true
} : {})
)
.css({
float: 'left',
width: '16px',
height: '14px',
margin: '-1px -7px 0 -16px',
opacity: 0
})
.bind({
change: addFiles
})
.appendTo(self.$bar);
}
return that; return that;
}; };

View file

@ -116,7 +116,7 @@ Ox.Menu = function(options, self) {
} }
} }
function clickItem(position) { function clickItem(position, files) {
var item = that.items[position], var item = that.items[position],
group = item.options('group'), group = item.options('group'),
menu = self.options.mainmenu || self.options.parent || that, menu = self.options.mainmenu || self.options.parent || that,
@ -156,10 +156,10 @@ Ox.Menu = function(options, self) {
}); });
} }
} else { } else {
menu.triggerEvent('click', { menu.triggerEvent('click', Ox.extend({
id: item.options('id'), id: item.options('id'),
title: Ox.stripTags(item.options('title')[0]) title: Ox.stripTags(item.options('title')[0])
}); }, files ? {files: files} : {}));
} }
if (item.options('title').length == 2) { if (item.options('title').length == 2) {
item.toggleTitle(); item.toggleTitle();
@ -236,10 +236,14 @@ Ox.Menu = function(options, self) {
var item, var item,
position, position,
$target = $(event.target), $target = $(event.target),
$parent = $target.parent(); $parent = $target.parent(),
$grandparent = $parent.parent();
if ($parent.is('.OxCell')) { if ($parent.is('.OxCell')) {
$target = $parent; $target = $parent;
$parent = $target.parent(); $parent = $target.parent();
} else if ($grandparent.is('.OxCell')) {
$target = $grandparent;
$parent = $target.parent();
} }
if ($target.is('.OxCell')) { if ($target.is('.OxCell')) {
position = $parent.data('position'); position = $parent.data('position');
@ -617,6 +621,10 @@ Ox.Menu = function(options, self) {
} }
}; };
that.clickItem = function(position, files) {
clickItem(position, files);
};
/*@ /*@
getItem <f> getItem <f>
@*/ @*/

View file

@ -28,7 +28,6 @@ Ox.MenuItem = function(options, self) {
bind: [], // fixme: what's this? bind: [], // fixme: what's this?
checked: null, checked: null,
disabled: false, disabled: false,
file: false,
group: '', group: '',
icon: '', icon: '',
id: '', id: '',
@ -38,6 +37,7 @@ Ox.MenuItem = function(options, self) {
menu: null, // fixme: is passing the menu to 100s of menu items really memory-neutral? menu: null, // fixme: is passing the menu to 100s of menu items really memory-neutral?
position: 0, position: 0,
title: [], title: [],
type: ''
}) })
.options(Ox.extend(Ox.clone(options), { .options(Ox.extend(Ox.clone(options), {
keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard), keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard),
@ -55,7 +55,6 @@ Ox.MenuItem = function(options, self) {
self.options.checked = false; self.options.checked = false;
} }
// construct
that.append( that.append(
that.$status = $('<td>') that.$status = $('<td>')
.addClass('OxCell OxStatus') .addClass('OxCell OxStatus')
@ -79,13 +78,25 @@ Ox.MenuItem = function(options, self) {
: {} : {}
) )
.html( .html(
self.options.file
?
Ox.FileButton(Ox.extend(Ox.clone(self.options.file), {
title: self.options.title[0],
width: self.options.file.width
})).bindEvent({
click: function(data) {
self.options.menu.clickItem(self.options.position, data.files);
}
})
: (
Ox.isString(self.options.title[0]) Ox.isString(self.options.title[0])
? self.options.title[0] ? self.options.title[0]
: $('<div>').html(self.options.title[0]).html() : $('<div>').html(self.options.title[0]).html()
) )
) )
)
.append( .append(
$('<td>') that.$modifiers = $('<td>')
.addClass('OxCell OxModifiers') .addClass('OxCell OxModifiers')
.html( .html(
self.options.keyboard.modifiers.map(function(modifier) { self.options.keyboard.modifiers.map(function(modifier) {
@ -94,7 +105,7 @@ Ox.MenuItem = function(options, self) {
) )
) )
.append( .append(
$('<td>') that.$key = $('<td>')
.addClass( .addClass(
'OxCell Ox' + (self.options.items.length ? 'Submenu' : 'Key') 'OxCell Ox' + (self.options.items.length ? 'Submenu' : 'Key')
) )