From 5aa0835649900a4f2dfdb1dd048bc19785e4db64 Mon Sep 17 00:00:00 2001 From: Amir Plivatsky Date: Tue, 12 Jul 2011 23:34:27 +0300 Subject: [PATCH] - Added support for textarea and HTMLarea fields + i18n additional labels (editor Save/Cancel, YUI Datatable Loading/Error messages, and also column sort tooltips (new in YUI 29.0). - Added CSS files for the existing two DataTable Templates. Each file should be added to the corresponding template as a CSS Attachment. - Avoid terminating the editor on Enter. - Arrange for TAB to save and move editor for next cell also for HTMLarea editor. - Define classes "wg-dt-textarea" and "wg-dt-htmlarea" + styling for the corresponding cells. - Commented out handleTableKeyEvent() (reason in the code). - Implemented a simple workaround to restore the "editor" field (not preserved due to an unknown reason). --- lib/WebGUI/i18n/English/Form_DataTable.pm | 29 +++ www/extras/css/wg-datatable-html.css | 60 ++++++ www/extras/css/wg-datatable-yui.css | 59 ++++++ .../yui-webgui/build/form/datatable.css | 12 ++ www/extras/yui-webgui/build/form/datatable.js | 171 ++++++++++++++---- 5 files changed, 293 insertions(+), 38 deletions(-) create mode 100644 www/extras/css/wg-datatable-html.css create mode 100644 www/extras/css/wg-datatable-yui.css diff --git a/lib/WebGUI/i18n/English/Form_DataTable.pm b/lib/WebGUI/i18n/English/Form_DataTable.pm index edc027a27..98c84260a 100644 --- a/lib/WebGUI/i18n/English/Form_DataTable.pm +++ b/lib/WebGUI/i18n/English/Form_DataTable.pm @@ -74,6 +74,18 @@ our $I18N = { 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" => { message => q{Add Column}, lastUpdated => 0, @@ -152,6 +164,23 @@ our $I18N = { 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; diff --git a/www/extras/css/wg-datatable-html.css b/www/extras/css/wg-datatable-html.css new file mode 100644 index 000000000..49914b162 --- /dev/null +++ b/www/extras/css/wg-datatable-html.css @@ -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; +} +*/ + diff --git a/www/extras/css/wg-datatable-yui.css b/www/extras/css/wg-datatable-yui.css new file mode 100644 index 000000000..090b084f7 --- /dev/null +++ b/www/extras/css/wg-datatable-yui.css @@ -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; +} +*/ diff --git a/www/extras/yui-webgui/build/form/datatable.css b/www/extras/yui-webgui/build/form/datatable.css index dcbf283e1..5eb78e34e 100644 --- a/www/extras/yui-webgui/build/form/datatable.css +++ b/www/extras/yui-webgui/build/form/datatable.css @@ -7,3 +7,15 @@ .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; +} diff --git a/www/extras/yui-webgui/build/form/datatable.js b/www/extras/yui-webgui/build/form/datatable.js index 279d8a1bb..23ba4ac80 100644 --- a/www/extras/yui-webgui/build/form/datatable.js +++ b/www/extras/yui-webgui/build/form/datatable.js @@ -1,4 +1,3 @@ - /*global WebGUI*/ // Initialize namespace if (typeof WebGUI == "undefined") { @@ -8,7 +7,6 @@ if (typeof WebGUI.Form == "undefined") { WebGUI.Form = {}; } - /** * This object contains scripts for the DataTable form control */ @@ -39,6 +37,21 @@ WebGUI.Form.DataTable this.options = options; 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 ) * Add a row to the bottom of the table @@ -105,16 +118,21 @@ WebGUI.Form.DataTable /************************************************************************ * handleEditorKeyEvent ( obj ) * 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. - * Use the handleTableKeyEvent() to handle the moving * Open a new cell editor on the newly focused cell */ this.handleEditorKeyEvent = function ( obj ) { // 9 = tab, 13 = enter 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 nextCell = this.dataTable.getNextTdEl( cell ); this.dataTable.saveCellEditor(); @@ -128,8 +146,6 @@ WebGUI.Form.DataTable // No next cell, make a new row and open the editor for that one 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 } }; @@ -159,7 +175,10 @@ WebGUI.Form.DataTable * handleTableKeyEvent ( obj ) * Handle a keypress inside the DataTable * 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 = function ( obj ) { // 9 = tab, 13 = enter, 32 = space @@ -171,6 +190,7 @@ WebGUI.Form.DataTable } } }; +*/ /************************************************************************ * hideSchemaDialog ( ) @@ -211,7 +231,13 @@ WebGUI.Form.DataTable } 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 ) { @@ -222,6 +248,40 @@ WebGUI.Form.DataTable 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 = "
" + value + "
"; + }; + 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.containerId, this.columns, @@ -230,12 +290,52 @@ WebGUI.Form.DataTable ); 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 YAHOO.util.Dom.addClass( document.body, "yui-skin-sam" ); this.dataTable.subscribe( "cellDblclickEvent", this.dataTable.onEventShowCellEditor ); 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( "editorShowEvent", this.handleEditorShowEvent, this, true ); this.dataTable.subscribe( "rowAddEvent", this.handleRowAdd, this, true ); @@ -288,7 +388,6 @@ WebGUI.Form.DataTable scope : this } } ); - // This data table will be submitted async if ( this.options.ajaxSaveUrl ) { var save = new YAHOO.widget.Button( { @@ -340,6 +439,8 @@ WebGUI.Form.DataTable "format link", "format number", "format date", + "format textarea", + "format htmlarea", "add column", "cancel", "ok", @@ -349,7 +450,13 @@ WebGUI.Form.DataTable "help select row", "help add row", "help default sort", - "help reorder column" + "help reorder column", + "data error", + "sort ascending", + "sort descending" + ], + 'WebGUI' : [ + "Loading..." ] }, onpreload : { @@ -372,7 +479,7 @@ WebGUI.Form.DataTable var helpDialog = new YAHOO.widget.Panel( "helpWindow", { modal : false, draggable : true, - zIndex : 1000 + zIndex : 10000 } ); helpDialog.setHeader( "DataTable Help" ); helpDialog.setBody( @@ -411,28 +518,16 @@ WebGUI.Form.DataTable }; var buttonLabel = this.i18n.get( "Form_DataTable", "delete column" ); - var availableFormats = [ - { - "value" : "text", - "label" : this.i18n.get( "Form_DataTable", "format text" ) - }, - { - "value" : "number", - "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" ) - } - ]; + var availableFormats = []; + var formatType = [ "text", "number", "email", "link", "date", "textarea", "htmlarea" ]; + for ( var fti = 0; fti < formatType.length; fti++) { + availableFormats.push( + { + "value" : formatType[fti], + "label" : this.i18n.get( "Form_DataTable", "format " + formatType[fti] ) + } + ); + } // function for creating new database columns to the table schema var createTableColumn = function(i,cols) { @@ -602,7 +697,7 @@ WebGUI.Form.DataTable this.updateSchema = function () { var data = this.schemaDialog.getData(); - + // First delete columns var deleteCols = YAHOO.lang.JSON.parse( data[ "deleteCols" ] ); for ( var x = 0; x < deleteCols.length; x++ ) { @@ -630,7 +725,7 @@ WebGUI.Form.DataTable var rows = this.dataTable.getRecordSet().getRecords(); for ( var r = 0; r < rows.length; r++ ) { rows[ r ].setData( newKey, rows[ r ].getData( oldKey ) ); - rows[ r ].setData( oldKey, undefined ); + rows[ r ].setData( oldKey, undefined ); } } @@ -640,7 +735,7 @@ WebGUI.Form.DataTable formatter : format, resizeable : ( col ? col.resizeable : 1 ), sortable : ( col ? col.sortable : 1 ), - editor : ( format == "date" ? "date" : "textbox") + editor : this.editorByFormat( format ) }; if ( format == "date" ) { newCol["dateOptions"] = { format : this.options.dateFormat }; @@ -671,9 +766,9 @@ WebGUI.Form.DataTable } } } + i++; } - this.dataTable.render(); this.schemaDialog.cancel(); };