📄 listgrid.js
字号:
/*
* Isomorphic SmartClient
* Version 6.5 (2008-04-30)
* Copyright(c) 1998-2007 Isomorphic Software, Inc. All rights reserved.
* "SmartClient" is a trademark of Isomorphic Software, Inc.
*
* licensing@smartclient.com
*
* http://smartclient.com/license
*/
//> @class ListGrid// A ListGrid displays a list of Objects in a grid, where each row represents one object and// each cell in the row represents one property. //// @implements DataBoundComponent // @treeLocation Client Reference/Grids// @visibility external//<isc.ClassFactory.defineClass("ListGrid", "Canvas");// Synonym for backCompat. NOTE: define an alias rather than make a subclass, otherwise, attempts// to skin the class using the old name would only affect the subclass!isc.addGlobal("ListViewer", isc.ListGrid);// define groups for documentation purposes //> @groupDef data //< //> @groupDef databinding // DataBinding means the automatic, highly customizable process of 'binding' a UI component // to a DataSource, so that a UI component displays, edits and saves DataSource records // using appropriate formatters, editors, validation rules, and persistance logic. // // @see interface:DataBoundComponent // @title DataBinding //< //> @groupDef hiliting //< //> @groupDef selection //< //> @groupDef sorting //< //> @groupDef dragging //< //> @groupDef editing // Data being displayed by a grid may be edited within the grid, by showing editing // interfaces embedded inside the cells of the grid. // <P> // <b>Enabling editing</b> // <P> // Editing is enabled when +link{listGrid.canEdit,canEdit} is <code>true</code>. When enabled, // the user can begin editing via the // +link{listGrid.editEvent,editEvent}, typically click or double-click. Editing can also be triggered // programmatically by a call to +link{listGrid.startEditing,startEditing()} or // +link{listGrid.startEditingNew,startEditingNew()}. // <P> // <b>New record creation</b> // <P> // By default, editing is restricted to existing records. Setting +link{listGrid.listEndEditAction} to // "next" allows the user to create new records by simply navigating off the end of the dataset // with the keyboard. Editing of new records can also be initiated with // +link{listGrid.startEditingNew()}, for example, from a button outside the grid. // <P> // <b>Saving changes</b> // <P> // Saving of changes is triggered automatically when the user navigates out of the row or cell // being edited (based on +link{listGrid.saveByCell}) or when the user ends editing. Automatic // saving of changes can be disabled entirely via // +link{listGrid.autoSaveEdits,autoSaveEdits:false}, in which case a manual call to // +link{listGrid.saveEdits,saveEdits()} or +link{listGrid.saveAllEdits,saveAllEdits()} is required // to trigger saving. // <P> // If a grid has no DataSource, saving means that the properties of the +link{ListGridRecord}s // in +link{listGrid.data,grid.data} are directly changed. // <P> // For a grid with a DataSource, saving will be accomplished by using DataSource "update" // operations for existing records, and DataSource "add" operations for new records. If multiple // records have been edited and +link{listGrid.saveAllEdits,saveAllEdits()} is called, // +link{rpcManager.startQueue,request queuing} will be automatically used to enable all // edits to be saved in one HTTP turnaround (if using the SmartClient Server). // <P> // By default, a grid will send only updated fields and the primaryKey field as part of // +link{dsRequest.data} so that the server can discern which fields the user actually changed. // However, the grid always includes the original field values in the // dsRequest as +link{dsRequest.oldValues}. // <P> // Note that although it is possible to load DataSource data without actually declaring a // +link{dataSourceField.primaryKey,primaryKey field}, a primaryKey must be declared for // editing and saving. The primaryKey value is how SmartClient identifies the changed // record to the server. // <P> // <b>Validation</b> // <P> // Any time saving is attempted, validation is automatically triggered. Values entered by the // user will be checked against the +link{listGridField.validators} and the // +link{dataSourceField.validators}. Any invalid values abort an attempted save. // <P> // Similar to editing and saving, validation can be done on row transitions or on cell // transitions by setting +link{listGrid.validateByCell,validateByCell}, or can be disabled entirely // via +link{listGrid.neverValidate,neverValidate:true}. // <P> // <b>Editability of cells</b> // <P> // Editors will either be shown for the complete row or for a single cell based on // +link{listGrid,editByCell,editByCell}. Whether a cell can be edited can be controlled on a // per field basis by setting +link{listGridField.canEdit,field.canEdit}, or on a per-record basis // by setting +link{listGrid.recordEditProperty,recordEditProperty} on a // +link{ListGridRecord,record}, or can be controlled on an arbitrary, programmatic basis via // an override of +link{listGrid.canEditCell()}. // <P> // Cells which are not editable just display the cell's current value. // <P> // <b>Keyboard Navigation</b> // <P> // Full keyboard navigation is supported by default, including Tab and Shift-Tab to navigate // between cells in a row, and Up Arrow and Down Arrow to traverse rows. Several properties // on both grids and fields, all named *EditAction, control navigation behavior of certain keys // (eg Enter). // <P> // You can use +link{listGrid.startEditing,startEditing(<i>rowNum</i>, <i>colNum</i>)} to // programmatically move editing to a particular cell, for example, during a // +link{listGridField.changed,field.changed()} event. // <P> // <b>editValues (unsaved changes)</b> // <P> // The term "editValues" means changes that the user has made to the dataset which have not // been saved. The grid manages and stores editValues separately from the data itself in order // to allow the user to revert to original values, and in order to enable to grid to send only // updated fields to the server. // <P> // Because editValues are stored separately, if you directly access the dataset (eg via // <code>grid.data.get()</code>) you will see the records without the user's unsaved changes. // Many APIs exist for retrieving and managing editValues (search for editValue). // For the common case of needing to access the record-as-edited, you can call // +link{listGrid.getEditedRecord,grid.getEditedRecord(rowNum)}. // <P> // When accessing and manipulating edited data, you should think carefully about whether // you want to be working with the original data or with the edited version. Values entered // by the user may not have been validated yet, or may have failed validation, hence you may // find a String value in a field of type "date" or "int", which could cause naive formatters or // totalling functions to crash. // <P> // Setting editValues is fully equivalent to the user making changes to data via the editing UI. // If you <i>also</i> allow editing external to the grid, setting editValues is one way to // combine changes from external editors into the grid's edits, so that you can do a single // save. // <P> // <b>Customizing Cell Editors</b> // <P> // When a cell is being edited, the editor displayed in the cell will be a +link{class:FormItem}. // The editor type for the cell will be determined by +link{listGrid.getEditorType()} based on the // specified +link{ListGridField.editorType} or +link{ListGridField.type, data type} for the field in // question. // <P> // You can customize the editor by setting +link{listGridField.editorProperties} to a set of // properties that is valid for that FormItem type. Custom FormItem classes are also allowed, // for example, you may use +link{formItem.icons} to create an icon that launches a separate // +link{Dialog} in order to provide an arbitrary interface that allows the user to select the // value for a field. // <P> // <b>Events</b> // <P> // Editing triggers several events which you can provide handlers for in order to customize // editing behavior. Some of the most popular are +link{listGridField.change,field.change()}, // +link{listGridField.changed,field.changed()} for detecting changes made by the user, // +link{listGrid.cellChanged()} for detecting changes that have been successfully saved, // and +link{listGrid.editorEnter()} and +link{listGrid.editorExit,editorExit()} for detecting user // navigation during editing. // <P> // You can also install event handlers directly on the FormItem-based editors used in the grid // via +link{listGridField.editorProperties,editorProperties} as mentioned above. When handling // event on items, or which involve items, be aware that in addition to standard // +link{FormItem} APIs, editors have the following properties: // <P> // - <code>rowNum</code>: The rowNum of the record being edited.<br> // - <code>colNum</code>: The colNum of the cell being edited.<br> // - <code>grid</code>: A pointer back to the listGrid containing the record. // // @title Grid Editing // @visibility external //< // Note: we also include a pointer to the record on the FormItem - don't expose this for now // as the user will be more likely to want to work with the result of 'getEditedRecord()' than // the underlying record values. //> @groupDef imageColumns // Columns that show images either as their only appearance or in addition to text. //<isc.defineClass("GridBody", isc.GridRenderer).addProperties({ // suppress adjustOverflow while pending a redraw so we can resize smaller without seeing // a scrollbar flash in and out of existance adjustOverflowWhileDirty:false, // context menus (NOTE: ListGrid-level handling is identical for cell vs row context click) cellContextClick : function (record, rowNum, colNum) { return this.grid._cellContextClick(record, rowNum, colNum); }, getInnerHTML : function () { // call bodyDrawing on the LG if we are the primary body if (this == this.grid.body) this.grid.bodyDrawing(this); return this.Super("getInnerHTML", arguments); }, // if this is removed, DONTCOMBINE directive no longer needed in GridRenderer.js _drawRecordAsSingleCell : function (rowNum, record,c) { var lg = this.grid; if (lg.showNewRecordRow && lg._isNewRecordRow(rowNum)) return true; return isc.GridRenderer._instancePrototype. _drawRecordAsSingleCell.call(this, rowNum,record,c); //return this.Super("_drawRecordAsSingleCell", arguments); }, // observe the scroll routine of the body so we can sync up scrollTo : function (left, top, cssScroll, dontReport) { if (isc._traceMarkers) arguments.__this = this; // Clamp the positions passed in to the edges of the viewport // (avoids the header from getting out of synch with the body.) if (left != null) { var maxScrollLeft = this.getScrollWidth() - this.getViewportWidth(); left = Math.max(0, Math.min(maxScrollLeft, left)); } if (top != null) { var maxScrollTop = this.getScrollHeight() - this.getViewportHeight(); top = Math.max(0, Math.min(maxScrollTop, top)); } var lg = this.grid; //this.logWarn("body.scrollTo: " + this.getStackTrace()); if (!dontReport) lg.bodyScrolled(left, top, this); this.invokeSuper(null, "scrollTo", left,top,cssScroll, dontReport); // If the body scrolled without forcing a redraw, ensure any visible edit form // items are notified that they have moved. if (!this.isDirty() && lg._editorShowing) { lg._editRowForm.itemsMoved(); } }, // Redraw overridden: // - Update the editRow form items (we don't create more items than we need when // rendering incrementally) // - Update the values in the edit row form. redraw : function (reason,b,c,d) { var lg = this.grid, editForm = lg._editRowForm, editing = lg._editorShowing, editColNum, editRowNum, editRecord, completeWidths, fieldsToRemove; // if body redraw came from data change, folder opening, or resizing of content, // it's likely to introduce a v-scrollbar. // If leaveScrollbarGap is false, call '_updateFieldWidths()' before the redraw occurs so // we leave a gap for the v-scrollbar, rather than redrawing with both V and H scrollbar, // then resizing the fields and redrawing without an H-scrollbar. if (!lg.leaveScrollbarGap && lg.predictScrollbarGap && (this.overflow == isc.Canvas.AUTO)) { var vScrollOn = this.vscrollOn, vScrollWillBeOn = !lg.isEmpty() && (lg.getTotalRows() * lg.cellHeight) > this.getInnerHeight(); if (vScrollOn != vScrollWillBeOn) { lg._updateFieldWidths("body redrawing with changed vertical scroll-state"); } } if (editing) { this.logInfo("redraw with editors showing, editForm.hasFocus: " + editForm.hasFocus, "gridEdit"); editColNum = lg.getEditCol(); this._storeFocusForRedraw(); // This will add the new edit items corresponding to the newly displayed fields // and return the items that need to be removed (after the body is actually redrawn, // which will hide them) // It also fires the "redrawing" notification on any items that are about to be redrawn fieldsToRemove = this._updateEditItems(); } this.invokeSuper(null, "redraw", reason,b,c,d); if (editing) { // Remove the items that correspond to fields that are no longer rendered in the DOM if (fieldsToRemove != null && fieldsToRemove.length > 0) { editForm.removeItems(fieldsToRemove); } // Fire the method to notify form items that they have been drawn() / redrawn() // or cleared() lg._editItemsDrawingNotification(null, true, this); /* var itemColArray = [], items = lg._editRowForm.getItems(); for (var i =0; i < items.length; i++) { itemColArray.add(items[i].colNum + " - " + items[i].name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -