Merge pull request #18 from ampli/datatable

DataTable changes and additions
This commit is contained in:
Doug Bell 2011-07-15 15:30:49 -07:00
commit 39f026f866
6 changed files with 311 additions and 38 deletions

View file

@ -392,6 +392,8 @@ sub prepare {
); );
$style->setLink( $url->extras('yui/build/container/assets/skins/sam/container.css'), $style->setLink( $url->extras('yui/build/container/assets/skins/sam/container.css'),
{ rel => "stylesheet", type => "text/css" } ); { rel => "stylesheet", type => "text/css" } );
$style->setLink( $url->extras( 'yui-webgui/build/form/datatable.css'),
{ rel => "stylesheet", type => "text/css" } );
$style->setScript( $url->extras('yui/build/container/container-min.js') ); $style->setScript( $url->extras('yui/build/container/container-min.js') );
$style->setScript( $url->extras('yui/build/button/button-min.js') ); $style->setScript( $url->extras('yui/build/button/button-min.js') );
$style->setScript( $url->extras('yui/build/calendar/calendar-min.js') ); $style->setScript( $url->extras('yui/build/calendar/calendar-min.js') );

View file

@ -74,6 +74,18 @@ our $I18N = {
context => q{Format for a column with a date}, context => q{Format for a column with a date},
}, },
"format textarea" => {
message => q{Textarea},
lastUpdated => 0,
context => q{Format for a textarea column},
},
"format htmlarea" => {
message => q{HTMLarea},
lastUpdated => 0,
context => q{Format for an HTMLarea column},
},
"add column" => { "add column" => {
message => q{Add Column}, message => q{Add Column},
lastUpdated => 0, lastUpdated => 0,
@ -152,6 +164,23 @@ our $I18N = {
context => q{The name of a newly added value to a column}, context => q{The name of a newly added value to a column},
}, },
"data error" => {
message => q{Data error.},
lastUpdated => 0,
context => q{Message to display when DataTable has data error},
},
"sort ascending" => {
message => q{Click to sort ascending},
lastUpdated => 0,
context => q{Message to display in tooltip to sort Column in ascending order},
},
"sort descending" => {
message => q{Click to sort descending},
lastUpdated => 0,
context => q{Message to display in tooltip to sort Column in descending order},
},
}; };
1; 1;

View file

@ -0,0 +1,60 @@
/**
* wg-datatable-html.css
* CSS rules for DataTable assets
*
* Add as attachment to Default DetaTable template (HTML)
*/
/* start content at top of cells */
.dataTable table>tbody>tr>td {
vertical-align: 0;
}
.dataTable>table>tbody>tr>td>p:first-child { /* for htmlarea, but really applies to the starting p of any cell */
margin-top: 0;
}
/* padding in all data cells */
.dataTable table>tbody>tr>td {
padding-left: 10px;
padding-right: 10px;
}
/* examples of further styles */
/* limited textarea/htmlarea cells, show vertical scrollbar if needed */
/*
.dataTable table>tbody>tr>td {
height: 70px;
width: 200px;
overflow-y: auto;
}
*/
/* styling a particular DataTable in the page, by assetId */
/*
#dataTablesrvp2vk8QJqY5E0imSRQag.dataTable table>tbody>tr>td {
color:red;
height:auto;
width:150px;
overflow-y: visible
}
*/
/* minimum row height */
/*
.dataTable table>tbody>tr>td {
min-height:70px;
height:auto !important;
height:70px;
}
*/
/* styling a particular column (e.g column 2), by assetId */
/*
#dataTablesvE67R6JQfmEI__T9pIAkQ.dataTable table>tbody>tr>td:first-child+td {
color:blue;
}
*/

View file

