[dojo-contributors] New way to declare widgets

Bill Keese bill at dojotoolkit.org
Sun Apr 2 06:13:27 EDT 2006


Hi Alex, this looks interesting.  It also looks like (something similar) 
could be used for non-widgets (?)  How does the constructor work?  Is 
there a constructor property (like a method called "initialize")?


dojo-checkins-admin at dojotoolkit.org wrote:
> Author: alex
> Date: Sat Apr  1 00:19:55 2006
> New Revision: 3421
> 
> Modified:
>    trunk/src/widget/Dialog.js
>    trunk/src/widget/Widget.js
> Log:
> a new, terser way to declare widgets and one widget ported to support the new style.
> 
> 
> Modified: trunk/src/widget/Dialog.js
> ==============================================================================
> --- trunk/src/widget/Dialog.js	(original)
> +++ trunk/src/widget/Dialog.js	Sat Apr  1 00:19:55 2006
> @@ -1,5 +1,5 @@
>  dojo.provide("dojo.widget.Dialog");
> -dojo.provide("dojo.widget.HtmlDialog");
> +dojo.provide("dojo.widget.html.Dialog");
>  
>  dojo.require("dojo.widget.*");
>  dojo.require("dojo.event.*");
> @@ -7,197 +7,190 @@
>  dojo.require("dojo.fx.*");
>  dojo.require("dojo.html");
>  
> -dojo.widget.tags.addParseTreeHandler("dojo:dialog");
> -
> -dojo.widget.HtmlDialog = function(){
> -	dojo.widget.HtmlWidget.call(this);
> -}
> -
> -dojo.inherits(dojo.widget.HtmlDialog, dojo.widget.HtmlWidget);
> -
> -dojo.lang.extend(dojo.widget.HtmlDialog, {
> -	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlDialog.html"),
> -	widgetType: "Dialog",
> -	isContainer: true,
> -
> -	_scrollConnected: false,
> -	
> -	// provide a focusable element or element id if you need to
> -	// work around FF's tendency to send focus into outer space on hide
> -	focusElement: "",
> -
> -	bg: null,
> -	bgColor: "black",
> -	bgOpacity: 0.4,
> -	followScroll: true,
> -	_fromTrap: false,
> -	anim: null,
> -
> -	trapTabs: function(e){
> -		if(e.target == this.tabStart) {
> -			if(this._fromTrap) {
> -				this._fromTrap = false;
> -			} else {
> -				this._fromTrap = true;
> -				this.tabEnd.focus();
> +dojo.widget.defineWidget(
> +	"dojo.widget.html.Dialog",
> +	dojo.widget.HtmlWidget,
> +	{
> +		templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlDialog.html"),
> +		isContainer: true,
> +		_scrollConnected: false,
> +		
> +		// provide a focusable element or element id if you need to
> +		// work around FF's tendency to send focus into outer space on hide
> +		focusElement: "",
> +
> +		bg: null,
> +		bgColor: "black",
> +		bgOpacity: 0.4,
> +		followScroll: true,
> +		_fromTrap: false,
> +		anim: null,
> +
> +		trapTabs: function(e){
> +			if(e.target == this.tabStart) {
> +				if(this._fromTrap) {
> +					this._fromTrap = false;
> +				} else {
> +					this._fromTrap = true;
> +					this.tabEnd.focus();
> +				}
> +			} else if(e.target == this.tabEnd) {
> +				if(this._fromTrap) {
> +					this._fromTrap = false;
> +				} else {
> +					this._fromTrap = true;
> +					this.tabStart.focus();
> +				}
>  			}
> -		} else if(e.target == this.tabEnd) {
> -			if(this._fromTrap) {
> -				this._fromTrap = false;
> -			} else {
> -				this._fromTrap = true;
> -				this.tabStart.focus();
> -			}
> -		}
> -	},
> +		},
>  
> -	clearTrap: function(e) {
> -		var _this = this;
> -		setTimeout(function() {
> -			_this._fromTrap = false;
> -		}, 100);
> -	},
> -
> -	postCreate: function(args, frag, parentComp) {
> -		with(this.domNode.style) {
> -			position = "absolute";
> -			zIndex = 999;
> -			display = "none";
> -			overflow = "visible";
> -		}
> -		var b = document.body;
> -		b.appendChild(this.domNode);
> +		clearTrap: function(e) {
> +			var _this = this;
> +			setTimeout(function() {
> +				_this._fromTrap = false;
> +			}, 100);
> +		},
> +
> +		postCreate: function(args, frag, parentComp) {
> +			with(this.domNode.style) {
> +				position = "absolute";
> +				zIndex = 999;
> +				display = "none";
> +				overflow = "visible";
> +			}
> +			var b = document.body;
> +			b.appendChild(this.domNode);
>  
> -		this.bgIframe = new dojo.html.BackgroundIframe(this.domNode);
> +			this.bgIframe = new dojo.html.BackgroundIframe(this.domNode);
>  
> -		this.bg = document.createElement("div");
> -		this.bg.className = "dialogUnderlay";
> -		with(this.bg.style) {
> -			position = "absolute";
> -			left = top = "0px";
> -			zIndex = 998;
> -			display = "none";
> -		}
> -		this.setBackgroundColor(this.bgColor);
> -		b.appendChild(this.bg);
> -	},
> -
> -	setBackgroundColor: function(color) {
> -		if(arguments.length >= 3) {
> -			color = new dojo.graphics.color.Color(arguments[0], arguments[1], arguments[2]);
> -		} else {
> -			color = new dojo.graphics.color.Color(color);
> -		}
> -		this.bg.style.backgroundColor = color.toString();
> -		return this.bgColor = color;
> -	},
> -	
> -	setBackgroundOpacity: function(op) {
> -		if(arguments.length == 0) { op = this.bgOpacity; }
> -		dojo.style.setOpacity(this.bg, op);
> -		try {
> -			this.bgOpacity = dojo.style.getOpacity(this.bg);
> -		} catch (e) {
> -			this.bgOpacity = op;
> -		}
> -		return this.bgOpacity;
> -	},
> -
> -	sizeBackground: function() {
> -		if(this.bgOpacity > 0) {
> -			var h = document.documentElement.scrollHeight || document.body.scrollHeight;
> -			var w = dojo.html.getViewportWidth();
> -			this.bg.style.width = w + "px";
> -			this.bg.style.height = h + "px";
> -		}
> -	},
> +			this.bg = document.createElement("div");
> +			this.bg.className = "dialogUnderlay";
> +			with(this.bg.style) {
> +				position = "absolute";
> +				left = top = "0px";
> +				zIndex = 998;
> +				display = "none";
> +			}
> +			this.setBackgroundColor(this.bgColor);
> +			b.appendChild(this.bg);
> +		},
> +
> +		setBackgroundColor: function(color) {
> +			if(arguments.length >= 3) {
> +				color = new dojo.graphics.color.Color(arguments[0], arguments[1], arguments[2]);
> +			} else {
> +				color = new dojo.graphics.color.Color(color);
> +			}
> +			this.bg.style.backgroundColor = color.toString();
> +			return this.bgColor = color;
> +		},
> +		
> +		setBackgroundOpacity: function(op) {
> +			if(arguments.length == 0) { op = this.bgOpacity; }
> +			dojo.style.setOpacity(this.bg, op);
> +			try {
> +				this.bgOpacity = dojo.style.getOpacity(this.bg);
> +			} catch (e) {
> +				this.bgOpacity = op;
> +			}
> +			return this.bgOpacity;
> +		},
>  
> -	showBackground: function() {
> -		this.sizeBackground();
> -		if(this.bgOpacity > 0) {
> -			this.bg.style.display = "block";
> -		}
> -	},
> +		sizeBackground: function() {
> +			if(this.bgOpacity > 0) {
> +				var h = document.documentElement.scrollHeight || document.body.scrollHeight;
> +				var w = dojo.html.getViewportWidth();
> +				this.bg.style.width = w + "px";
> +				this.bg.style.height = h + "px";
> +			}
> +		},
>  
> -	placeDialog: function() {
> -		var scroll_offset = dojo.html.getScrollOffset();
> -		var viewport_size = dojo.html.getViewportSize();
> -
> -		// find the size of the dialog
> -		var w = dojo.style.getOuterWidth(this.containerNode);
> -		var h = dojo.style.getOuterHeight(this.containerNode);
> -
> -		var x = scroll_offset[0] + (viewport_size[0] - w)/2;
> -		var y = scroll_offset[1] + (viewport_size[1] - h)/2;
> -
> -		with(this.domNode.style) {
> -			left = x + "px";
> -			top = y + "px";
> -		}
> -	},
> +		showBackground: function() {
> +			this.sizeBackground();
> +			if(this.bgOpacity > 0) {
> +				this.bg.style.display = "block";
> +			}
> +		},
>  
> -	show: function() {
> -		this.setBackgroundOpacity();
> -		this.showBackground();
> +		placeDialog: function() {
> +			var scroll_offset = dojo.html.getScrollOffset();
> +			var viewport_size = dojo.html.getViewportSize();
> +
> +			// find the size of the dialog
> +			var w = dojo.style.getOuterWidth(this.containerNode);
> +			var h = dojo.style.getOuterHeight(this.containerNode);
> +
> +			var x = scroll_offset[0] + (viewport_size[0] - w)/2;
> +			var y = scroll_offset[1] + (viewport_size[1] - h)/2;
> +
> +			with(this.domNode.style) {
> +				left = x + "px";
> +				top = y + "px";
> +			}
> +		},
>  
> -		this.domNode.style.visibility = "hidden";
> -		this.domNode.style.display = "block";
> -		dojo.widget.HtmlDialog.superclass.onResized.call(this);
> -		this.placeDialog();
> +		show: function() {
> +			this.setBackgroundOpacity();
> +			this.showBackground();
> +
> +			this.domNode.style.visibility = "hidden";
> +			this.domNode.style.display = "block";
> +			dojo.widget.html.Dialog.superclass.onResized.call(this);
> +			this.placeDialog();
>  
> -		this.domNode.style.display="none";
> -		this.domNode.style.visibility = "";
> +			this.domNode.style.display="none";
> +			this.domNode.style.visibility = "";
>  
> -		dojo.widget.HtmlDialog.superclass.show.call(this);
> +			dojo.widget.html.Dialog.superclass.show.call(this);
>  
> -		// FIXME: moz doesn't generate onscroll events for mouse or key scrolling (wtf)
> -		// we should create a fake event by polling the scrolltop/scrollleft every X ms.
> -		// this smells like it should be a dojo feature rather than just for this widget.
> +			// FIXME: moz doesn't generate onscroll events for mouse or key scrolling (wtf)
> +			// we should create a fake event by polling the scrolltop/scrollleft every X ms.
> +			// this smells like it should be a dojo feature rather than just for this widget.
> +
> +			if (this.followScroll && !this._scrollConnected){
> +				this._scrollConnected = true;
> +				dojo.event.connect(window, "onscroll", this, "onScroll");
> +			}
> +		},
>  
> -		if (this.followScroll && !this._scrollConnected){
> -			this._scrollConnected = true;
> -			dojo.event.connect(window, "onscroll", this, "onScroll");
> -		}
> -	},
> +		hide: function(){
> +			// workaround for FF focus going into outer space
> +			if (this.focusElement) { 
> +				dojo.byId(this.focusElement).focus(); 
> +				dojo.byId(this.focusElement).blur();
> +			}
>  
> -	hide: function(){
> -		// workaround for FF focus going into outer space
> -		if (this.focusElement) { 
> -			dojo.byId(this.focusElement).focus(); 
> -			dojo.byId(this.focusElement).blur();
> -		}
> +			this.bg.style.display = "none";
> +			this.bg.style.width = this.bg.style.height = "1px";
>  
> -		this.bg.style.display = "none";
> -		this.bg.style.width = this.bg.style.height = "1px";
> +			dojo.widget.html.Dialog.superclass.hide.call(this);
>  
> -		dojo.widget.HtmlDialog.superclass.hide.call(this);
> +			if (this._scrollConnected){
> +				this._scrollConnected = false;
> +				dojo.event.disconnect(window, "onscroll", this, "onScroll");
> +			}
> +		},
>  
> -		if (this._scrollConnected){
> -			this._scrollConnected = false;
> -			dojo.event.disconnect(window, "onscroll", this, "onScroll");
> -		}
> -	},
> +		setCloseControl: function(node) {
> +			dojo.event.connect(node, "onclick", this, "hide");
> +		},
>  
> -	setCloseControl: function(node) {
> -		dojo.event.connect(node, "onclick", this, "hide");
> -	},
> -
> -	setShowControl: function(node) {
> -		dojo.event.connect(node, "onclick", this, "show");
> -	},
> -
> -	onScroll: function(){
> -		this.placeDialog();
> -		this.domNode.style.display = "block";
> -	},
> +		setShowControl: function(node) {
> +			dojo.event.connect(node, "onclick", this, "show");
> +		},
>  
> -	onResized: function() {
> -		if(this.isShowing()){
> -			this.sizeBackground();
> +		onScroll: function(){
>  			this.placeDialog();
> -			this.domNode.style.display="block";
> -			dojo.widget.HtmlDialog.superclass.onResized.call(this);
> +			this.domNode.style.display = "block";
> +		},
> +
> +		onResized: function() {
> +			if(this.isShowing()){
> +				this.sizeBackground();
> +				this.placeDialog();
> +				this.domNode.style.display="block";
> +				dojo.widget.html.Dialog.superclass.onResized.call(this);
> +			}
>  		}
>  	}
> -});
> -
> +);
> 
> Modified: trunk/src/widget/Widget.js
> ==============================================================================
> --- trunk/src/widget/Widget.js	(original)
> +++ trunk/src/widget/Widget.js	Sat Apr  1 00:19:55 2006
> @@ -463,6 +463,13 @@
>  	var properties = widgetParser.parseProperties(fragment["dojo:connect"]);
>  }
>  
> +// FIXME: if we know the insertion point (to a reasonable location), why then do we:
> +//	- create a template node
> +//	- clone the template node
> +//	- render the clone and set properties
> +//	- remove the clone from the render tree
> +//	- place the clone
> +// this is quite dumb
>  dojo.widget.buildWidgetFromParseTree = function(type, frag, 
>  												parser, parentComp, 
>  												insertionIndex, localProps){
> @@ -484,3 +491,47 @@
>  	// dojo.debug(new Date() - tic);
>  	return ret;
>  }
> +
> +/*
> + * it would be best to be able to call defineWidget for any widget namespace
> + */
> +dojo.widget.defineWidget = function(	widgetClass 	/*string*/, 
> +										superclass 		/*function*/, 
> +										props 			/*object*/,
> +										renderer 		/*string*/, 
> +										ctor 			/*function*/){
> +	if((!ctor)&&(props["classConstructor"])){
> +		ctor = props.classConstructor;
> +	}
> +	if(!ctor){ ctor = function(){}; }
> +	var nsref;
> +	var namespace;
> +	var type;
> +	if(renderer){
> +		// widgetClass takes the form foo.bar.baz.html.WidgetName
> +		var parts = widgetClass.split("."+renderer+".");
> +		namespace = parts[0];
> +		nsref = dojo.evalObjPath(namespace+"."+renderer, true);
> +		type = parts[1];
> +	}else{
> +		// widgetClass takes the form foo.bar.baz.WidgetName
> +		var parts = widgetClass.split(".");
> +		type = parts.pop();
> +		namespace = parts.join(".");
> +		nsref = dojo.evalObjPath(namespace, true);
> +	}
> +	
> +	if(!props){ props = {}; }
> +	props.widgetType = type;
> +
> +	dojo.widget.tags.addParseTreeHandler("dojo:"+type.toLowerCase());
> +
> +	nsref[type] = function(){
> +		superclass.call(this);
> +		ctor.call(this);
> +	}
> +
> +	dojo.inherits(nsref[type], superclass);
> +
> +	dojo.lang.extend(nsref[type], props);
> +}
> _______________________________________________
> Dojo-checkins mailing list
> Dojo-checkins at dojotoolkit.org
> http://dojotoolkit.org/mailman/listinfo/dojo-checkins

-- 

Bill



More information about the dojo-contributors mailing list