How to extend 'old style' dojox widgets? - javascript

I've already written my own dijit widgets, as well as extended the existing one. It's simply making new declare with extended widget as argument, and using the own one instead of extended one.
However, I have a problem with dojox/form/Uploader, because it's that 'old-style' widget using old-style syntax. Instead of using the object returned by require, one should use the global object:
require(['dojox/form/Uploader'], function(Uploader){
var u = new dojox.form.Uploader({})
u.startup()
})
So, if I want to extend that widget, and using the child 'class' instead of the original, how should I actually do that?
Another thing I don't fully understand is, why whe need to use that 'old-style' syntax for dojox/form/Uploader, because it's created with the same syntax as 'normal' widget:
return declare("dojox.form.Uploader", [Base, Button, HTML5, IFrame, Flash], {

I believe you can extend it just like a 'new style' (AMD) widget, i.e.:
require([
"dojo/_base/declare",
"dojox/form/Uploader"
], function(decl) {
var MyUploader = decl(dojox.form.Uploader, {
buildRendering: function() {
this.inherited(arguments);
this.domNode.appendChild(
document.createTextNode(" ← awesome"));
}
});
new MyUploader({}).placeAt("x").startup();
});
Or am I misunderstanding your question? The reason there are traces of the 'old style' syntax in Uploader (and some other widgets) is probably just because nobody has had the time to port it to the new style yet (so it was probably automatically "converted").
Edit: Actually, the Uploader returns a 'new style' object in addition to setting the dojox.form.Uploader global. So you can actually change the above example to:
require([
"dojo/_base/declare",
"dojox/form/Uploader"
], function(decl, Uploader) {
var MyUploader = decl(Uploader, {
....
since Uploader === dojox.form.Uploader here.

Related

How to extend native DOM elements using "is"?

I am trying to using the custom elements spec to extend native DOM elements using the "is" attribute, but it doesn't seem to be doing anything at all. I am using Google Canary so I am able to create custom elements, but no effect in extending.
In my sample, I am trying to add a caption to the native img tag:
<img is="super-img" src="http://lorempixel.com/400/200/"
caption="This is my custom caption!" />
<script>
document.registerElement('super-img', {
prototype: Object.create(HTMLImageElement.prototype, {
createdCallback: function() {
var caption = this.attributes.getNamedItem('caption').value;
alert(caption);
}
})
});
</script>
http://jsbin.com/OMaPIVoV/3/
The createdCallback never fires. Any ideas on how to accomplish this?
Object.create(HTMLImageElement.prototype, {
createdCallback: function() {…}
})
Object.create does create a map of property descriptors as its second parameter - not plain values - like Object.defineProperties does.
This is also mentioned in the article you found at "Adding JS properties and methods":
Of course there are umpteen thousand ways to construct a prototype. If
you're not a fan of creating prototypes like this, here's a more
condensed version of the same thing:
[…] [This] first format allows for the use of ES5 Object.defineProperty.
The second allows the use of get/set.
(The strike-through was added by me as it's rubbish)
So what you want is either
var SuperImgProto = Object.create(HTMLImageElement.prototype);
SuperImgProto.createdCallback = function() { … };
var SuperImg = document.registerElement('super-img', {prototype: SuperImgProto});
or
document.registerElement('super-img', {
prototype: Object.create(HTMLImageElement.prototype, {
createdCallback: {value: function() { … } }
})
});
looks like you forgot to tell your web component, that it extends the native img element. Here's a running example based on your fiddle but broken down to the important bits: http://jsbin.com/OMaPIVoV/7/edit
hope this helps!

jQuery UI Operator Overloading?

I'm attempting to figure out OOP Javascript, jQuery, and jQuery UI all at the same time. Basically, I want to create a custom "panel" component that I can reuse in various places throughout my web app. The panel consists of a title bar and then content below it.
So I'm using jQuery UI to accomplish this. I want to be able to make the component and then change its attributes (like the title bar text). Here's an example:
$(function()
{
$.widget("custom.ShinyPanel",
{
options: {
css:{},
title:""
},
_create:function()
{
$(this.element).addClass("shinyPanel").disableSelection();
this.titleBar = $(createElement("div")).addClass("shinyPanelTitleBar").appendTo(this.element);
this.topShine = $(createElement("div")).addClass("shinyPanelTopShine").appendTo(this.element);
this.leftShine = $(createElement("div")).addClass("shinyPanelLeftShine").appendTo(this.element);
this.content = $(createElement("div")).addClass("shinyPanelContent").appendTo(this.element);
this._refresh();
},
_refresh:function()
{
if (this.options.hasOwnProperty("title"))
$(this.titleBar).html(this.options.title);
}
});
});
// $("#divShotList").ShinyPanel({title:"Shot List"}); // this works
$("#divShotList").ShinyPanel();
$("#divShotList").title = "Shot List"; // this doesn't work
<div id="divShotList" style="position:absolute; top:5px; bottom:10px; width:250px;"></div>
Is there a way for me to overload the = operator or something to make this work with this syntax? I know that I could probably create an extra function, like setProperty or something, but it would be really cool if I could just keep this syntax and get it to work. Any idea how I can modify the widget to make this happen?
The element or jQuery wrapped element is not your widget:
$("#divShotList").data('ShinyPanel')._setOption('title', 'something');
But it is store in the .data() of the element.
Alternatively:
var shinyPanel = $("#divShotList").ShinyPanel().data('ShinyPanel');
shinyPanel.options.title = 'new title';
shinyPanel.refresh();
would also work.
Final Edit: To answer you question: No.

How to create a well formed global javascript object containing special functions

I am creating a small project that heavily relies on JavaScript. I come from php/mysql and now stepping into node.js/javascript/mongodb, and I hve to say it's quite a mindswitch.
I want to create a simple object that has some special function that I can use in the page. I have been looking at some tutorial, and looking at the libraries such as jquery and backbone, but I need some final advice on my decision.
I only need some small functions, and no cross-browser support, that's why I don't choose something like backbone. Maybe ill change to that later when I have a better crasp on JavaScript programming.
What is confusing me is whether to use the new, or maybe wrapping the code into a self-invoking function.
I see jquery creates an object inside the window and than exposes that, but I have no idea how that works.
Enough intro, now to the point. I have created something like this:
var $s = Object.create({
page: Object.create({
title: 'pagetitle',
html: '',
data: {},
render: function(){
// Basic render function
}
}),
socket: Object.create({
// My websocket connection
}),
store: function(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
retrieve: function(key) {
var value = localStorage.getItem(key);
return value && JSON.parse(value);
},
slugify: function(slug){
return slug.replace(/[^a-zA-Z 0-9-]+/g,'').toLowerCase().replace(/ /g,'-');
}
});
This are just a few random functions I put in.
I haven't tested this yet, it is a draft, I want to know if this is any good.
Now I was thinking i can do some stuff like this:
$s.page.html = 'somehtml';
$s.page.render();
// Maybe
$s.store( $s.page.title, $s.page.html );
I do use jQuery and jQuery templating, so something like this could be possible:
$.tmpl( $s.page.html, $s.page.data ).appendTo( "#content" );
Nothing fancy is needed here. You can create a global javascript object with a method like this:
var myGlobalObject = {};
myGlobalObject.testFunction = function() {
// put your code here
};
You can then call that like this:
myGlobalObject.testFunction();
One slightly more flexible design pattern you will often seen used is this:
var myGlobalObject = myGlobalObject || {};
myGlobalObject.testFunction = function() {
// put your code here
};
This is used when there might be lots of different pieces of code contributing to myGlobalObject and they all want to make sure that it's properly declared before adding properties to it. This way of doing it, creates it if it doesn't already exist and if it does already exist, leaves the methods and properties on it that might already be there. This allows multiple modules to each contribute initialization to myGlobalObject without regards for the order they load.

Ext.Template is not defined

I'm having trouble preparing my application for deployment. I'm using ext-dev.js and have a compnent with the following:
Ext.define(myNameSpace.myComponentName, {
requires: ['Ext.XTemplate'],
tpl: new Ext.XTemplate('someTemplate')
})
On application startup it gives an
Ext.XTemplate is not a constructor
Do you have a solution for this?
You cannot define Ext.XTemplate inline because it hasn't been retrieved from the server yet by the Ext.Loader which handles loading of dependencies. There are two solutions:
// If you really want to add it to the prototype, but adding objects to the
// prototype is usually a bad idea since they are shared by all instances
// In this case, it may be ok, since there isn't much you can change about a
// template after you create it
Ext.define('myNameSpace.myComponentName', {
requires: ['Ext.XTemplate'],
}, function() {
// This callback is for when all the dependencies are loaded
myNameSpace.myComponentName.prototype.tpl = new Ext.XTemplate('someTemplate')
});
// Or just define it in initComponent, since you shouldn't instantiate it
// until after Ext.onReady is called (which means all dependencies are loaded)
Ext.define('myNameSpace.myComponentName', {
requires: ['Ext.XTemplate'],
initComponent: function() {
this.tpl = new Ext.XTemplate('someTemplate');
this.callParent();
}
});
UPDATE I actually forgot to list another possibility that may work, that is, don't use new, use Ext.create('Ext.XTemplate', args)'. The problem with Ext.create is that it will block until Ext.XTemplate (and dependencies) is loaded. I would still go with one of two approaches mentioned at the top

Dojo widget defaults

i'm currently writing a large scale application heavily based on the dojo toolkit. The whole app is working and standing, but one issue i can not find my way out with, is the creation of custom widgets. It would be useful because it would clean up my source code and also i can reuse this 'widgets' in later projects.
For example: i have a main toolbar, which i would like to call using
myapp.toolbar = new myapp.mainToolbar();
instead of using
myapp.toolbar = new new dijit.Toolbar({}, containerID);
var button1 = new dijit.form.Button({
label: 'Delete',
id: 'toolbarbutton1',
showLabel: true,
iconClass: "dijitEditorIcon dijitEditorIcon Delete"
});
myapp.toolbar.addChild(button1);
...
So in short: how do i set up the whole toolbar somewhere else and call it as a simple object? Trying to figure out dojo.declare('myapp.mainToolbar', dijit.Toolbar, {...}) but then i get a bunch of errors like 'startup function not existing' etc...
I'd like to do all this programmatically, so without the template html and css files in a custom widget.
A link to a good tutorial or howto would be nice, although google nor yahoo! will reveal any extra's on this matter for me... :)
There are multiple ways to do this.
It seems like your method of extending Toolbar should work (not sure why it didn't).
You can also declare a class that embeds Toolbar and the buttons, using widgetsInTemplate:
dojo.declare("MyToolbar", [dijit._Widget, dijit._Templated], {
_widgetsInTemplate: true,
templateString: '<div> <div dojoType=dijit.Toolbar>' +
' <button dojoType=dijit.form.Button ...
Note that the top node in MyToolbar can't have a dojoType, so I put Toolbar one level down.
Alternately you can do the same thing by using dijit.Declaration, see http://docs.dojocampus.org/dijit/Declaration.
It works for me when I use declare with the superclass inside of an array:
dojo.declare('myapp.mainToolbar', [ dijit.Toolbar ],
{
....
}
);
var x = new myapp.mainToolbar({ ... });
x.startup();
Which kind of violates the docs. It should take one Function or an array of Functions.

Categories

Resources