You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by he...@apache.org on 2006/11/13 23:55:14 UTC
svn commit: r474551 [34/49] - in
/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo:
./ src/ src/alg/ src/animation/ src/cal/ src/charting/ src/charting/svg/
src/charting/vml/ src/collections/ src/crypto/ src/data/ src/data/cs...
Propchange: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/Editor2Toolbar.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FilteringTable.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FilteringTable.js?view=auto&rev=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FilteringTable.js (added)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FilteringTable.js Mon Nov 13 14:54:45 2006
@@ -0,0 +1,961 @@
+/*
+ Copyright (c) 2004-2006, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.FilteringTable");
+
+dojo.require("dojo.date.format");
+dojo.require("dojo.collections.Store");
+dojo.require("dojo.html.*");
+dojo.require("dojo.html.util");
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+
+dojo.widget.defineWidget(
+ "dojo.widget.FilteringTable",
+ dojo.widget.HtmlWidget,
+ function(){
+ // summary
+ // Initializes all properties for the widget.
+ this.store=new dojo.collections.Store();
+
+ //declare per instance changeable widget properties
+ this.valueField="Id";
+ this.multiple=false;
+ this.maxSelect=0;
+ this.maxSortable=1; // how many columns can be sorted at once.
+ this.minRows=0;
+ this.defaultDateFormat = "%D";
+ this.isInitialized=false;
+ this.alternateRows=false;
+
+ this.columns=[];
+ this.sortInformation=[{
+ index:0,
+ direction:0
+ }];
+
+ // CSS definitions
+ this.headClass="";
+ this.tbodyClass="";
+ this.headerClass="";
+ this.headerUpClass="selectedUp";
+ this.headerDownClass="selectedDown";
+ this.rowClass="";
+ this.rowAlternateClass="alt";
+ this.rowSelectedClass="selected";
+ this.columnSelected="sorted-column";
+ },
+{
+ // dojo widget properties
+ isContainer: false,
+ templatePath: null,
+ templateCssPath: null,
+
+ // methods.
+ getTypeFromString: function(/* string */s){
+ // summary
+ // Gets a function based on the passed string.
+ var parts = s.split("."), i = 0, obj = dj_global;
+ do{
+ obj = obj[parts[i++]];
+ } while (i < parts.length && obj);
+ return (obj != dj_global) ? obj : null; // function
+ },
+
+ // custom data access.
+ getByRow: function(/*HTMLTableRow*/row){
+ // summary
+ // Returns the data object based on the passed row.
+ return this.store.getByKey(dojo.html.getAttribute(row, "value")); // object
+ },
+ getDataByRow: function(/*HTMLTableRow*/row){
+ // summary
+ // Returns the source data object based on the passed row.
+ return this.store.getDataByKey(dojo.html.getAttribute(row, "value")); // object
+ },
+
+ getRow: function(/* Object */ obj){
+ // summary
+ // Finds the row in the table based on the passed data object.
+ var rows = this.domNode.tBodies[0].rows;
+ for(var i=0; i<rows.length; i++){
+ if(this.store.getDataByKey(dojo.html.getAttribute(rows[i], "value")) == obj){
+ return rows[i]; // HTMLTableRow
+ }
+ }
+ return null; // HTMLTableRow
+ },
+ getColumnIndex: function(/* string */fieldPath){
+ // summary
+ // Returns index of the column that represents the passed field path.
+ for(var i=0; i<this.columns.length; i++){
+ if(this.columns[i].getField() == fieldPath){
+ return i; // integer
+ }
+ }
+ return -1; // integer
+ },
+
+ getSelectedData: function(){
+ // summary
+ // returns all objects that are selected.
+ var data=this.store.get();
+ var a=[];
+ for(var i=0; i<data.length; i++){
+ if(data[i].isSelected){
+ a.push(data[i].src);
+ }
+ }
+ if(this.multiple){
+ return a; // array
+ } else {
+ return a[0]; // object
+ }
+ },
+
+ isSelected: function(/* object */obj){
+ // summary
+ // Returns whether the passed object is currently selected.
+ var data = this.store.get();
+ for(var i=0; i<data.length; i++){
+ if(data[i].src == obj){
+ return true; // boolean
+ }
+ }
+ return false; // boolean
+ },
+ isValueSelected: function(/* string */val){
+ // summary
+ // Returns the object represented by key "val" is selected.
+ var v = this.store.getByKey(val);
+ if(v){
+ return v.isSelected; // boolean
+ }
+ return false; // boolean
+ },
+ isIndexSelected: function(/* number */idx){
+ // summary
+ // Returns the object represented by integer "idx" is selected.
+ var v = this.store.getByIndex(idx);
+ if(v){
+ return v.isSelected; // boolean
+ }
+ return false; // boolean
+ },
+ isRowSelected: function(/* HTMLTableRow */row){
+ // summary
+ // Returns if the passed row is selected.
+ var v = this.getByRow(row);
+ if(v){
+ return v.isSelected; // boolean
+ }
+ return false; // boolean
+ },
+
+ reset: function(){
+ // summary
+ // Resets the widget to its initial internal state.
+ this.store.clearData();
+ this.columns = [];
+ this.sortInformation = [ {index:0, direction:0} ];
+ this.resetSelections();
+ this.isInitialized = false;
+ this.onReset();
+ },
+ resetSelections: function(){
+ // summary
+ // Unselects all data objects.
+ this.store.forEach(function(element){
+ element.isSelected = false;
+ });
+ },
+ onReset:function(){
+ // summary
+ // Stub for onReset event.
+ },
+
+ // selection and toggle functions
+ select: function(/*object*/ obj){
+ // summary
+ // selects the passed object.
+ var data = this.store.get();
+ for(var i=0; i<data.length; i++){
+ if(data[i].src == obj){
+ data[i].isSelected = true;
+ break;
+ }
+ }
+ this.onDataSelect(obj);
+ },
+ selectByValue: function(/*string*/ val){
+ // summary
+ // selects the object represented by key "val".
+ this.select(this.store.getDataByKey(val));
+ },
+ selectByIndex: function(/*number*/ idx){
+ // summary
+ // selects the object represented at index "idx".
+ this.select(this.store.getDataByIndex(idx));
+ },
+ selectByRow: function(/*HTMLTableRow*/ row){
+ // summary
+ // selects the object represented by HTMLTableRow row.
+ this.select(this.getDataByRow(row));
+ },
+ selectAll: function(){
+ // summary
+ // selects all objects.
+ this.store.forEach(function(element){
+ element.isSelected = true;
+ });
+ },
+ onDataSelect: function(/* object */obj){
+ // summary
+ // Stub for onDataSelect event.
+ },
+
+ toggleSelection: function(/*object*/obj){
+ // summary
+ // Flips the selection state of passed obj.
+ var data = this.store.get();
+ for(var i=0; i<data.length; i++){
+ if(data[i].src == obj){
+ data[i].isSelected = !data[i].isSelected;
+ break;
+ }
+ }
+ this.onDataToggle(obj);
+ },
+ toggleSelectionByValue: function(/*string*/val){
+ // summary
+ // Flips the selection state of object represented by val.
+ this.toggleSelection(this.store.getDataByKey(val));
+ },
+ toggleSelectionByIndex: function(/*number*/idx){
+ // summary
+ // Flips the selection state of object at index idx.
+ this.toggleSelection(this.store.getDataByIndex(idx));
+ },
+ toggleSelectionByRow: function(/*HTMLTableRow*/row){
+ // summary
+ // Flips the selection state of object represented by row.
+ this.toggleSelection(this.getDataByRow(row));
+ },
+ toggleAll: function(){
+ // summary
+ // Flips the selection state of all objects.
+ this.store.forEach(function(element){
+ element.isSelected = !element.isSelected;
+ });
+ },
+ onDataToggle: function(/* object */obj){
+ // summary
+ // Stub for onDataToggle event.
+ },
+
+ // parsing functions, from HTML to metadata/SimpleStore
+ _meta:{
+ field:null,
+ format:null,
+ filterer:null,
+ noSort:false,
+ sortType:"String",
+ dataType:String,
+ sortFunction:null,
+ filterFunction:null,
+ label:null,
+ align:"left",
+ valign:"middle",
+ getField:function(){
+ return this.field || this.label;
+ },
+ getType:function(){
+ return this.dataType;
+ }
+ },
+ createMetaData: function(/* object */obj){
+ // summary
+ // Take a JSON-type structure and make it into a ducktyped metadata object.
+ for(var p in this._meta){
+ // rudimentary mixin
+ if(!obj[p]){
+ obj[p] = this._meta[p];
+ }
+ }
+ if(!obj.label){
+ obj.label=obj.field;
+ }
+ if(!obj.filterFunction){
+ obj.filterFunction=this._defaultFilter;
+ }
+ return obj; // object
+ },
+ parseMetadata: function(/* HTMLTableHead */head){
+ // summary
+ // Parses the passed HTMLTableHead element to create meta data.
+ this.columns=[];
+ this.sortInformation=[];
+ var row = head.getElementsByTagName("tr")[0];
+ var cells = row.getElementsByTagName("td");
+ if (cells.length == 0){
+ cells = row.getElementsByTagName("th");
+ }
+ for(var i=0; i<cells.length; i++){
+ var o = this.createMetaData({ });
+
+ // presentation attributes
+ if(dojo.html.hasAttribute(cells[i], "align")){
+ o.align = dojo.html.getAttribute(cells[i],"align");
+ }
+ if(dojo.html.hasAttribute(cells[i], "valign")){
+ o.valign = dojo.html.getAttribute(cells[i],"valign");
+ }
+ if(dojo.html.hasAttribute(cells[i], "nosort")){
+ o.noSort = (dojo.html.getAttribute(cells[i],"nosort")=="true");
+ }
+ if(dojo.html.hasAttribute(cells[i], "sortusing")){
+ var trans = dojo.html.getAttribute(cells[i],"sortusing");
+ var f = this.getTypeFromString(trans);
+ if (f != null && f != window && typeof(f)=="function"){
+ o.sortFunction=f;
+ }
+ }
+ o.label = dojo.html.renderedTextContent(cells[i]);
+ if(dojo.html.hasAttribute(cells[i], "field")){
+ o.field=dojo.html.getAttribute(cells[i],"field");
+ } else if(o.label.length > 0){
+ o.field=o.label;
+ } else {
+ o.field = "field" + i;
+ }
+ if(dojo.html.hasAttribute(cells[i], "format")){
+ o.format=dojo.html.getAttribute(cells[i],"format");
+ }
+ if(dojo.html.hasAttribute(cells[i], "dataType")){
+ var sortType = dojo.html.getAttribute(cells[i],"dataType");
+ if(sortType.toLowerCase()=="html" || sortType.toLowerCase()=="markup"){
+ o.sortType = "__markup__"; // always convert to "__markup__"
+ }else{
+ var type = this.getTypeFromString(sortType);
+ if(type){
+ o.sortType = sortType;
+ o.dataType = type;
+ }
+ }
+ }
+
+ // TODO: set up filtering mechanisms here.
+ if(dojo.html.hasAttribute(cells[i], "filterusing")){
+ var trans = dojo.html.getAttribute(cells[i],"filterusing");
+ var f = this.getTypeFromString(trans);
+ if (f != null && f != window && typeof(f)=="function"){
+ o.filterFunction=f;
+ }
+ }
+
+ this.columns.push(o);
+
+ // check to see if there's a default sort, and set the properties necessary
+ if(dojo.html.hasAttribute(cells[i], "sort")){
+ var info = {
+ index:i,
+ direction:0
+ };
+ var dir = dojo.html.getAttribute(cells[i], "sort");
+ if(!isNaN(parseInt(dir))){
+ dir = parseInt(dir);
+ info.direction = (dir != 0) ? 1 : 0;
+ }else{
+ info.direction = (dir.toLowerCase() == "desc") ? 1 : 0;
+ }
+ this.sortInformation.push(info);
+ }
+ }
+ if(this.sortInformation.length == 0){
+ this.sortInformation.push({
+ index:0,
+ direction:0
+ });
+ } else if (this.sortInformation.length > this.maxSortable){
+ this.sortInformation.length = this.maxSortable;
+ }
+ },
+ parseData: function(/* HTMLTableBody */body){
+ // summary
+ // Parse HTML data into native JSON structure for the store.
+ if(body.rows.length == 0 && this.columns.length == 0){
+ return; // there's no data, ignore me.
+ }
+
+ // create a data constructor based on what we've got for the fields.
+ var self=this;
+ this["__selected__"] = [];
+ var arr = this.store.getFromHtml(this.columns, body, function(obj, row){
+ obj[self.valueField] = dojo.html.getAttribute(row, "value");
+ if(dojo.html.getAttribute(row, "selected")=="true"){
+ self["__selected__"].push(obj);
+ }
+ });
+ this.store.setData(arr);
+ for(var i=0; i<this["__selected__"].length; i++){
+ this.select(this["__selected__"][i]);
+ }
+ this.renderSelections();
+
+ delete this["__selected__"];
+
+ // say that we are already initialized so that we don't kill anything
+ this.isInitialized=true;
+ },
+
+ // standard events
+ onSelect: function(/* HTMLEvent */e){
+ // summary
+ // Handles the onclick event of any element.
+ var row = dojo.html.getParentByType(e.target,"tr");
+ if(dojo.html.hasAttribute(row,"emptyRow")){
+ return;
+ }
+ var body = dojo.html.getParentByType(row,"tbody");
+ if(this.multiple){
+ if(e.shiftKey){
+ var startRow;
+ var rows=body.rows;
+ for(var i=0;i<rows.length;i++){
+ if(rows[i]==row){
+ break;
+ }
+ if(this.isRowSelected(rows[i])){
+ startRow=rows[i];
+ }
+ }
+ if(!startRow){
+ startRow = row;
+ for(; i<rows.length; i++){
+ if(this.isRowSelected(rows[i])){
+ row = rows[i];
+ break;
+ }
+ }
+ }
+ this.resetSelections();
+ if(startRow == row){
+ this.toggleSelectionByRow(row);
+ } else {
+ var doSelect = false;
+ for(var i=0; i<rows.length; i++){
+ if(rows[i] == startRow){
+ doSelect=true;
+ }
+ if(doSelect){
+ this.selectByRow(rows[i]);
+ }
+ if(rows[i] == row){
+ doSelect = false;
+ }
+ }
+ }
+ } else {
+ this.toggleSelectionByRow(row);
+ }
+ } else {
+ this.resetSelections();
+ this.toggleSelectionByRow(row);
+ }
+ this.renderSelections();
+ },
+ onSort: function(/* HTMLEvent */e){
+ // summary
+ // Sort the table based on the column selected.
+ var oldIndex=this.sortIndex;
+ var oldDirection=this.sortDirection;
+
+ var source=e.target;
+ var row=dojo.html.getParentByType(source,"tr");
+ var cellTag="td";
+ if(row.getElementsByTagName(cellTag).length==0){
+ cellTag="th";
+ }
+
+ var headers=row.getElementsByTagName(cellTag);
+ var header=dojo.html.getParentByType(source,cellTag);
+
+ for(var i=0; i<headers.length; i++){
+ dojo.html.setClass(headers[i], this.headerClass);
+ if(headers[i]==header){
+ if(this.sortInformation[0].index != i){
+ this.sortInformation.unshift({
+ index:i,
+ direction:0
+ });
+ } else {
+ this.sortInformation[0] = {
+ index:i,
+ direction:(~this.sortInformation[0].direction)&1
+ };
+ }
+ }
+ }
+
+ this.sortInformation.length = Math.min(this.sortInformation.length, this.maxSortable);
+ for(var i=0; i<this.sortInformation.length; i++){
+ var idx=this.sortInformation[i].index;
+ var dir=(~this.sortInformation[i].direction)&1;
+ dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass);
+ }
+ this.render();
+ },
+ onFilter: function(){
+ // summary
+ // show or hide rows based on the parameters of the passed filter.
+ },
+
+ // Filtering methods
+ _defaultFilter: function(/* Object */obj){
+ // summary
+ // Always return true as the result of the default filter.
+ return true;
+ },
+ setFilter: function(/* string */field, /* function */fn){
+ // summary
+ // set a filtering function on the passed field.
+ for(var i=0; i<this.columns.length; i++){
+ if(this.columns[i].getField() == field){
+ this.columns[i].filterFunction=fn;
+ break;
+ }
+ }
+ this.applyFilters();
+ },
+ setFilterByIndex: function(/* number */idx, /* function */fn){
+ // summary
+ // set a filtering function on the passed column index.
+ this.columns[idx].filterFunction=fn;
+ this.applyFilters();
+ },
+ clearFilter: function(/* string */field){
+ // summary
+ // clear a filtering function on the passed field.
+ for(var i=0; i<this.columns.length; i++){
+ if(this.columns[i].getField() == field){
+ this.columns[i].filterFunction=this._defaultFilter;
+ break;
+ }
+ }
+ this.applyFilters();
+ },
+ clearFilterByIndex: function(/* number */idx){
+ // summary
+ // clear a filtering function on the passed column index.
+ this.columns[idx].filterFunction=this._defaultFilter;
+ this.applyFilters();
+ },
+ clearFilters: function(){
+ // summary
+ // clears all filters.
+ for(var i=0; i<this.columns.length; i++){
+ this.columns[i].filterFunction=this._defaultFilter;
+ }
+ // we'll do the clear manually, it will be faster.
+ var rows=this.domNode.tBodies[0].rows;
+ for(var i=0; i<rows.length; i++){
+ rows[i].style.display="";
+ if(this.alternateRows){
+ dojo.html[((i % 2 == 1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass);
+ }
+ }
+ this.onFilter();
+ },
+ applyFilters: function(){
+ // summary
+ // apply all filters to the table.
+ var alt=0;
+ var rows=this.domNode.tBodies[0].rows;
+ for(var i=0; i<rows.length; i++){
+ var b=true;
+ var row=rows[i];
+ for(var j=0; j<this.columns.length; j++){
+ var value = this.store.getField(this.getDataByRow(row), this.columns[j].getField());
+ if(this.columns[j].getType() == Date && value != null && !value.getYear){
+ value = new Date(value);
+ }
+ if(!this.columns[j].filterFunction(value)){
+ b=false;
+ break;
+ }
+ }
+ row.style.display=(b?"":"none");
+ if(b && this.alternateRows){
+ dojo.html[((alt++ % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass);
+ }
+ }
+ this.onFilter();
+ },
+
+ // sorting functionality
+ createSorter: function(/* array */info){
+ // summary
+ // creates a custom function to be used for sorting.
+ var self=this;
+ var sortFunctions=[]; // our function stack.
+
+ function createSortFunction(fieldIndex, dir){
+ var meta=self.columns[fieldIndex];
+ var field=meta.getField();
+ return function(rowA, rowB){
+ if(dojo.html.hasAttribute(rowA,"emptyRow") || dojo.html.hasAttribute(rowB,"emptyRow")){
+ return -1;
+ }
+ // TODO: check for markup and compare by rendered text.
+ var a = self.store.getField(self.getDataByRow(rowA), field);
+ var b = self.store.getField(self.getDataByRow(rowB), field);
+ var ret = 0;
+ if(a > b) ret = 1;
+ if(a < b) ret = -1;
+ return dir * ret;
+ }
+ }
+
+ var current=0;
+ var max = Math.min(info.length, this.maxSortable, this.columns.length);
+ while(current < max){
+ var direction = (info[current].direction == 0) ? 1 : -1;
+ sortFunctions.push(
+ createSortFunction(info[current].index, direction)
+ );
+ current++;
+ }
+
+ return function(rowA, rowB){
+ var idx=0;
+ while(idx < sortFunctions.length){
+ var ret = sortFunctions[idx++](rowA, rowB);
+ if(ret != 0) return ret;
+ }
+ // if we got here then we must be equal.
+ return 0;
+ }; // function
+ },
+
+ // rendering
+ createRow: function(/* object */obj){
+ // summary
+ // Create an HTML row based on the passed object
+ var row=document.createElement("tr");
+ dojo.html.disableSelection(row);
+ if(obj.key != null){
+ row.setAttribute("value", obj.key);
+ }
+ for(var j=0; j<this.columns.length; j++){
+ var cell=document.createElement("td");
+ cell.setAttribute("align", this.columns[j].align);
+ cell.setAttribute("valign", this.columns[j].valign);
+ dojo.html.disableSelection(cell);
+ var val = this.store.getField(obj.src, this.columns[j].getField());
+ if(typeof(val)=="undefined"){
+ val="";
+ }
+ this.fillCell(cell, this.columns[j], val);
+ row.appendChild(cell);
+ }
+ return row; // HTMLTableRow
+ },
+ fillCell: function(/* HTMLTableCell */cell, /* object */meta, /* object */val){
+ // summary
+ // Fill the passed cell with value, based on the passed meta object.
+ if(meta.sortType=="__markup__"){
+ cell.innerHTML=val;
+ } else {
+ if(meta.getType()==Date) {
+ val=new Date(val);
+ if(!isNaN(val)){
+ var format = this.defaultDateFormat;
+ if(meta.format){
+ format = meta.format;
+ }
+ cell.innerHTML = dojo.date.strftime(val, format);
+ } else {
+ cell.innerHTML = val;
+ }
+ } else if ("Number number int Integer float Float".indexOf(meta.getType())>-1){
+ // TODO: number formatting
+ if(val.length == 0){
+ val="0";
+ }
+ var n = parseFloat(val, 10) + "";
+ // TODO: numeric formatting + rounding :)
+ if(n.indexOf(".")>-1){
+ n = dojo.math.round(parseFloat(val,10),2);
+ }
+ cell.innerHTML = n;
+ }else{
+ cell.innerHTML = val;
+ }
+ }
+ },
+ prefill: function(){
+ // summary
+ // if there's no data in the table, then prefill it with this.minRows.
+ this.isInitialized = false;
+ var body = this.domNode.tBodies[0];
+ while (body.childNodes.length > 0){
+ body.removeChild(body.childNodes[0]);
+ }
+
+ if(this.minRows>0){
+ for(var i=0; i < this.minRows; i++){
+ var row = document.createElement("tr");
+ if(this.alternateRows){
+ dojo.html[((i % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass);
+ }
+ row.setAttribute("emptyRow","true");
+ for(var j=0; j<this.columns.length; j++){
+ var cell = document.createElement("td");
+ cell.innerHTML = " ";
+ row.appendChild(cell);
+ }
+ body.appendChild(row);
+ }
+ }
+ },
+ init: function(){
+ // summary
+ // initializes the table of data
+ this.isInitialized=false;
+
+ // if there is no thead, create it now.
+ var head=this.domNode.getElementsByTagName("thead")[0];
+ if(head.getElementsByTagName("tr").length == 0){
+ // render the column code.
+ var row=document.createElement("tr");
+ for(var i=0; i<this.columns.length; i++){
+ var cell=document.createElement("td");
+ cell.setAttribute("align", this.columns[i].align);
+ cell.setAttribute("valign", this.columns[i].valign);
+ dojo.html.disableSelection(cell);
+ cell.innerHTML=this.columns[i].label;
+ row.appendChild(cell);
+
+ // attach the events.
+ if(!this.columns[i].noSort){
+ dojo.event.connect(cell, "onclick", this, "onSort");
+ }
+ }
+ dojo.html.prependChild(row, head);
+ }
+
+ if(this.store.get().length == 0){
+ return false;
+ }
+
+ var idx=this.domNode.tBodies[0].rows.length;
+ if(!idx || idx==0 || this.domNode.tBodies[0].rows[0].getAttribute("emptyRow")=="true"){
+ idx = 0;
+ var body = this.domNode.tBodies[0];
+ while(body.childNodes.length>0){
+ body.removeChild(body.childNodes[0]);
+ }
+
+ var data = this.store.get();
+ for(var i=0; i<data.length; i++){
+ var row = this.createRow(data[i]);
+ dojo.event.connect(row, "onclick", this, "onSelect");
+ body.appendChild(row);
+ idx++;
+ }
+ }
+
+ // add empty rows
+ if(this.minRows > 0 && idx < this.minRows){
+ idx = this.minRows - idx;
+ for(var i=0; i<idx; i++){
+ row=document.createElement("tr");
+ row.setAttribute("emptyRow","true");
+ for(var j=0; j<this.columns.length; j++){
+ cell=document.createElement("td");
+ cell.innerHTML=" ";
+ row.appendChild(cell);
+ }
+ body.appendChild(row);
+ }
+ }
+
+ // last but not least, show any columns that have sorting already on them.
+ var row=this.domNode.getElementsByTagName("thead")[0].rows[0];
+ var cellTag="td";
+ if(row.getElementsByTagName(cellTag).length==0) cellTag="th";
+ var headers=row.getElementsByTagName(cellTag);
+ for(var i=0; i<headers.length; i++){
+ dojo.html.setClass(headers[i], this.headerClass);
+ }
+ for(var i=0; i<this.sortInformation.length; i++){
+ var idx=this.sortInformation[i].index;
+ var dir=(~this.sortInformation[i].direction)&1;
+ dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass);
+ }
+
+ this.isInitialized=true;
+ return this.isInitialized;
+ },
+ render: function(){
+ // summary
+ // Renders the actual table data.
+
+ /* The method that should be called once underlying changes
+ * are made, including sorting, filtering, data changes.
+ * Rendering the selections themselves are a different method,
+ * which render() will call as the last step.
+ ****************************************************************/
+ if(!this.isInitialized){
+ var b = this.init();
+ if(!b){
+ this.prefill();
+ return;
+ }
+ }
+
+ // do the sort
+ var rows=[];
+ var body=this.domNode.tBodies[0];
+ var emptyRowIdx=-1;
+ for(var i=0; i<body.rows.length; i++){
+ rows.push(body.rows[i]);
+ }
+
+ // build the sorting function, and do the sorting.
+ var sortFunction = this.createSorter(this.sortInformation);
+ if(sortFunction){
+ rows.sort(sortFunction);
+ }
+
+ // append the rows without killing them, this should help with the HTML problems.
+ for(var i=0; i<rows.length; i++){
+ if(this.alternateRows){
+ dojo.html[((i%2==1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass);
+ }
+ dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass);
+ body.appendChild(rows[i]);
+ }
+ },
+ renderSelections: function(){
+ // summary
+ // Render all selected objects using CSS.
+ var body=this.domNode.tBodies[0];
+ for(var i=0; i<body.rows.length; i++){
+ dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass);
+ }
+ },
+
+ // widget lifetime handlers
+ initialize: function(){
+ // summary
+ // Initializes the widget.
+ var self=this;
+ // connect up binding listeners here.
+ dojo.event.connect(this.store, "onSetData", function(){
+ self.store.forEach(function(element){
+ element.isSelected = false;
+ });
+ self.isInitialized=false;
+ var body = self.domNode.tBodies[0];
+ if(body){
+ while(body.childNodes.length>0){
+ body.removeChild(body.childNodes[0]);
+ }
+ }
+ self.render();
+ });
+ dojo.event.connect(this.store, "onClearData", function(){
+ self.render();
+ });
+ dojo.event.connect(this.store, "onAddData", function(addedObject){
+ var row=self.createRow(addedObject);
+ dojo.event.connect(row, "onclick", self, "onSelect");
+ self.domNode.tBodies[0].appendChild(row);
+ self.render();
+ });
+ dojo.event.connect(this.store, "onAddDataRange", function(arr){
+ for(var i=0; i<arr.length; i++){
+ arr[i].isSelected=false;
+ var row=self.createRow(arr[i]);
+ dojo.event.connect(row, "onclick", self, "onSelect");
+ self.domNode.tBodies[0].appendChild(row);
+ };
+ self.render();
+ });
+ dojo.event.connect(this.store, "onRemoveData", function(removedObject){
+ var rows = self.domNode.tBodies[0].rows;
+ for(var i=0; i<rows.length; i++){
+ if(self.getDataByRow(rows[i]) == removedObject.src){
+ rows[i].parentNode.removeChild(rows[i]);
+ break;
+ }
+ }
+ self.render();
+ });
+ dojo.event.connect(this.store, "onUpdateField", function(obj, fieldPath, val){
+ var row = self.getRow(obj);
+ var idx = self.getColumnIndex(fieldPath);
+ if(row && row.cells[idx] && self.columns[idx]){
+ self.fillCell(row.cells[idx], self.columns[idx], val);
+ }
+ });
+ },
+ postCreate: function(){
+ // summary
+ // finish widget initialization.
+ this.store.keyField = this.valueField;
+
+ if(this.domNode){
+ // start by making sure domNode is a table element;
+ if(this.domNode.nodeName.toLowerCase() != "table"){
+ }
+
+ // see if there is columns set up already
+ if(this.domNode.getElementsByTagName("thead")[0]){
+ var head=this.domNode.getElementsByTagName("thead")[0];
+ if(this.headClass.length > 0){
+ head.className = this.headClass;
+ }
+ dojo.html.disableSelection(this.domNode);
+ this.parseMetadata(head);
+
+ var header="td";
+ if(head.getElementsByTagName(header).length==0){
+ header="th";
+ }
+ var headers = head.getElementsByTagName(header);
+ for(var i=0; i<headers.length; i++){
+ if(!this.columns[i].noSort){
+ dojo.event.connect(headers[i], "onclick", this, "onSort");
+ }
+ }
+ } else {
+ this.domNode.appendChild(document.createElement("thead"));
+ }
+
+ // if the table doesn't have a tbody already, add one and grab a reference to it
+ if (this.domNode.tBodies.length < 1) {
+ var body = document.createElement("tbody");
+ this.domNode.appendChild(body);
+ } else {
+ var body = this.domNode.tBodies[0];
+ }
+
+ if (this.tbodyClass.length > 0){
+ body.className = this.tbodyClass;
+ }
+ this.parseData(body);
+ }
+ }
+});
Propchange: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FilteringTable.js
------------------------------------------------------------------------------
svn:eol-style = native
Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FisheyeList.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FisheyeList.js?view=diff&rev=474551&r1=474550&r2=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FisheyeList.js (original)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FisheyeList.js Mon Nov 13 14:54:45 2006
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2004-2005, The Dojo Foundation
+ Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
@@ -9,8 +9,6 @@
*/
dojo.provide("dojo.widget.FisheyeList");
-dojo.provide("dojo.widget.html.FisheyeList");
-dojo.provide("dojo.widget.html.FisheyeListItem");
//
// TODO
@@ -20,76 +18,114 @@
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
-dojo.require("dojo.widget.Container");
-dojo.require("dojo.dom");
-dojo.require("dojo.html");
-dojo.require("dojo.style");
-dojo.require("dojo.event");
-
-dojo.widget.tags.addParseTreeHandler("dojo:FisheyeList");
-dojo.widget.tags.addParseTreeHandler("dojo:FisheyeListItem");
-
-dojo.widget.html.FisheyeList = function(){
- dojo.widget.html.Container.call(this);
-}
-dojo.inherits(dojo.widget.html.FisheyeList, dojo.widget.html.Container);
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.html.util");
+dojo.require("dojo.event.*");
+
+/*
+ * summary
+ * Menu similar to the fish eye menu on the Mac OS
+ * usage
+ * <div dojoType="FisheyeList"
+ * itemWidth="40" itemHeight="40"
+ * itemMaxWidth="150" itemMaxHeight="150"
+ * orientation="horizontal"
+ * effectUnits="2"
+ * itemPadding="10"
+ * attachEdge="center"
+ * labelEdge="bottom">
+ *
+ * <div dojoType="FisheyeListItem"
+ * id="item1"
+ * onclick="alert('click on' + this.caption + '(from widget id ' + this.widgetId + ')!');"
+ * caption="Item 1"
+ * iconsrc="images/fisheye_1.png">
+ * </div>
+ * ...
+ * </div>
+ */
+dojo.widget.defineWidget(
+ "dojo.widget.FisheyeList",
+ dojo.widget.HtmlWidget,
+function(){
+ this.pos = {x: -1, y: -1}; // current cursor position, relative to the grid
-dojo.lang.extend(dojo.widget.html.FisheyeList, {
-
- templateString: '<div class="dojoHtmlFisheyeListBar"></div>',
- templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlFisheyeList.css"),
- widgetType: "FisheyeList",
-
- EDGE: {
+ this.EDGE = {
CENTER: 0,
LEFT: 1,
RIGHT: 2,
TOP: 3,
BOTTOM: 4
- },
-
- snarfChildDomOutput: true,
-
- pos: {x: -1, y: -1}, // current cursor position, relative to the grid
+ };
// for conservative trigger mode, when triggered, timerScale is gradually increased from 0 to 1
- timerScale: 1.0,
+ this.timerScale = 1.0;
- /////////////////////////////////////////////////////////////////
- //
- // i spy OPTIONS!!!!
- //
+},
+{
+ templateString: '<div class="dojoHtmlFisheyeListBar"></div>',
+ templateCssPath: dojo.uri.dojoUri("src/widget/templates/FisheyeList.css"),
+
+ isContainer: true,
+ snarfChildDomOutput: true,
+ // Integer
+ // width of menu item (in pixels) in it's dormant state (when the mouse is far away)
itemWidth: 40,
+
+ // Integer
+ // height of menu item (in pixels) in it's dormant state (when the mouse is far away)
itemHeight: 40,
+ // Integer
+ // width of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
itemMaxWidth: 150,
+
+ // Integer
+ // height of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
itemMaxHeight: 150,
+
+ // String
+ // orientation of the menu, either "horizontal" or "vertical"
orientation: 'horizontal',
-
- conservativeTrigger: false, // don't active menu until mouse is over an image (macintosh style)
+ // Boolean
+ // if true, don't start enlarging menu items until mouse is over an image;
+ // if false, start enlarging menu items as the mouse moves near them.
+ conservativeTrigger: false,
+
+ // Number
+ // controls how much reaction the menu makes, relative to the distance of the mouse from the menu
effectUnits: 2,
+
+ // Integer
+ // padding (in pixels) betweeen each menu item
itemPadding: 10,
+ // String
+ // controls the border that the menu items don't expand past;
+ // for example, if set to "top", then the menu items will drop downwards as they expand.
+ // values
+ // "center", "left", "right", "top", "bottom".
attachEdge: 'center',
+
+ // String
+ // controls were the labels show up in relation to the menu item icons
+ // values
+ // "center", "left", "right", "top", "bottom".
labelEdge: 'bottom',
+ // Boolean
+ // for browsers that support svg, use the svg image (specified in FisheyeListIem.svgSrc)
+ // rather than the iconSrc image attribute
enableCrappySvgSupport: false,
-
- //
- //
- //
- /////////////////////////////////////////////////////////////////
-
- fillInTemplate: function(args, frag) {
- //dojo.debug(this.orientation);
-
+ fillInTemplate: function() {
dojo.html.disableSelection(this.domNode);
- this.isHorizontal = (this.orientation == 'horizontal') ? 1 : 0;
+ this.isHorizontal = (this.orientation == 'horizontal');
this.selectedNode = -1;
this.isOver = false;
@@ -101,9 +137,8 @@
//
// only some edges make sense...
//
-
- this.anchorEdge = this.toEdge(this.attachEdge, this.EDGE.CENTER);
- this.labelEdge = this.toEdge(this.labelEdge, this.EDGE.TOP);
+ this.anchorEdge = this._toEdge(this.attachEdge, this.EDGE.CENTER);
+ this.labelEdge = this._toEdge(this.labelEdge, this.EDGE.TOP);
if ( this.isHorizontal && (this.anchorEdge == this.EDGE.LEFT )){ this.anchorEdge = this.EDGE.CENTER; }
if ( this.isHorizontal && (this.anchorEdge == this.EDGE.RIGHT )){ this.anchorEdge = this.EDGE.CENTER; }
@@ -116,11 +151,9 @@
if (!this.isHorizontal && (this.labelEdge == this.EDGE.TOP )){ this.labelEdge = this.EDGE.LEFT; }
if (!this.isHorizontal && (this.labelEdge == this.EDGE.BOTTOM)){ this.labelEdge = this.EDGE.LEFT; }
-
//
// figure out the proximity size
//
-
this.proximityLeft = this.itemWidth * (this.effectUnits - 0.5);
this.proximityRight = this.itemWidth * (this.effectUnits - 0.5);
this.proximityTop = this.itemHeight * (this.effectUnits - 0.5);
@@ -146,8 +179,22 @@
}
},
- postCreate: function(args, frag) {
+ postCreate: function() {
+ this._initializePositioning();
+
+ //
+ // in liberal trigger mode, activate menu whenever mouse is close
+ //
+ if( !this.conservativeTrigger ){
+ dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
+ }
+
+ // Deactivate the menu if mouse is moved off screen (doesn't work for FF?)
+ dojo.event.connect(document.documentElement, "onmouseout", this, "_onBodyOut");
+ dojo.event.connect(this, "addChild", this, "_initializePositioning");
+ },
+ _initializePositioning: function(){
this.itemCount = this.children.length;
this.barWidth = (this.isHorizontal ? this.itemCount : 1) * this.itemWidth;
@@ -159,7 +206,6 @@
//
// calculate effect ranges for each item
//
-
for (var i=0; i<this.children.length; i++){
this.children[i].posX = this.itemWidth * (this.isHorizontal ? i : 0);
@@ -187,15 +233,12 @@
//dojo.debug('effect range for '+i+' is '+range_lhs+'/'+range_rhs);
}
-
//
// create the bar
//
-
this.domNode.style.width = this.barWidth + 'px';
this.domNode.style.height = this.barHeight + 'px';
-
//
// position the items
//
@@ -227,88 +270,78 @@
//
// calc the grid
//
-
- this.calcHitGrid();
-
- //
- // in liberal trigger mode, activate menu whenever mouse is close
- //
- if( !this.conservativeTrigger ){
- dojo.event.connect(document.documentElement, "onmousemove", this, "mouseHandler");
- }
-
- // Deactivate the menu if mouse is moved off screen (doesn't work for FF?)
- dojo.event.connect(document.documentElement, "onmouseout", this, "onBodyOut");
+ this._calcHitGrid();
},
- onBodyOut: function(e){
+ _onBodyOut: function(/*Event*/ e){
// clicking over an object inside of body causes this event to fire; ignore that case
- if( dojo.html.overElement(dojo.html.body(), e) ){
+ if( dojo.html.overElement(dojo.body(), e) ){
return;
}
- this.setDormant(e);
+ this._setDormant(e);
},
- // when mouse moves out of menu's range
- setDormant: function(e){
+ _setDormant: function(/*Event*/ e){
+ // summary: called when mouse moves out of menu's range
+
if( !this.isOver ){ return; } // already dormant?
this.isOver = false;
if ( this.conservativeTrigger ) {
// user can't re-trigger the menu expansion
// until he mouses over a icon again
- dojo.event.disconnect(document.documentElement, "onmousemove", this, "mouseHandler");
+ dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
}
- this.onGridMouseMove(-1, -1);
+ this._onGridMouseMove(-1, -1);
},
- // when mouse is moved into menu's range
- setActive: function(e){
+ _setActive: function(/*Event*/ e){
+ // summary: called when mouse is moved into menu's range
+
if( this.isOver ){ return; } // already activated?
this.isOver = true;
if ( this.conservativeTrigger ) {
// switch event handlers so that we handle mouse events from anywhere near
// the menu
- dojo.event.connect(document.documentElement, "onmousemove", this, "mouseHandler");
+ dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
this.timerScale=0.0;
// call mouse handler to do some initial necessary calculations/positioning
- this.mouseHandler(e);
+ this._onMouseMove(e);
// slowly expand the icon size so it isn't jumpy
- this.expandSlowly();
+ this._expandSlowly();
}
},
- // when mouse is moved
- mouseHandler: function(e) {
- var p = this.getCursorPos(e);
-
- if ((p.x >= this.hitX1) && (p.x <= this.hitX2) &&
- (p.y >= this.hitY1) && (p.y <= this.hitY2)){
+ _onMouseMove: function(/*Event*/ e) {
+ // summary: called when mouse is moved
+ if ((e.pageX >= this.hitX1) && (e.pageX <= this.hitX2) &&
+ (e.pageY >= this.hitY1) && (e.pageY <= this.hitY2)){
if( !this.isOver ){
- this.setActive(e);
+ this._setActive(e);
}
- this.onGridMouseMove(p.x-this.hitX1, p.y-this.hitY1);
+ this._onGridMouseMove(e.pageX-this.hitX1, e.pageY-this.hitY1);
}else{
if (this.isOver){
- this.setDormant(e);
+ this._setDormant(e);
}
}
},
onResized: function() {
- this.calcHitGrid();
+ this._calcHitGrid();
},
- onGridMouseMove: function(x, y){
+ _onGridMouseMove: function(x, y){
+ // summary: called when mouse is moved in the vicinity of the menu
this.pos = {x:x, y:y};
- this.paint();
+ this._paint();
},
- paint: function(){
+ _paint: function(){
var x=this.pos.x;
var y=this.pos.y;
@@ -317,7 +350,6 @@
//
// figure out our main index
//
-
var pos = this.isHorizontal ? x : y;
var prx = this.isHorizontal ? this.proximityLeft : this.proximityTop;
var siz = this.isHorizontal ? this.itemWidth : this.itemHeight;
@@ -330,11 +362,9 @@
if (max_off_cen > this.effectUnits){ max_off_cen = this.effectUnits; }
-
//
// figure out our off-axis weighting
//
-
var off_weight = 0;
if (this.anchorEdge == this.EDGE.BOTTOM){
@@ -354,7 +384,6 @@
off_weight = (cen2 < 0.5) ? 1 : (this.totalWidth - x) / (this.proximityRight + (this.itemWidth / 2));
}
if (this.anchorEdge == this.EDGE.CENTER){
-
if (this.isHorizontal){
off_weight = y / (this.totalHeight);
}else{
@@ -368,18 +397,13 @@
off_weight *= 2;
}
-
//
// set the sizes
//
-
for(var i=0; i<this.itemCount; i++){
-
- var weight = this.weightAt(cen, i);
-
+ var weight = this._weighAt(cen, i);
if (weight < 0){weight = 0;}
-
- this.setitemsize(i, weight * off_weight);
+ this._setItemSize(i, weight * off_weight);
}
//
@@ -401,40 +425,16 @@
offset = (cen - main_p) * ((this.isHorizontal ? this.itemWidth : this.itemHeight) - this.children[main_p].sizeMain);
}
- this.positionElementsFrom(main_p, offset);
+ this._positionElementsFrom(main_p, offset);
},
- weightAt: function(cen, i){
-
+ _weighAt: function(/*Integer*/ cen, /*Integer*/ i){
var dist = Math.abs(cen - i);
-
var limit = ((cen - i) > 0) ? this.children[i].effectRangeRght : this.children[i].effectRangeLeft;
-
- return (dist > limit) ? 0 : (1 - dist / limit);
- },
-
- positionFromNode: function(p, w){
-
- //
- // we need to grow all the nodes growing out from node 'i'
- //
-
- this.setitemsize(p, w);
-
- var wx = w;
- for(var i=p; i<this.itemCount; i++){
- wx = 0.8 * wx;
- this.setitemsize(i, wx);
- }
-
- var wx = w;
- for(var i=p; i>=0; i--){
- wx = 0.8 * wx;
- this.setitemsize(i, wx);
- }
+ return (dist > limit) ? 0 : (1 - dist / limit); // Integer
},
- setitemsize: function(p, scale){
+ _setItemSize: function(p, scale){
scale *= this.timerScale;
var w = Math.round(this.itemWidth + ((this.itemMaxWidth - this.itemWidth ) * scale));
var h = Math.round(this.itemHeight + ((this.itemMaxHeight - this.itemHeight) * scale));
@@ -448,24 +448,16 @@
this.children[p].sizeOff = h;
var y = 0;
-
if (this.anchorEdge == this.EDGE.TOP){
-
y = (this.children[p].cenY - (this.itemHeight / 2));
-
}else if (this.anchorEdge == this.EDGE.BOTTOM){
-
y = (this.children[p].cenY - (h - (this.itemHeight / 2)));
-
}else{
-
y = (this.children[p].cenY - (h / 2));
}
this.children[p].usualX = Math.round(this.children[p].cenX - (w / 2));
-
this.children[p].domNode.style.top = y + 'px';
-
this.children[p].domNode.style.left = this.children[p].usualX + 'px';
}else{
@@ -477,16 +469,11 @@
this.children[p].sizeMain = h;
var x = 0;
-
if (this.anchorEdge == this.EDGE.LEFT){
-
x = this.children[p].cenX - (this.itemWidth / 2);
-
}else if (this.anchorEdge == this.EDGE.RIGHT){
-
x = this.children[p].cenX - (w - (this.itemWidth / 2));
}else{
-
x = this.children[p].cenX - (w / 2);
}
@@ -504,7 +491,7 @@
}
},
- positionElementsFrom: function(p, offset){
+ _positionElementsFrom: function(p, offset){
var pos = 0;
@@ -515,17 +502,14 @@
pos = Math.round(this.children[p].usualY + offset);
this.children[p].domNode.style.top = pos + 'px';
}
- this.positionLabel(this.children[p]);
+ this._positionLabel(this.children[p]);
//
// position before
//
-
var bpos = pos;
-
for(var i=p-1; i>=0; i--){
-
bpos -= this.children[i].sizeMain;
if (this.isHorizontal){
@@ -533,17 +517,14 @@
}else{
this.children[i].domNode.style.top = bpos + 'px';
}
- this.positionLabel(this.children[i]);
+ this._positionLabel(this.children[i]);
}
//
// position after
//
-
var apos = pos;
-
for(var i=p+1; i<this.itemCount; i++){
-
apos += this.children[i-1].sizeMain;
if (this.isHorizontal){
@@ -551,53 +532,45 @@
}else{
this.children[i].domNode.style.top = apos + 'px';
}
- this.positionLabel(this.children[i]);
+ this._positionLabel(this.children[i]);
}
},
- positionLabel: function(itm){
+ _positionLabel: function(itm){
var x = 0;
var y = 0;
- var labelW = dojo.style.getOuterWidth(itm.lblNode);
- var labelH = dojo.style.getOuterHeight(itm.lblNode);
+ var mb = dojo.html.getMarginBox(itm.lblNode);
if (this.labelEdge == this.EDGE.TOP){
- x = Math.round((itm.sizeW / 2) - (labelW / 2));
- y = -labelH;
+ x = Math.round((itm.sizeW / 2) - (mb.width / 2));
+ y = -mb.height;
}
if (this.labelEdge == this.EDGE.BOTTOM){
- x = Math.round((itm.sizeW / 2) - (labelW / 2));
+ x = Math.round((itm.sizeW / 2) - (mb.width / 2));
y = itm.sizeH;
}
if (this.labelEdge == this.EDGE.LEFT){
- x = -labelW;
- y = Math.round((itm.sizeH / 2) - (labelH / 2));
+ x = -mb.width;
+ y = Math.round((itm.sizeH / 2) - (mb.height / 2));
}
if (this.labelEdge == this.EDGE.RIGHT){
x = itm.sizeW;
- y = Math.round((itm.sizeH / 2) - (labelH / 2));
+ y = Math.round((itm.sizeH / 2) - (mb.height / 2));
}
itm.lblNode.style.left = x + 'px';
itm.lblNode.style.top = y + 'px';
},
- getCursorPos: function(e){
- return {
- 'x': e.pageX || e.clientX + dojo.html.body().scrollLeft,
- 'y': e.pageY || e.clientY + dojo.html.body().scrollTop
- };
- },
-
- calcHitGrid: function(){
+ _calcHitGrid: function(){
- var pos = dojo.style.getAbsolutePosition(this.domNode);
+ var pos = dojo.html.getAbsolutePosition(this.domNode, true);
this.hitX1 = pos.x - this.proximityLeft;
this.hitY1 = pos.y - this.proximityTop;
@@ -607,36 +580,54 @@
//dojo.debug(this.hitX1+','+this.hitY1+' // '+this.hitX2+','+this.hitY2);
},
- toEdge: function(inp, def){
+ _toEdge: function(inp, def){
return this.EDGE[inp.toUpperCase()] || def;
},
- // slowly expand the image to user specified max size
- expandSlowly: function(){
+ _expandSlowly: function(){
+ // summary: slowly expand the image to user specified max size
if( !this.isOver ){ return; }
this.timerScale += 0.2;
- this.paint();
+ this._paint();
if ( this.timerScale<1.0 ) {
- dojo.lang.setTimeout(this, "expandSlowly", 10);
+ dojo.lang.setTimeout(this, "_expandSlowly", 10);
}
- }
+ },
+ destroy: function(){
+ // need to disconnect when we destroy
+ dojo.event.disconnect(document.documentElement, "onmouseout", this, "_onBodyOut");
+ dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
+ dojo.widget.FisheyeList.superclass.destroy.call(this);
+ }
});
-dojo.widget.html.FisheyeListItem = function(){
- dojo.widget.HtmlWidget.call(this);
-}
-dojo.inherits(dojo.widget.html.FisheyeListItem, dojo.widget.HtmlWidget);
-
-dojo.lang.extend(dojo.widget.html.FisheyeListItem, {
- widgetType: "FisheyeListItem",
-
- // Constructor arguments
+/*
+ * summary
+ * Menu item inside of a FisheyeList.
+ * See FisheyeList documentation for details on usage.
+ */
+dojo.widget.defineWidget(
+ "dojo.widget.FisheyeListItem",
+ dojo.widget.HtmlWidget,
+{
+ // String
+ // pathname to image file (jpg, gif, png, etc.) of icon for this menu item
iconSrc: "",
+
+ // String
+ // pathname to svg file of icon for this menu item
svgSrc: "",
+
+ // String
+ // label to print next to the icon, when it is moused-over
caption: "",
- blankImgPath: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
+ // String
+ // will be set to the id of the orginal div element
+ id: "",
+
+ _blankImgPath: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
templateString:
'<div class="dojoHtmlFisheyeListItem">' +
@@ -644,8 +635,6 @@
' <div class="dojoHtmlFisheyeListItemLabel" dojoAttachPoint="lblNode"></div>' +
'</div>',
- imgNode: null,
-
fillInTemplate: function() {
//
// set image
@@ -653,13 +642,22 @@
// this.parent.enableCrappySvgSupport is not available to this function
//
if (this.svgSrc != ""){
- this.svgNode = this.createSvgNode(this.svgSrc);
+ this.svgNode = this._createSvgNode(this.svgSrc);
this.domNode.appendChild(this.svgNode);
this.imgNode.style.display = 'none';
- } else if((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4)==".png")&&(dojo.render.html.ie)){
+ } else if((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4)==".png")&&(dojo.render.html.ie)&&(!dojo.render.html.ie70)){
+ /* we set the id of the new fisheyeListItem to the id of the div defined in the HTML */
+ if (dojo.dom.hasParent(this.imgNode) && this.id != ""){
+ var parent = this.imgNode.parentNode;
+ parent.setAttribute("id", this.id);
+ }
this.imgNode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='scale')";
- this.imgNode.src = this.blankImgPath.toString();
+ this.imgNode.src = this._blankImgPath.toString();
} else {
+ if (dojo.dom.hasParent(this.imgNode) && this.id != ""){
+ var parent = this.imgNode.parentNode;
+ parent.setAttribute("id", this.id);
+ }
this.imgNode.src = this.iconSrc;
}
@@ -672,8 +670,7 @@
dojo.html.disableSelection(this.domNode);
},
- createSvgNode: function(src){
-
+ _createSvgNode: function(src){
var elm = document.createElement('embed');
elm.src = src;
elm.type = 'image/svg+xml';
@@ -721,22 +718,25 @@
return elm;
},
- onMouseOver: function(e) {
+ onMouseOver: function(/*Event*/ e) {
+ // summary: callback when user moves mouse over this menu item
// in conservative mode, don't activate the menu until user mouses over an icon
if( !this.parent.isOver ){
- this.parent.setActive(e);
+ this.parent._setActive(e);
}
if ( this.caption != "" ) {
dojo.html.addClass(this.lblNode, "selected");
- this.parent.positionLabel(this);
+ this.parent._positionLabel(this);
}
},
- onMouseOut: function() {
+ onMouseOut: function(/*Event*/ e) {
+ // summary: callback when user moves mouse off of this menu item
dojo.html.removeClass(this.lblNode, "selected");
},
- onClick: function() {
+ onClick: function(/*Event*/ e) {
+ // summary: user overridable callback when user clicks this menu item
}
});
Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FloatingPane.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FloatingPane.js?view=diff&rev=474551&r1=474550&r2=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FloatingPane.js (original)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/FloatingPane.js Mon Nov 13 14:54:45 2006
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2004-2005, The Dojo Foundation
+ Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
@@ -8,521 +8,434 @@
http://dojotoolkit.org/community/licensing.shtml
*/
-dojo.provide("dojo.widget.FloatingPane");
-dojo.provide("dojo.widget.html.FloatingPane");
-
-//
-// this widget provides a window-like floating pane
-//
-
-dojo.require("dojo.widget.*");
-dojo.require("dojo.widget.Manager");
-dojo.require("dojo.html");
-dojo.require("dojo.style");
-dojo.require("dojo.dom");
-dojo.require("dojo.widget.ContentPane");
-dojo.require("dojo.widget.LayoutPane");
-dojo.require("dojo.dnd.HtmlDragMove");
-dojo.require("dojo.dnd.HtmlDragMoveSource");
-dojo.require("dojo.dnd.HtmlDragMoveObject");
-
-dojo.widget.html.FloatingPane = function(){
- dojo.widget.html.LayoutPane.call(this);
-}
-
-dojo.inherits(dojo.widget.html.FloatingPane, dojo.widget.html.LayoutPane);
-
-dojo.lang.extend(dojo.widget.html.FloatingPane, {
- widgetType: "FloatingPane",
-
- // Constructor arguments
- title: '',
- iconSrc: '',
- hasShadow: false,
- constrainToContainer: false,
- taskBarId: "",
- resizable: true, // note: if specified, user must include ResizeHandle
- overflow: "",
-
- resizable: false,
- titleBarDisplay: "fancy",
- titleHeight: 22, // workaround to CSS loading race condition bug
-
- href: "",
- extractContent: true,
- parseContent: true,
- cacheContent: true,
-
- // FloatingPane supports 3 modes for the client area (the part below the title bar)
- // default - client area is a ContentPane, that can hold
- // either inlined data and/or data downloaded from a URL
- // layout - the client area is a layout pane
- // none - the user specifies a single widget which becomes the content pane
- contentWrapper: "default",
-
- containerNode: null,
- domNode: null,
- clientPane: null,
- dragBar: null,
-
- windowState: "normal",
- displayCloseAction: false,
-
- maxTaskBarConnectAttempts: 5,
- taskBarConnectAttempts: 0,
-
- minimizeIcon: dojo.uri.dojoUri("src/widget/templates/images/floatingPaneMinimize.gif"),
- maximizeIcon: dojo.uri.dojoUri("src/widget/templates/images/floatingPaneMaximize.gif"),
- restoreIcon: dojo.uri.dojoUri("src/widget/templates/images/floatingPaneRestore.gif"),
- closeIcon: dojo.uri.dojoUri("src/widget/templates/images/floatingPaneClose.gif"),
- titleBarBackground: dojo.uri.dojoUri("src/widget/templates/images/titlebar-bg.jpg"),
-
- shadowPng: dojo.uri.dojoUri("src/widget/templates/images/shadow"),
- shadowThickness: 8,
- shadowOffset: 15,
-
- templateString: '<div></div>',
- templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlFloatingPane.css"),
-
- initialized: false,
-
- addChild: function(child, overrideContainerNode, pos, ref, insertIndex) {
- this.clientPane.addChild(child, overrideContainerNode, pos, ref, insertIndex);
- },
-
- // make a widget container to hold all the contents of the floating pane (other than the
- // title and the resize bar at the bottom)
- _makeClientPane: function(clientDiv){
- var args = {
- layoutAlign: "client",
- id:this.widgetId+"_client",
- href: this.href,
- cacheContent: this.cacheContent,
- extractContent: this.extractContent,
- parseContent: this.parseContent
- };
- var pane = this._createPane(this.contentWrapper=="layout"?"LayoutPane":"ContentPane", clientDiv, args);
- return pane;
- },
-
- fillInTemplate: function(args, frag){
- var source = this.getFragNodeRef(frag);
-
- // Copy style info and id from input node to output node
- this.domNode.style.cssText = source.style.cssText;
- dojo.html.addClass(this.domNode, dojo.html.getClass(source));
- dojo.html.addClass(this.domNode, "dojoFloatingPane");
- this.domNode.style.position="absolute";
- this.domNode.id = source.id;
- if(dojo.render.html.safari){
- dojo.html.body().appendChild(this.domNode);
- }
-
- // make client pane wrapper to hold the contents of this floating pane
- if(this.contentWrapper!="none"){
- var clientDiv = document.createElement('div');
- dojo.dom.moveChildren(source, clientDiv, 0);
- this.clientPane = this._makeClientPane(clientDiv);
- }
-
- if (this.titleBarDisplay != "none") {
- // this is our chrome
- var chromeDiv = document.createElement('div');
- dojo.html.addClass(chromeDiv, 'dojoFloatingPaneDragbar');
- chromeDiv.style.height=this.titleHeight+"px"; // workaround CSS loading race condition bug
-
- this.dragBar = this._createPane("LayoutPane", chromeDiv, {layoutAlign: 'top', id:this.widgetId+"_chrome"});
- dojo.html.disableSelection(this.dragBar.domNode);
-
- if( this.titleBarDisplay == "fancy"){
- // image background to get gradient
- var img = document.createElement('img');
- img.src = this.titleBarBackground;
- dojo.html.addClass(img, 'dojoFloatingPaneDragbarBackground');
- var backgroundPane = dojo.widget.createWidget("ContentPane", {layoutAlign:"flood", id:this.widgetId+"_titleBackground"}, img);
- this.dragBar.addChild(backgroundPane);
- }
-
- //Title Bar
- var titleBar = document.createElement('div');
- dojo.html.addClass(titleBar, "dojoFloatingPaneTitleBar");
- dojo.html.disableSelection(titleBar);
-
- //TitleBarActions
- var titleBarActions = document.createElement('div');
- dojo.html.addClass(titleBarActions, "dojoFloatingPaneActions");
-
- //Title Icon
- if(this.iconSrc!=""){
- var titleIcon = document.createElement('img');
- dojo.html.addClass(titleIcon,"dojoTitleBarIcon");
- titleIcon.src = this.iconSrc;
- titleBar.appendChild(titleIcon);
- }
-
- //Title text
- var titleText = document.createTextNode(this.title)
- titleBar.appendChild(titleText);
-
- if (this.resizable) {
-
- //FloatingPane Action Minimize
- this.minimizeAction = document.createElement("img");
- dojo.html.addClass(this.minimizeAction, "dojoFloatingPaneActionItem");
- this.minimizeAction.src = this.minimizeIcon;
- titleBarActions.appendChild(this.minimizeAction);
- dojo.event.connect(this.minimizeAction, 'onclick', this, 'minimizeWindow');
-
- //FloatingPane Action Restore
- this.restoreAction = document.createElement("img");
- dojo.html.addClass(this.restoreAction, "dojoFloatingPaneActionItem");
- this.restoreAction.src = this.restoreIcon;
- titleBarActions.appendChild(this.restoreAction);
- dojo.event.connect(this.restoreAction, 'onclick', this, 'restoreWindow');
-
- if (this.windowState != "normal") {
- this.restoreAction.style.display="inline";
- } else {
- this.restoreAction.style.display="none";
- }
-
- //FloatingPane Action Maximize
- this.maximizeAction = document.createElement("img");
- dojo.html.addClass(this.maximizeAction, "dojoFloatingPaneActionItem");
- this.maximizeAction.src = this.maximizeIcon;
- titleBarActions.appendChild(this.maximizeAction);
- dojo.event.connect(this.maximizeAction, 'onclick', this, 'maximizeWindow');
-
- if (this.windowState != "maximized") {
- this.maximizeAction.style.display="inline";
- } else {
- this.maximizeAction.style.display="none";
- }
-
- }
-
- if (this.displayCloseAction) {
- //FloatingPane Action Close
- var closeAction= document.createElement("img");
- dojo.html.addClass(closeAction, "dojoFloatingPaneActionItem");
- closeAction.src = this.closeIcon;
- titleBarActions.appendChild(closeAction);
- dojo.event.connect(closeAction, 'onclick', this, 'closeWindow');
- }
-
-
- chromeDiv.appendChild(titleBar);
- chromeDiv.appendChild(titleBarActions);
- }
-
- if ( this.resizable ) {
- // add the resize handle
- var resizeDiv = document.createElement('div');
- dojo.html.addClass(resizeDiv, "dojoFloatingPaneResizebar");
- dojo.html.disableSelection(resizeDiv);
- var rh = dojo.widget.createWidget("ResizeHandle", {targetElmId: this.widgetId, id:this.widgetId+"_resize"});
- this.resizePane = this._createPane("ContentPane", resizeDiv, {layoutAlign: "bottom"});
- this.resizePane.addChild(rh);
- }
-
- // add a drop shadow
- this._makeShadow();
-
- dojo.event.connect(this.domNode, 'onmousedown', this, 'onMouseDown');
-
- // Prevent IE bleed-through problem
- this.bgIframe = new dojo.html.BackgroundIframe();
- if( this.bgIframe.iframe ){
- this.domNode.appendChild(this.bgIframe.iframe);
- }
- if ( this.isVisible() ) {
- this.bgIframe.show();
- };
-
- if( this.taskBarId ){
- this.taskBarSetup();
- }
-
- if (dojo.hostenv.post_load_) {
- this.setInitialWindowState();
- } else {
- dojo.addOnLoad(this, "setInitialWindowState");
- }
- if(dojo.render.html.safari){
- dojo.html.body().removeChild(this.domNode);
- }
-
- dojo.widget.html.FloatingPane.superclass.postCreate.call(this, args, frag);
- },
-
- postCreate: function(args, frag){
- // Make the client pane. It will either be the widget specified by the user,
- // or a wrapper widget
- if(this.contentWrapper=="none"){
- // the user has specified a single widget which will become our content
- this.clientPane = this.children[0];
- this.domNode.appendChild(this.clientPane.domNode);
- }else{
- // move our 'children' into the client pane
- // we already moved the domnodes, but now we need to move the 'children'
- var kids = this.children.concat();
- this.children = [];
-
- for(var i=0; i<kids.length; i++){
- if (kids[i].ownerPane == this){
- this.children.push(kids[i]);
- }else{
- if(this.contentWrapper=="layout"){
- this.clientPane.addChild(kids[i]);
- }else{
- this.clientPane.children.push(kids[i]);
- }
- }
- }
- }
- dojo.html.addClass(this.clientPane.domNode, 'dojoFloatingPaneClient');
- this.clientPane.layoutAlign="client";
- this.clientPane.ownerPane=this;
- if (this.overflow != "") {
- this.clientPane.domNode.style.overflow=this.overflow;
- }
-
- if (this.titleBarDisplay != "none") {
- var drag = new dojo.dnd.HtmlDragMoveSource(this.domNode);
-
- if (this.constrainToContainer) {
- drag.constrainTo();
- }
-
- drag.setDragHandle(this.dragBar.domNode);
- }
-
- this.initialized=true;
- },
-
- _makeShadow: function(){
- if ( this.hasShadow ) {
- // make all the pieces of the shadow, and position/size them as much
- // as possible (but a lot of the coordinates are set in sizeShadow
- this.shadow={};
- var x1 = -1 * this.shadowThickness;
- var y0 = this.shadowOffset;
- var y1 = this.shadowOffset + this.shadowThickness;
- this._makeShadowPiece("ul", "top", y0, "left", x1);
- this._makeShadowPiece("l", "top", y1, "left", x1, "scale");
- this._makeShadowPiece("ur", "top", y0, "left", 0);
- this._makeShadowPiece("r", "top", y1, "left", 0, "scale");
- this._makeShadowPiece("bl", "top", 0, "left", x1);
- this._makeShadowPiece("b", "top", 0, "left", 0, "crop");
- this._makeShadowPiece("br", "top", 0, "left", 0);
- }
- },
-
- _makeShadowPiece: function(name, vertAttach, vertCoord, horzAttach, horzCoord, sizing){
- var img;
- var url = this.shadowPng + name.toUpperCase() + ".png";
- if(dojo.render.html.ie){
- img=document.createElement("div");
- img.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"'"+
- (sizing?", sizingMethod='"+sizing+"'":"") + ")";
- }else{
- img=document.createElement("img");
- img.src=url;
- }
- img.style.position="absolute";
- img.style[vertAttach]=vertCoord+"px";
- img.style[horzAttach]=horzCoord+"px";
- img.style.width=this.shadowThickness+"px";
- img.style.height=this.shadowThickness+"px";
- this.shadow[name]=img;
- this.domNode.appendChild(img);
- },
-
- _sizeShadow: function(width, height){
- if ( this.shadow ) {
- var sideHeight = height - (this.shadowOffset+this.shadowThickness+1);
- this.shadow.l.style.height = sideHeight+"px";
- this.shadow.r.style.height = sideHeight+"px";
- this.shadow.b.style.width = (width-1)+"px";
- this.shadow.bl.style.top = (height-1)+"px";
- this.shadow.b.style.top = (height-1)+"px";
- this.shadow.br.style.top = (height-1)+"px";
- this.shadow.ur.style.left = (width-1)+"px";
- this.shadow.r.style.left = (width-1)+"px";
- this.shadow.br.style.left = (width-1)+"px";
- }
- },
-
- maximizeWindow: function(evt) {
- this.previousWidth= this.domNode.style.width;
- this.previousHeight= this.domNode.style.height;
- this.previousLeft = this.domNode.style.left;
- this.previousTop = this.domNode.style.top;
-
- this.domNode.style.left =
- dojo.style.getPixelValue(this.domNode.parentNode, "padding-left", true) + "px";
- this.domNode.style.top =
- dojo.style.getPixelValue(this.domNode.parentNode, "padding-top", true) + "px";
-
- if ((this.domNode.parentNode.nodeName.toLowerCase() == 'body')) {
- dojo.style.setOuterWidth(this.domNode, dojo.html.getViewportWidth()-dojo.style.getPaddingWidth(dojo.html.body()));
- dojo.style.setOuterHeight(this.domNode, dojo.html.getViewportHeight()-dojo.style.getPaddingHeight(dojo.html.body()));
- } else {
- dojo.style.setOuterWidth(this.domNode, dojo.style.getContentWidth(this.domNode.parentNode));
- dojo.style.setOuterHeight(this.domNode, dojo.style.getContentHeight(this.domNode.parentNode));
- }
- this.maximizeAction.style.display="none";
- this.restoreAction.style.display="inline";
- this.windowState="maximized";
- this.onResized();
- },
-
- minimizeWindow: function(evt) {
- this.hide();
- if (this.resizable) {
- this.maximizeAction.style.display="inline";
- this.restoreAction.style.display="inline";
- }
-
- this.windowState = "minimized";
- },
-
- restoreWindow: function(evt) {
- if (this.previousWidth && this.previousHeight && this.previousLeft && this.previousTop) {
- this.domNode.style.width = this.previousWidth;
- this.domNode.style.height = this.previousHeight;
- this.domNode.style.left = this.previousLeft;
- this.domNode.style.top = this.previousTop;
- dojo.widget.html.FloatingPane.superclass.onResized.call(this);
- }
-
- if (this.widgetState != "maximized") {
- this.show();
- }
-
- if (this.resizable) {
- this.maximizeAction.style.display="inline";
- this.restoreAction.style.display="none";
- }
-
- this.bringToTop();
- this.windowState="normal";
- },
-
- closeWindow: function(evt) {
- this.destroy();
- },
-
- onMouseDown: function(evt) {
- this.bringToTop();
- },
-
- bringToTop: function() {
- var floatingPaneStartingZ = 100;
- var floatingPanes= dojo.widget.manager.getWidgetsByType("FloatingPane");
- var windows = []
- var y=0;
- for (var x=0; x<floatingPanes.length; x++) {
- if (this.widgetId != floatingPanes[x].widgetId) {
- windows.push(floatingPanes[x]);
- }
- }
-
- windows.sort(function(a,b) {
- return a.domNode.style.zIndex - b.domNode.style.zIndex;
- });
-
- windows.push(this);
-
- for (x=0; x<windows.length;x++) {
- windows[x].domNode.style.zIndex = floatingPaneStartingZ + x;
- }
- },
-
- setInitialWindowState: function() {
- if (this.windowState == "maximized") {
- this.maximizeWindow();
- this.show();
- this.bringToTop();
- return;
- }
-
- if (this.windowState=="normal") {
- dojo.lang.setTimeout(this, this.onResized, 50);
- this.show();
- this.bringToTop();
- return;
- }
-
- if (this.windowState=="minimized") {
- this.hide();
- return;
- }
-
- this.windowState="minimized";
- },
-
- // add icon to task bar, connected to me
- taskBarSetup: function() {
- var taskbar = dojo.widget.getWidgetById(this.taskBarId);
- if (!taskbar){
- if (this.taskBarConnectAttempts < this.maxTaskBarConnectAttempts) {
- dojo.lang.setTimeout(this, this.taskBarSetup, 50);
- this.taskBarConnectAttempts++;
- } else {
- dojo.debug("Unable to connect to the taskBar");
- }
- return;
- }
- taskbar.addChild(this);
- },
-
- onResized: function(){
- if( !this.isVisible() ){ return; }
- var newHeight = dojo.style.getInnerHeight(this.domNode);
- var newWidth = dojo.style.getInnerWidth(this.domNode);
-
- //if ( newWidth != this.width || newHeight != this.height ) {
- this.width = newWidth;
- this.height = newHeight;
- this._sizeShadow(newWidth, newHeight);
- dojo.widget.html.FloatingPane.superclass.onResized.call(this);
- //}
-
- // bgIframe is a child of this.domNode, so position should be relative to [0,0]
- if(this.bgIframe){
- this.bgIframe.size([0, 0, newWidth, newHeight]);
- }
- },
-
- hide: function(){
- dojo.widget.html.FloatingPane.superclass.hide.call(this);
- if(this.bgIframe){
- this.bgIframe.hide();
- }
- },
-
- show: function(){
- dojo.widget.html.FloatingPane.superclass.show.call(this);
- if(this.bgIframe){
- this.bgIframe.show();
- }
- },
-
- _createPane: function(type, node, args){
- var pane = dojo.widget.createWidget(type, args, node);
- dojo.widget.html.FloatingPane.superclass.addChild.call(this,pane);
- pane.ownerPane=this;
- return pane;
- },
-
- setUrl: function(url){
- this.clientPane.setUrl(url);
- },
-
- setContent: function(str){
- this.clientPane.setContent(str);
- }
-});
-
-dojo.widget.tags.addParseTreeHandler("dojo:FloatingPane");
+dojo.provide("dojo.widget.FloatingPane");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Manager");
+dojo.require("dojo.html.*");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.iframe");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.lfx.shadow");
+dojo.require("dojo.widget.html.layout");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.dnd.HtmlDragMove");
+dojo.require("dojo.widget.Dialog"); // for ModalFloatingPane
+dojo.require("dojo.widget.ResizeHandle");
+
+// summary
+// Base class for FloatingPane, ModalFloatingPane
+dojo.declare(
+ "dojo.widget.FloatingPaneBase",
+ null,
+ {
+ // String
+ // text to display in floating pane's title bar (ex: "My Window")
+ title: '',
+
+ // String
+ // path of icon to display in floating pane's title bar
+ iconSrc: '',
+
+ // Boolean
+ // if true, display a shadow behind the floating pane
+ hasShadow: false,
+
+ // Boolean
+ // if true, and the floating pane is inside another container (ContentPane, another FloatingPane, etc.),
+ // then don't allow the floating pane to be dragged outside of it's container
+ constrainToContainer: false,
+
+ // String
+ // widget id of TaskBar widget;
+ // if specified, then an icon for this FloatingPane will be added to the specified TaskBar
+ taskBarId: "",
+
+ // Boolean
+ // if true, allow user to resize floating pane
+ resizable: true,
+
+ // Boolean
+ // if true, display title bar for this floating pane
+ titleBarDisplay: true,
+
+ // String
+ // control whether window is initially not displayed ("minimized"), displayed full screen ("maximized"),
+ // or just displayed normally ("normal")
+ // Values
+ // "normal", "maximized", "minimized"
+ windowState: "normal",
+
+ // Boolean
+ // display button to close window
+ displayCloseAction: false,
+
+ // Boolean
+ // display button to minimize window (ie, window disappears so only the taskbar item remains)
+ displayMinimizeAction: false,
+
+ // Boolean
+ // display button to maximize window (ie, to take up the full screen)
+ displayMaximizeAction: false,
+
+ // Related to connecting to taskbar
+ // TODO: use topics rather than repeated connect attempts?
+ _max_taskBarConnectAttempts: 5,
+ _taskBarConnectAttempts: 0,
+
+ templatePath: dojo.uri.dojoUri("src/widget/templates/FloatingPane.html"),
+ templateCssPath: dojo.uri.dojoUri("src/widget/templates/FloatingPane.css"),
+
+ fillInFloatingPaneTemplate: function(args, frag){
+ // summary: this should be called by fillInTemplate() of the widget that I'm mixed into
+
+ // Copy style info from input node to output node
+ var source = this.getFragNodeRef(frag);
+ dojo.html.copyStyle(this.domNode, source);
+
+ // necessary for safari, khtml (for computing width/height)
+ dojo.body().appendChild(this.domNode);
+
+ // if display:none then state=minimized, otherwise state=normal
+ if(!this.isShowing()){
+ this.windowState="minimized";
+ }
+
+ // <img src=""> can hang IE! better get rid of it
+ if(this.iconSrc==""){
+ dojo.html.removeNode(this.titleBarIcon);
+ }else{
+ this.titleBarIcon.src = this.iconSrc.toString();// dojo.uri.Uri obj req. toString()
+ }
+
+ if(this.titleBarDisplay){
+ this.titleBar.style.display="";
+ dojo.html.disableSelection(this.titleBar);
+
+ this.titleBarIcon.style.display = (this.iconSrc=="" ? "none" : "");
+
+ this.minimizeAction.style.display = (this.displayMinimizeAction ? "" : "none");
+ this.maximizeAction.style.display=
+ (this.displayMaximizeAction && this.windowState!="maximized" ? "" : "none");
+ this.restoreAction.style.display=
+ (this.displayMaximizeAction && this.windowState=="maximized" ? "" : "none");
+ this.closeAction.style.display= (this.displayCloseAction ? "" : "none");
+
+ this.drag = new dojo.dnd.HtmlDragMoveSource(this.domNode);
+ if (this.constrainToContainer) {
+ this.drag.constrainTo();
+ }
+ this.drag.setDragHandle(this.titleBar);
+
+ var self = this;
+
+ dojo.event.topic.subscribe("dragMove",
+ function (info){
+ if (info.source.domNode == self.domNode){
+ dojo.event.topic.publish('floatingPaneMove', { source: self } );
+ }
+ }
+ );
+ }
+
+ if(this.resizable){
+ this.resizeBar.style.display="";
+ this.resizeHandle = dojo.widget.createWidget("ResizeHandle", {targetElmId: this.widgetId, id:this.widgetId+"_resize"});
+ this.resizeBar.appendChild(this.resizeHandle.domNode);
+ }
+
+ // add a drop shadow
+ if(this.hasShadow){
+ this.shadow=new dojo.lfx.shadow(this.domNode);
+ }
+
+ // Prevent IE bleed-through problem
+ this.bgIframe = new dojo.html.BackgroundIframe(this.domNode);
+
+ if( this.taskBarId ){
+ this._taskBarSetup();
+ }
+
+ // counteract body.appendChild above
+ dojo.body().removeChild(this.domNode);
+ },
+
+ postCreate: function(){
+ if (dojo.hostenv.post_load_) {
+ this._setInitialWindowState();
+ } else {
+ dojo.addOnLoad(this, "_setInitialWindowState");
+ }
+ },
+
+ maximizeWindow: function(/*Event*/ evt) {
+ // summary: maximize the window
+ var mb = dojo.html.getMarginBox(this.domNode);
+ this.previous={
+ width: mb.width || this.width,
+ height: mb.height || this.height,
+ left: this.domNode.style.left,
+ top: this.domNode.style.top,
+ bottom: this.domNode.style.bottom,
+ right: this.domNode.style.right
+ };
+ if(this.domNode.parentNode.style.overflow.toLowerCase() != 'hidden'){
+ this.parentPrevious={
+ overflow: this.domNode.parentNode.style.overflow
+ };
+ dojo.debug(this.domNode.parentNode.style.overflow);
+ this.domNode.parentNode.style.overflow = 'hidden';
+ }
+
+ this.domNode.style.left =
+ dojo.html.getPixelValue(this.domNode.parentNode, "padding-left", true) + "px";
+ this.domNode.style.top =
+ dojo.html.getPixelValue(this.domNode.parentNode, "padding-top", true) + "px";
+
+ if ((this.domNode.parentNode.nodeName.toLowerCase() == 'body')) {
+ var viewport = dojo.html.getViewport();
+ var padding = dojo.html.getPadding(dojo.body());
+ this.resizeTo(viewport.width-padding.width, viewport.height-padding.height);
+ } else {
+ var content = dojo.html.getContentBox(this.domNode.parentNode);
+ this.resizeTo(content.width, content.height);
+ }
+ this.maximizeAction.style.display="none";
+ this.restoreAction.style.display="";
+
+ //disable resize and drag
+ if(this.resizeHandle){
+ this.resizeHandle.domNode.style.display="none";
+ }
+ this.drag.setDragHandle(null);
+
+ this.windowState="maximized";
+ },
+
+ minimizeWindow: function(/*Event*/ evt) {
+ // summary: hide the window so that only the icon in the taskbar is shown
+ this.hide();
+ for(var attr in this.parentPrevious){
+ this.domNode.parentNode.style[attr] = this.parentPrevious[attr];
+ }
+ this.lastWindowState = this.windowState;
+ this.windowState = "minimized";
+ },
+
+ restoreWindow: function(/*Event*/ evt) {
+ // summary: set the winow to normal size (neither maximized nor minimized)
+ if (this.windowState=="minimized") {
+ this.show();
+ if(this.lastWindowState == "maximized"){
+ this.domNode.parentNode.style.overflow = 'hidden';
+ this.windowState="maximized";
+ }else{ //normal
+ this.windowState="normal";
+ }
+ } else if (this.windowState=="maximized"){
+ for(var attr in this.previous){
+ this.domNode.style[attr] = this.previous[attr];
+ }
+ for(var attr in this.parentPrevious){
+ this.domNode.parentNode.style[attr] = this.parentPrevious[attr];
+ }
+ this.resizeTo(this.previous.width, this.previous.height);
+ this.previous=null;
+ this.parentPrevious=null;
+
+ this.restoreAction.style.display="none";
+ this.maximizeAction.style.display=this.displayMaximizeAction ? "" : "none";
+
+ if(this.resizeHandle){
+ this.resizeHandle.domNode.style.display="";
+ }
+ this.drag.setDragHandle(this.titleBar);
+ this.windowState="normal";
+ } else { //normal
+ // do nothing
+ }
+ },
+
+ toggleDisplay: function(){
+ // summary: switch between hidden mode and displayed mode (either maximized or normal, depending on state before window was minimized)
+ if(this.windowState=="minimized"){
+ this.restoreWindow();
+ }else{
+ this.minimizeWindow();
+ }
+ },
+
+ closeWindow: function(/*Event*/ evt) {
+ // summary: destroy this window
+ dojo.html.removeNode(this.domNode);
+ this.destroy();
+ },
+
+ onMouseDown: function(/*Event*/ evt) {
+ // summary: callback when user clicks anywhere on the floating pane
+ this.bringToTop();
+ },
+
+ bringToTop: function() {
+ // summary
+ // all the floating panes are stacked in z-index order; bring this floating pane to the top of that stack,
+ // so that it's displayed in front of all the other floating panes
+ var floatingPanes= dojo.widget.manager.getWidgetsByType(this.widgetType);
+ var windows = [];
+ for (var x=0; x<floatingPanes.length; x++) {
+ if (this.widgetId != floatingPanes[x].widgetId) {
+ windows.push(floatingPanes[x]);
+ }
+ }
+
+ windows.sort(function(a,b) {
+ return a.domNode.style.zIndex - b.domNode.style.zIndex;
+ });
+
+ windows.push(this);
+
+ var floatingPaneStartingZ = 100;
+ for (x=0; x<windows.length;x++) {
+ windows[x].domNode.style.zIndex = floatingPaneStartingZ + x*2;
+ }
+ },
+
+ _setInitialWindowState: function() {
+ if(this.isShowing()){
+ this.width=-1; // force resize
+ var mb = dojo.html.getMarginBox(this.domNode);
+ this.resizeTo(mb.width, mb.height);
+ }
+ if (this.windowState == "maximized") {
+ this.maximizeWindow();
+ this.show();
+ return;
+ }
+
+ if (this.windowState=="normal") {
+ this.show();
+ return;
+ }
+
+ if (this.windowState=="minimized") {
+ this.hide();
+ return;
+ }
+
+ this.windowState="minimized";
+ },
+
+ _taskBarSetup: function() {
+ // summary: add icon to task bar, connected to me
+ var taskbar = dojo.widget.getWidgetById(this.taskBarId);
+ if (!taskbar){
+ if (this._taskBarConnectAttempts < this._max_taskBarConnectAttempts) {
+ dojo.lang.setTimeout(this, this._taskBarSetup, 50);
+ this._taskBarConnectAttempts++;
+ } else {
+ dojo.debug("Unable to connect to the taskBar");
+ }
+ return;
+ }
+ taskbar.addChild(this);
+ },
+
+ showFloatingPane: function(){
+ // summary:
+ // bring this floating pane to the top
+ this.bringToTop();
+ },
+
+ onFloatingPaneShow: function(){
+ // summary: callback for when someone calls FloatingPane.show
+ var mb = dojo.html.getMarginBox(this.domNode);
+ this.resizeTo(mb.width, mb.height);
+ },
+
+ // summary: set the floating pane to the given size
+ resizeTo: function(/*Integer*/ width, /*Integer*/ height){
+ dojo.html.setMarginBox(this.domNode, { width: width, height: height });
+
+ dojo.widget.html.layout(this.domNode,
+ [
+ {domNode: this.titleBar, layoutAlign: "top"},
+ {domNode: this.resizeBar, layoutAlign: "bottom"},
+ {domNode: this.containerNode, layoutAlign: "client"}
+ ] );
+
+ // If any of the children have layoutAlign specified, obey it
+ dojo.widget.html.layout(this.containerNode, this.children, "top-bottom");
+
+ this.bgIframe.onResized();
+ if(this.shadow){ this.shadow.size(width, height); }
+ this.onResized();
+ },
+
+ checkSize: function() {
+ // summary
+ // checkSize() is called when the user has resized the browser window,
+ // but that doesn't affect this widget (or this widget's children)
+ // so it can be safely ignored...
+ // TODO: unless we are maximized. then we should resize ourself.
+ }
+ }
+);
+
+// summary
+// A non-modal floating window.
+// Attaches to a Taskbar which has an icon for each window.
+// Must specify size (like style="width: 500px; height: 500px;"),
+dojo.widget.defineWidget(
+ "dojo.widget.FloatingPane",
+ [dojo.widget.ContentPane, dojo.widget.FloatingPaneBase],
+{
+ fillInTemplate: function(args, frag){
+ this.fillInFloatingPaneTemplate(args, frag);
+ dojo.widget.FloatingPane.superclass.fillInTemplate.call(this, args, frag);
+ },
+ postCreate: function(){
+ dojo.widget.FloatingPaneBase.prototype.postCreate.apply(this, arguments);
+ dojo.widget.FloatingPane.superclass.postCreate.apply(this, arguments);
+ },
+ show: function(){
+ dojo.widget.FloatingPane.superclass.show.apply(this, arguments);
+ this.showFloatingPane();
+ },
+ onShow: function(){
+ dojo.widget.FloatingPane.superclass.onShow.call(this);
+ this.onFloatingPaneShow();
+ }
+});
+
+
+// summary
+// A modal floating window.
+// This widget is similar to the Dialog widget, but the window, unlike the Dialog, can be moved.
+// Must specify size (like style="width: 500px; height: 500px;"),
+dojo.widget.defineWidget(
+ "dojo.widget.ModalFloatingPane",
+ [dojo.widget.FloatingPane, dojo.widget.ModalDialogBase],
+ {
+ windowState: "minimized",
+ displayCloseAction: true,
+ postCreate: function(){
+ dojo.widget.ModalDialogBase.prototype.postCreate.call(this);
+ dojo.widget.ModalFloatingPane.superclass.postCreate.call(this);
+ },
+ show: function(){
+ dojo.widget.ModalFloatingPane.superclass.show.apply(this, arguments);
+ this.showModalDialog();
+ this.placeModalDialog();
+ //place the background div under this modal pane
+ this.shared.bg.style.zIndex = this.domNode.style.zIndex-1;
+ },
+ hide: function(){
+ this.hideModalDialog();
+ dojo.widget.ModalFloatingPane.superclass.hide.apply(this, arguments);
+ },
+ closeWindow: function(){
+ this.hide();
+ dojo.widget.ModalFloatingPane.superclass.closeWindow.apply(this, arguments);
+ }
+ }
+);