@ -0,0 +1,59 @@
/**
* wg-datatable-yui.css
* CSS rules for DataTable assets
*
* Add as attachment to Default DetaTable template (YUI)
*/
/* start content at top of cells */
.yui-dt-editable {
vertical-align: 0;
}
.wg-dt-htmlarea>p:first-child {
margin-top: 0;
}
/* padding in all data cells */
td.yui-dt-editable .yui-dt-liner {
padding-left: 10px;
padding-right: 10px;
}
/* examples of further styles */
/* limited textarea/htmlarea cells, show vertical scrollbar if needed */
/*
.wg-dt-textarea, .wg-dt-htmlarea {
height: 70px;
width: 200px;
overflow-y: auto;
}
*/
/* styling a particular DataTable in the page */
/*
#dataTablesrvp2vk8QJqY5E0imSRQag .wg-dt-textarea, #dataTablesrvp2vk8QJqY5E0imSRQag .wg-dt-htmlarea {
color:red;
height:auto;
width:150px;
overflow:visible;
}
*/
/* minimum row height */
/*
td.yui-dt-editable .yui-dt-liner {
min-height:70px;
height:auto !important;
height:70px;
}
*/
/* styling a particular column */
/*
#dataTablesrvp2vk8QJqY5E0imSRQag .yui-dt-col-col1 .yui-dt-liner {
color:blue;
}
*/

View file

@ -0,0 +1,21 @@
/**
* datatable.css
* CSS rules for Edit DataTable
*/
/* prevent collapsing of empty rows */
.yui-dt-editable .yui-dt-liner {
min-height: 10px;
}
/* displaying the initial blank line in HTMLarea is not useful */
.wg-dt-htmlarea>p:first-child {
margin-top: 0;
}
/* size of Textarea/HTMLarea cell */
.wg-dt-textarea, .wg-dt-htmlarea {
height: 50px;
width: 150px;
overflow-y: auto;
}

View file

@ -1,4 +1,3 @@
/*global WebGUI*/ /*global WebGUI*/
// Initialize namespace // Initialize namespace
if (typeof WebGUI == "undefined") { if (typeof WebGUI == "undefined") {
@ -8,7 +7,6 @@ if (typeof WebGUI.Form == "undefined") {
WebGUI.Form = {}; WebGUI.Form = {};
} }
/** /**
* This object contains scripts for the DataTable form control * This object contains scripts for the DataTable form control
*/ */
@ -39,6 +37,21 @@ WebGUI.Form.DataTable
this.options = options; this.options = options;
this.schemaDialog = undefined; this.schemaDialog = undefined;
/************************************************************************
* editorByFormat ( event, data )
* Return the DataTable editor type that matches the given format
*/
this.editorByFormat
= function ( format ) {
switch( format ) {
case "text":
case "number":
case "link":
return "textbox";
}
return format;
};
/************************************************************************ /************************************************************************
* addRow ( event, data ) * addRow ( event, data )
* Add a row to the bottom of the table * Add a row to the bottom of the table
@ -59,11 +72,18 @@ WebGUI.Form.DataTable
/************************************************************************ /************************************************************************
* deleteSelectedRows ( ) * deleteSelectedRows ( )
* Delete the selected rows after confirming * Delete the selected rows after confirming
* If there is an editor in the deleted row, cancel it
*/ */
this.deleteSelectedRows this.deleteSelectedRows
= function ( ) { = function ( ) {
if ( confirm( this.i18n.get( "Form_DataTable", "delete confirm" ) ) ) { if ( confirm( this.i18n.get( "Form_DataTable", "delete confirm" ) ) ) {
var rows = this.dataTable.getSelectedRows(); var rows = this.dataTable.getSelectedRows();
// Cancel editor if present
if ( this.dataTable.getCellEditor() ) {
this.dataTable.cancelCellEditor();
}
for ( var i = 0; i < rows.length; i++ ) { for ( var i = 0; i < rows.length; i++ ) {
this.dataTable.deleteRow( this.dataTable.getRecord( rows[i] ) ); this.dataTable.deleteRow( this.dataTable.getRecord( rows[i] ) );
} }
@ -98,16 +118,21 @@ WebGUI.Form.DataTable
/************************************************************************ /************************************************************************
* handleEditorKeyEvent ( obj ) * handleEditorKeyEvent ( obj )
* Handle a keypress when the Cell Editor is open * Handle a keypress when the Cell Editor is open
* Enter will close the editor and move down * Not implemented: Enter will close the editor and move down
* Tab will close the editor and move right. * Tab will close the editor and move right.
* Use the handleTableKeyEvent() to handle the moving
* Open a new cell editor on the newly focused cell * Open a new cell editor on the newly focused cell
*/ */
this.handleEditorKeyEvent this.handleEditorKeyEvent
= function ( obj ) { = function ( obj ) {
// 9 = tab, 13 = enter // 9 = tab, 13 = enter
var e = obj.event; var e = obj.event;
if ( e.keyCode == 9 || e.keyCode == 13 ) {
// Avoid terminating the editor on enter
if ( e.keyCode == 13) {
return false;
}
if ( e.keyCode == 9) {
var cell = this.dataTable.getCellEditor().getTdEl(); var cell = this.dataTable.getCellEditor().getTdEl();
var nextCell = this.dataTable.getNextTdEl( cell ); var nextCell = this.dataTable.getNextTdEl( cell );
this.dataTable.saveCellEditor(); this.dataTable.saveCellEditor();
@ -121,8 +146,6 @@ WebGUI.Form.DataTable
// No next cell, make a new row and open the editor for that one // No next cell, make a new row and open the editor for that one
this.dataTable.addRow( {} ); this.dataTable.addRow( {} );
} }
// BUG: If pressing Enter, editor gets hidden right away due to YUI default event
// putting e.preventDefault() and return false here makes no difference
} }
}; };
@ -152,7 +175,10 @@ WebGUI.Form.DataTable
* handleTableKeyEvent ( obj ) * handleTableKeyEvent ( obj )
* Handle a keypress inside the DataTable * Handle a keypress inside the DataTable
* Space will open the cell editor * Space will open the cell editor
* Note: it doesn't currently work: getSelectedTdEls() always returns [] when selectionMode is "standard"
* Commented out for now.
*/ */
/*
this.handleTableKeyEvent this.handleTableKeyEvent
= function ( obj ) { = function ( obj ) {
// 9 = tab, 13 = enter, 32 = space // 9 = tab, 13 = enter, 32 = space
@ -164,6 +190,7 @@ WebGUI.Form.DataTable
} }
} }
}; };
*/
/************************************************************************ /************************************************************************
* hideSchemaDialog ( ) * hideSchemaDialog ( )
@ -204,7 +231,13 @@ WebGUI.Form.DataTable
} }
var dataTableOptions = { var dataTableOptions = {
dateOptions : { format : this.options.dateFormat } dateOptions : {
format : this.options.dateFormat,
MSG_LOADING : this.i18n.get( "WebGUI", "Loading..." ),
MSG_ERROR : this.i18n.get( "Form_DataTable", "data error" ),
MSG_SORTASC : this.i18n.get( "Form_DataTable", "sort ascending" ),
MSG_SORTDESC : this.i18n.get( "Form_DataTable", "sort descending" )
}
}; };
if ( this.options.showEdit ) { if ( this.options.showEdit ) {
@ -215,6 +248,40 @@ WebGUI.Form.DataTable
dataTableOptions.initialRequest = ""; dataTableOptions.initialRequest = "";
} }
for ( var i = 0; i < this.columns.length; i++ ) {
this.columns[ i ].editor = this.editorByFormat( this.columns[ i ].formatter );
}
var widget = YAHOO.widget,
DT = widget.DataTable;
// Dynamically add HTMLarea field type
// HTMLAreaCellEditor is like TextareaCellEditor, but with an additional property "htmlarea" which is true
var HTMLAreaCellEditor = function(a) {
widget.TextareaCellEditor.superclass.constructor.call(this, a);
};
YAHOO.lang.extend( HTMLAreaCellEditor, widget.TextareaCellEditor, {
htmlarea : true
} );
// Extend the static arrays of editors and formatters
DT.Editors[ "htmlarea" ] = HTMLAreaCellEditor;
// Define classes "wg-dt-textarea" and "wg-dt-htmlarea" that can be overided by a stylesheet
// (e.g. in the extraHeadTags of the asset).
var formatter = function ( type ) {
var fmt = function( el, oRecord, oColumn, oData ) {
var value = YAHOO.lang.isValue(oData) ? oData : "";
el.innerHTML = "<div class='wg-dt-" + type + "'>" + value + "</div>";
};
return fmt;
};
DT.Formatter[ "textarea" ] = formatter( "textarea" );
DT.Formatter[ "htmlarea" ] = formatter( "htmlarea" );
// XXX need to do it with YUI API
widget.BaseCellEditor.prototype.LABEL_SAVE = this.i18n.get( "Form_DataTable", "save" );
widget.BaseCellEditor.prototype.LABEL_CANCEL = this.i18n.get( "Form_DataTable", "cancel" );
this.dataTable = new YAHOO.widget.DataTable( this.dataTable = new YAHOO.widget.DataTable(
this.containerId, this.containerId,
this.columns, this.columns,
@ -223,12 +290,52 @@ WebGUI.Form.DataTable
); );
if ( this.options.showEdit ) { if ( this.options.showEdit ) {
var tinymceEdit = "tinymce-edit";
var saveThis = this;
this.dataTable.doBeforeShowCellEditor = function( oCellEditor ) {
if ( !oCellEditor.htmlarea ) {
return true;
}
oCellEditor.getInputValue = function() {
return tinyMCE.activeEditor.getContent();
};
oCellEditor.textarea.setAttribute( 'id', tinymceEdit );
tinyMCE.execCommand( 'mceAddControl', false, tinymceEdit );
setTimeout(function(){ tinyMCE.execCommand( 'mceFocus',false, tinymceEdit ); }, 0);
// watch hitting tab, which should save the current cell and open an editor on the next
tinyMCE.activeEditor.onKeyDown.add(
function( eh, t ) {
return function(ed, e) { // ed unused
eh.call( t, { event: e } );
};
}( saveThis.handleEditorKeyEvent, saveThis )
);
return true;
};
// Remove TinyMCE on save or cancel
var mceRemoveControl = function ( oArgs ) {
var oCellEditor = oArgs.editor;
if ( oCellEditor.htmlarea ) {
tinyMCE.execCommand( 'mceRemoveControl', false, tinymceEdit );
oCellEditor.textarea.removeAttribute( 'id' );
}
};
this.dataTable.subscribe( "editorSaveEvent", mceRemoveControl );
this.dataTable.subscribe( "editorCancelEvent", mceRemoveControl );
// Add the class so our editors get the right skin // Add the class so our editors get the right skin
YAHOO.util.Dom.addClass( document.body, "yui-skin-sam" ); YAHOO.util.Dom.addClass( document.body, "yui-skin-sam" );
this.dataTable.subscribe( "cellDblclickEvent", this.dataTable.onEventShowCellEditor ); this.dataTable.subscribe( "cellDblclickEvent", this.dataTable.onEventShowCellEditor );
this.dataTable.subscribe( "rowClickEvent", this.dataTable.onEventSelectRow ); this.dataTable.subscribe( "rowClickEvent", this.dataTable.onEventSelectRow );
this.dataTable.subscribe( "tableKeyEvent", this.handleTableKeyEvent, this, true ); /* this.handleTableKeyEvent() is commented out, see there for the reason */
/* this.dataTable.subscribe( "tableKeyEvent", this.handleTableKeyEvent, this, true ); */
this.dataTable.subscribe( "editorKeydownEvent", this.handleEditorKeyEvent, this, true ); this.dataTable.subscribe( "editorKeydownEvent", this.handleEditorKeyEvent, this, true );
this.dataTable.subscribe( "editorShowEvent", this.handleEditorShowEvent, this, true ); this.dataTable.subscribe( "editorShowEvent", this.handleEditorShowEvent, this, true );
this.dataTable.subscribe( "rowAddEvent", this.handleRowAdd, this, true ); this.dataTable.subscribe( "rowAddEvent", this.handleRowAdd, this, true );
@ -281,7 +388,6 @@ WebGUI.Form.DataTable
scope : this scope : this
} }
} ); } );
// This data table will be submitted async // This data table will be submitted async
if ( this.options.ajaxSaveUrl ) { if ( this.options.ajaxSaveUrl ) {
var save = new YAHOO.widget.Button( { var save = new YAHOO.widget.Button( {
@ -333,6 +439,8 @@ WebGUI.Form.DataTable
"format link", "format link",
"format number", "format number",
"format date", "format date",
"format textarea",
"format htmlarea",
"add column", "add column",
"cancel", "cancel",
"ok", "ok",
@ -342,7 +450,13 @@ WebGUI.Form.DataTable
"help select row", "help select row",
"help add row", "help add row",
"help default sort", "help default sort",
"help reorder column" "help reorder column",
"data error",
"sort ascending",
"sort descending"
],
'WebGUI' : [
"Loading..."
] ]
}, },
onpreload : { onpreload : {
@ -365,7 +479,7 @@ WebGUI.Form.DataTable
var helpDialog = new YAHOO.widget.Panel( "helpWindow", { var helpDialog = new YAHOO.widget.Panel( "helpWindow", {
modal : false, modal : false,
draggable : true, draggable : true,
zIndex : 1000 zIndex : 10000
} ); } );
helpDialog.setHeader( "DataTable Help" ); helpDialog.setHeader( "DataTable Help" );
helpDialog.setBody( helpDialog.setBody(
@ -404,28 +518,16 @@ WebGUI.Form.DataTable
}; };
var buttonLabel = this.i18n.get( "Form_DataTable", "delete column" ); var buttonLabel = this.i18n.get( "Form_DataTable", "delete column" );
var availableFormats = [ var availableFormats = [];
{ var formatType = [ "text", "number", "email", "link", "date", "textarea", "htmlarea" ];
"value" : "text", for ( var fti = 0; fti < formatType.length; fti++) {
"label" : this.i18n.get( "Form_DataTable", "format text" ) availableFormats.push(
}, {
{ "value" : formatType[fti],
"value" : "number", "label" : this.i18n.get( "Form_DataTable", "format " + formatType[fti] )
"label" : this.i18n.get( "Form_DataTable", "format number" ) }
}, );
{ }
"value" : "email",
"label" : this.i18n.get( "Form_DataTable", "format email" )
},
{
"value" : "link",
"label" : this.i18n.get( "Form_DataTable", "format link" )
},
{
"value" : "date",
"label" : this.i18n.get( "Form_DataTable", "format date" )
}
];
// function for creating new database columns to the table schema // function for creating new database columns to the table schema
var createTableColumn = function(i,cols) { var createTableColumn = function(i,cols) {
@ -595,7 +697,7 @@ WebGUI.Form.DataTable
this.updateSchema this.updateSchema
= function () { = function () {
var data = this.schemaDialog.getData(); var data = this.schemaDialog.getData();
// First delete columns // First delete columns
var deleteCols = YAHOO.lang.JSON.parse( data[ "deleteCols" ] ); var deleteCols = YAHOO.lang.JSON.parse( data[ "deleteCols" ] );
for ( var x = 0; x < deleteCols.length; x++ ) { for ( var x = 0; x < deleteCols.length; x++ ) {
@ -623,7 +725,7 @@ WebGUI.Form.DataTable
var rows = this.dataTable.getRecordSet().getRecords(); var rows = this.dataTable.getRecordSet().getRecords();
for ( var r = 0; r < rows.length; r++ ) { for ( var r = 0; r < rows.length; r++ ) {
rows[ r ].setData( newKey, rows[ r ].getData( oldKey ) ); rows[ r ].setData( newKey, rows[ r ].getData( oldKey ) );
rows[ r ].setData( oldKey, undefined ); rows[ r ].setData( oldKey, undefined );
} }
} }
@ -633,7 +735,7 @@ WebGUI.Form.DataTable
formatter : format, formatter : format,
resizeable : ( col ? col.resizeable : 1 ), resizeable : ( col ? col.resizeable : 1 ),
sortable : ( col ? col.sortable : 1 ), sortable : ( col ? col.sortable : 1 ),
editor : ( format == "date" ? "date" : "textbox") editor : this.editorByFormat( format )
}; };
if ( format == "date" ) { if ( format == "date" ) {
newCol["dateOptions"] = { format : this.options.dateFormat }; newCol["dateOptions"] = { format : this.options.dateFormat };
@ -664,9 +766,9 @@ WebGUI.Form.DataTable
} }
} }
} }
i++; i++;
} }
this.dataTable.render(); this.dataTable.render();
this.schemaDialog.cancel(); this.schemaDialog.cancel();
}; };