├── .gitignore ├── 001-hello-world ├── app │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 002-button-click ├── app │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 003-dialog ├── app │ ├── main.js │ ├── theme │ │ └── main.css │ └── view │ │ └── dialog.html └── index.html ├── 004-menubar ├── app │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 005-contextmenu ├── app │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 006-layout ├── NOTES.md ├── app │ ├── main.js │ ├── theme │ │ └── main.css │ └── view │ │ ├── second.html │ │ └── third.html └── index.html ├── 007-custom-alert-dialog ├── NOTES.md ├── app │ ├── dialog │ │ ├── AlertDialog.html │ │ └── AlertDialog.js │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 008-custom-confirm-dialog ├── app │ ├── dialog │ │ ├── ConfirmDialog.html │ │ └── ConfirmDialog.js │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 009-form ├── app │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 010-form-validation ├── app │ ├── main.js │ ├── theme │ │ └── main.css │ └── validate │ │ └── custom.js └── index.html ├── 011-form-ajax-validator ├── app │ ├── form │ │ └── AjaxValidationTextBox.js │ ├── main.js │ └── theme │ │ └── main.css ├── index.html └── validate.php ├── 012-login-form-dialog ├── app │ ├── dialog │ │ ├── LoginDialog.html │ │ └── LoginDialog.js │ ├── main.js │ └── theme │ │ └── main.css ├── index.html └── login.php ├── 013-dojo-amd ├── app │ ├── asset │ │ └── wtf.jpg │ ├── main.js │ ├── theme │ │ └── main.css │ └── view │ │ └── hello.html └── index.html ├── 014-mvc-form ├── app │ ├── controller │ │ └── FormController.js │ ├── main.js │ ├── theme │ │ └── main.css │ └── view │ │ └── form.html ├── form.php └── index.html ├── 015-grid ├── app │ ├── main.js │ └── theme │ │ └── main.css └── index.html ├── 016-dynamic-grid ├── app │ ├── controller │ │ └── GridController.js │ ├── grid │ │ └── Grid.js │ ├── main.js │ ├── theme │ │ └── main.css │ └── view │ │ └── grid.html └── index.html ├── README.md ├── fabfile.py ├── favicon.png ├── index.html ├── reset.css └── tutorial ├── 001.md ├── 002.md ├── 003.md ├── 004.md ├── 005.md ├── 006.md ├── 007.md ├── 008.md ├── 009.md ├── 010.md ├── 011.md ├── 012.md ├── 013.md ├── 014.md ├── 015.md ├── 016.md ├── about.md └── index.json /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings 2 | /.buildpath 3 | /.project 4 | /.pydevproject 5 | /vendor 6 | /dist.tar 7 | /dist.tar.gz 8 | /composer.phar 9 | /composer.lock 10 | /fabfile.pyc 11 | /build.properties 12 | *.pyc 13 | -------------------------------------------------------------------------------- /001-hello-world/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready' 4 | ], function(require, ready){ 5 | 6 | var app = {}; 7 | 8 | ready(function(){ 9 | app.alert('Hello World!'); 10 | }); 11 | 12 | /** 13 | * Display alert dialog. 14 | */ 15 | app.alert = function(message){ 16 | require(['dijit/Dialog'], function(Dialog){ 17 | var dialog = new Dialog({ title: 'Hello!', content: message }); 18 | dialog.show(); 19 | }); 20 | }; 21 | 22 | return app; 23 | }); 24 | -------------------------------------------------------------------------------- /001-hello-world/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /001-hello-world/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /002-button-click/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry' 5 | ], function(require, ready, registry){ 6 | 7 | var app = {}; 8 | 9 | ready(function(){ 10 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 11 | console.log('loaded!'); 12 | }); 13 | 14 | /** 15 | * Display alert dialog. 16 | */ 17 | app.alert = function(message){ 18 | require(['dijit/Dialog'], function(Dialog){ 19 | var dialog = new Dialog({ title: 'Hello!', content: message }); 20 | dialog.show(); 21 | }); 22 | }; 23 | 24 | /** 25 | * Button click action. 26 | */ 27 | app.onButtonClick = function(){ 28 | app.alert('You just have clicked this button!'); 29 | }; 30 | 31 | return app; 32 | }); 33 | -------------------------------------------------------------------------------- /002-button-click/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /002-button-click/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /003-dialog/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry' 5 | ], function(require, ready, registry){ 6 | 7 | var app = {}; 8 | 9 | ready(function(){ 10 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 11 | console.log('loaded!'); 12 | }); 13 | 14 | /** 15 | * Button click action. 16 | */ 17 | app.onButtonClick = function(){ 18 | require(['dijit/Dialog'], function(Dialog){ 19 | var dialog = new Dialog({ 20 | title: "Some dialog", 21 | href: appConfig.baseUrl + '/app/view/dialog.html', 22 | style: "width:400px" 23 | }); 24 | dialog.show(); 25 | }); 26 | }; 27 | 28 | return app; 29 | }); 30 | -------------------------------------------------------------------------------- /003-dialog/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /003-dialog/app/view/dialog.html: -------------------------------------------------------------------------------- 1 |

Dialog

2 |

3 | This is a custom dialog.
4 | Content was loaded from a remote html file. 5 |

6 | -------------------------------------------------------------------------------- /003-dialog/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /004-menubar/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry' 5 | ], function(require, ready, registry){ 6 | 7 | var app = {}; 8 | 9 | ready(function(){ 10 | dojo.connect(registry.byId('mbtnHelp'), 'onClick', app.onHelpButtonClick); 11 | console.log('loaded!'); 12 | }); 13 | 14 | /** 15 | * Display alert dialog. 16 | */ 17 | app.alert = function(message){ 18 | require(['dijit/Dialog'], function(Dialog){ 19 | var dialog = new Dialog({ title: 'Hello!', content: message }); 20 | dialog.show(); 21 | }); 22 | }; 23 | 24 | /** 25 | * Help button click action. 26 | */ 27 | app.onHelpButtonClick = function(){ 28 | app.alert('This is a Dojo MenuBar example.'); 29 | }; 30 | 31 | return app; 32 | }); 33 | -------------------------------------------------------------------------------- /004-menubar/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appIconEditCopy { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/editcopy.png'); } 12 | .appIconEditCut { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/editcut.png'); } 13 | .appIconEditPaste { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/editpaste.png'); } 14 | .appIconExit { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/exit.png'); } 15 | .appIconFileNew { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/filenew.png'); } 16 | .appIconFileOpen { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/fileopen.png'); } 17 | .appIconFileSave { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/filesave.png'); } 18 | .appIconFileSaveAs { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/filesaveas.png'); } 19 | .appIconFileClose { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/fileclose.png'); } 20 | .appIconHelp { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/help.png'); } 21 | .appIconRedo { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/redo.png'); } 22 | .appIconUndo { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/undo.png'); } 23 | -------------------------------------------------------------------------------- /004-menubar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 |
41 |
42 | File 43 |
44 |
New
45 |
Open
46 |
Save
47 |
Save As...
48 |
Close
49 |
Exit
50 |
51 |
52 |
53 | Edit 54 |
55 |
Undo
56 |
Redo
57 |
58 |
Cut
59 |
Copy
60 |
Paste
61 |
62 |
63 |
64 | Help 65 |
66 |
About
67 |
68 |
69 |
70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /005-contextmenu/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo', 4 | 'dojo/ready', 5 | 'dojo/on', 6 | 'dojo/dom' 7 | ], function(require, dojo, ready, on, dom){ 8 | 9 | var app = {}; 10 | 11 | ready(function(){ 12 | on(dom.byId('mbtnAction1'), 'click', function(){ app.alert('Click Action 1'); }); 13 | on(dom.byId('mbtnAction2'), 'click', function(){ app.alert('Click Action 2'); }); 14 | on(dom.byId('mbtnAction3'), 'click', function(){ app.alert('Click Action 3'); }); 15 | console.log('loaded!'); 16 | }); 17 | 18 | /** 19 | * Display alert dialog. 20 | */ 21 | app.alert = function(message){ 22 | require(['dijit/Dialog'], function(Dialog){ 23 | var dialog = new Dialog({ title: 'Hello!', content: message, style: 'width:200px' }); 24 | dialog.show(); 25 | }); 26 | }; 27 | 28 | return app; 29 | }); 30 | -------------------------------------------------------------------------------- /005-contextmenu/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appIconEditCopy { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/editcopy.png'); } 12 | .appIconEditCut { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/editcut.png'); } 13 | .appIconEditPaste { background-image:url('http://cdn.devgrid.net/icon/nuvola/1.0/16x16/actions/editpaste.png'); } 14 | 15 | #contextMenu { 16 | position:absolute; 17 | opacity:0; 18 | } 19 | -------------------------------------------------------------------------------- /005-contextmenu/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 |

41 | Click somewhere with right mouse button. 42 |

43 | 44 |
45 |
Cut
46 |
Copy
47 |
Paste
48 |
49 |
50 | Submenu 51 |
52 |
Action 1
53 |
Action 2
54 |
Action 3
55 |
56 |
57 |
58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /006-layout/NOTES.md: -------------------------------------------------------------------------------- 1 | - Border container has to have explicitly set width and height! 2 | 3 | -------------------------------------------------------------------------------- /006-layout/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready' 4 | ], function(require, ready){ 5 | 6 | var app = {}; 7 | 8 | ready(function(){ 9 | console.log('loaded!'); 10 | }); 11 | 12 | /** 13 | * Display alert dialog. 14 | */ 15 | app.alert = function(message){ 16 | require(['dijit/Dialog'], function(Dialog){ 17 | var dialog = new Dialog({ title: 'Hello!', content: message }); 18 | dialog.show(); 19 | }); 20 | }; 21 | 22 | return app; 23 | }); 24 | -------------------------------------------------------------------------------- /006-layout/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appBorderContainer { 12 | width:100%; 13 | height:100%; 14 | } 15 | 16 | .appLeadingAccordionContainer { 17 | width:300px; 18 | } 19 | 20 | .appTrailingAccordionContainer { 21 | width:200px; 22 | } -------------------------------------------------------------------------------- /006-layout/app/view/second.html: -------------------------------------------------------------------------------- 1 | This is content from a remote html file. 2 | -------------------------------------------------------------------------------- /006-layout/app/view/third.html: -------------------------------------------------------------------------------- 1 | 4 | This is content from a remote html file that is being parsed by Dojo. 5 | 10 | -------------------------------------------------------------------------------- /006-layout/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 |
41 |
42 | This is the header content pane. 43 |
44 |
45 |
46 | First pane content. 47 |
48 |
49 | Second pane content. 50 |
51 |
52 | Third pane content. 53 |
54 |
55 |
56 |
57 | First tab inline content. 58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | First pane content. 67 |
68 |
69 | Second pane content. 70 |
71 |
72 |
73 | This is the footer content pane. 74 |
75 |
76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /007-custom-alert-dialog/NOTES.md: -------------------------------------------------------------------------------- 1 | - Parser requires explicitly loaded dijit/form/Button 2 | 3 | -------------------------------------------------------------------------------- /007-custom-alert-dialog/app/dialog/AlertDialog.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /007-custom-alert-dialog/app/dialog/AlertDialog.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'dojo/_base/declare', 3 | 'dijit/Dialog', 4 | 'dijit/_WidgetsInTemplateMixin', 5 | 'dojo/text!./AlertDialog.html', 6 | 'dijit/form/Button' 7 | ], function(declare, Dialog, _WidgetsInTemplateMixin, template){ 8 | return declare('app.dialog.AlertDialog', [Dialog, _WidgetsInTemplateMixin], { 9 | title: 'Alert', 10 | templateString: template 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /007-custom-alert-dialog/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready' 4 | ], function(require, ready){ 5 | 6 | var app = {}; 7 | 8 | ready(function(){ 9 | app.alert('Hello World!'); 10 | }); 11 | 12 | /** 13 | * Display alert dialog. 14 | */ 15 | app.alert = function(message){ 16 | require(['app/dialog/AlertDialog'], function(Dialog){ 17 | var dialog = new Dialog({ content: message }); 18 | dialog.show(); 19 | }); 20 | }; 21 | 22 | return app; 23 | }); 24 | -------------------------------------------------------------------------------- /007-custom-alert-dialog/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appAlertDialog { 12 | min-width:150px; 13 | } 14 | .appAlertDialog .appDialogPaneButtons, 15 | .appAlertDialog .dijitDialogPaneContent { 16 | text-align:center; 17 | background: #fff; 18 | } 19 | -------------------------------------------------------------------------------- /007-custom-alert-dialog/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /008-custom-confirm-dialog/app/dialog/ConfirmDialog.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /008-custom-confirm-dialog/app/dialog/ConfirmDialog.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'dojo/_base/declare', 3 | 'dijit/Dialog', 4 | 'dijit/_WidgetsInTemplateMixin', 5 | 'dojo/text!./ConfirmDialog.html', 6 | 'dijit/form/Button' 7 | ], function(declare, Dialog, _WidgetsInTemplateMixin, template){ 8 | return declare('app.dialog.ConfirmDialog', [Dialog, _WidgetsInTemplateMixin], { 9 | 10 | title: 'Confirm', 11 | templateString: template, 12 | 13 | constructor: function(options){ 14 | if (options.message) { 15 | this.content = options.message; 16 | } 17 | } 18 | 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /008-custom-confirm-dialog/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry' 5 | ], function(require, ready, registry){ 6 | 7 | var app = {}; 8 | 9 | ready(function(){ 10 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 11 | console.log('loaded!'); 12 | }); 13 | 14 | /** 15 | * Display confirm dialog. 16 | */ 17 | app.confirm = function(options){ 18 | require(['app/dialog/ConfirmDialog'], function(Dialog){ 19 | var dialog = new Dialog(options); 20 | dialog.show(); 21 | }); 22 | }; 23 | 24 | /** 25 | * Button click action. 26 | */ 27 | app.onButtonClick = function(){ 28 | app.confirm({ 29 | message: 'Do you like this demo?', 30 | onExecute: function(){ 31 | console.log('great! :)'); 32 | }, 33 | onCancel: function(){ 34 | console.log('too bad :<'); 35 | } 36 | }); 37 | }; 38 | 39 | return app; 40 | }); 41 | -------------------------------------------------------------------------------- /008-custom-confirm-dialog/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appConfirmDialog { 12 | min-width:150px; 13 | } 14 | .appConfirmDialog .appDialogPaneButtons, 15 | .appConfirmDialog .dijitDialogPaneContent { 16 | text-align:center; 17 | background: #fff; 18 | } 19 | -------------------------------------------------------------------------------- /008-custom-confirm-dialog/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /009-form/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready' 4 | ], function(require, ready){ 5 | 6 | var app = {}; 7 | 8 | ready(function(){ 9 | console.log('loaded!'); 10 | }); 11 | 12 | /** 13 | * Display alert dialog. 14 | */ 15 | app.alert = function(message){ 16 | require(['dijit/Dialog'], function(Dialog){ 17 | var dialog = new Dialog({ title: 'Hello!', content: message }); 18 | dialog.show(); 19 | }); 20 | }; 21 | 22 | return app; 23 | }); 24 | -------------------------------------------------------------------------------- /009-form/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | min-height:100%; 6 | margin:0; 7 | padding:0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /009-form/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 55 | 60 | 65 | 70 |
71 |
72 |
73 |
74 |
75 |
    76 |
  1. 0%
  2. 77 |
  3. 78 |
  4. 50%
  5. 79 |
  6. 80 |
  7. 100%
  8. 81 |
82 |
    83 |
  1. 84 |
  2. 25%
  3. 85 |
  4. 86 |
  5. 75%
  6. 87 |
  7. 88 |
89 |
90 |
91 |
    92 |
  1. 0%
  2. 93 |
  3. 94 |
  4. 50%
  5. 95 |
  6. 96 |
  7. 100%
  8. 97 |
98 |
    99 |
  1. 100 |
  2. 25%
  3. 101 |
  4. 102 |
  5. 75%
  6. 103 |
  7. 104 |
105 |
106 |
107 | 108 |
109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /010-form-validation/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dojox/validate/web', 5 | 'app/validate/custom' 6 | ], function(require, ready){ 7 | 8 | var app = {}; 9 | 10 | ready(function(){ 11 | console.log('loaded!'); 12 | }); 13 | 14 | /** 15 | * Display alert dialog. 16 | */ 17 | app.alert = function(message){ 18 | require(['dijit/Dialog'], function(Dialog){ 19 | var dialog = new Dialog({ title: 'Hello!', content: message }); 20 | dialog.show(); 21 | }); 22 | }; 23 | 24 | return app; 25 | }); 26 | -------------------------------------------------------------------------------- /010-form-validation/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /010-form-validation/app/validate/custom.js: -------------------------------------------------------------------------------- 1 | define("app/validate/custom", ["dojo", "dojo/_base/lang"], function(dojo, lang){ 2 | var validate = lang.getObject("dojox.validate", true); 3 | 4 | validate.isOver666 = function(value, flags){ 5 | console.log('validate'); 6 | return (parseInt(value) > 666); 7 | }; 8 | 9 | return validate; 10 | }); 11 | -------------------------------------------------------------------------------- /010-form-validation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 48 |
49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /011-form-ajax-validator/app/form/AjaxValidationTextBox.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'dojo/_base/declare', 3 | 'dojo', 4 | 'dijit/form/ValidationTextBox' 5 | ], function(declare, dojo, ValidationTextBox){ 6 | return declare('app.form.AjaxValidationTextBox', [ValidationTextBox], { 7 | 8 | ajaxUrl: null, 9 | ajaxLock: false, 10 | ajaxResult: false, 11 | 12 | isValid: function(){ 13 | var widget = this; 14 | if (!this.ajaxLock && this.ajaxUrl) { 15 | this.ajaxLock = true; 16 | dojo.xhrGet({ 17 | url: widget.ajaxUrl + '?value=' + widget.get('value'), 18 | handleAs: 'json', 19 | load: function(result){ 20 | widget.ajaxResult = result; 21 | widget.validate(); 22 | widget.ajaxLock = false; 23 | } 24 | }); 25 | } 26 | return this.ajaxResult; 27 | } 28 | 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /011-form-ajax-validator/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready' 4 | ], function(require, ready){ 5 | 6 | var app = {}; 7 | 8 | ready(function(){ 9 | console.log('loaded!'); 10 | }); 11 | 12 | /** 13 | * Display alert dialog. 14 | */ 15 | app.alert = function(message){ 16 | require(['dijit/Dialog'], function(Dialog){ 17 | var dialog = new Dialog({ title: 'Hello!', content: message }); 18 | dialog.show(); 19 | }); 20 | }; 21 | 22 | return app; 23 | }); 24 | -------------------------------------------------------------------------------- /011-form-ajax-validator/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /011-form-ajax-validator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | 45 |
46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /011-form-ajax-validator/validate.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | x 6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 |
21 | -------------------------------------------------------------------------------- /012-login-form-dialog/app/dialog/LoginDialog.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'dojo/_base/declare', 3 | 'dojo/_base/lang', 4 | 'dojo', 5 | 'dijit/Dialog', 6 | 'dijit/_WidgetsInTemplateMixin', 7 | 'dojo/text!./LoginDialog.html', 8 | 'dijit/form/Button', 9 | 'dijit/form/Form', 10 | 'dijit/form/TextBox', 11 | 'dojox/layout/TableContainer' 12 | ], function(declare, lang, dojo, Dialog, _WidgetsInTemplateMixin, template){ 13 | return declare('app.dialog.LoginDialog', [Dialog, _WidgetsInTemplateMixin], { 14 | 15 | title: 'Login required', 16 | style: 'width:400px', 17 | templateString: template, 18 | 19 | constructor: function(options){ 20 | lang.mixin(this, options); 21 | }, 22 | 23 | onSubmit: function(){ 24 | var widget = this; 25 | dojo.xhrPost({ 26 | url: this.url, 27 | form: this.loginForm.id, 28 | handleAs: 'json', 29 | load: function(response){ 30 | if (response.status == 'success') { 31 | widget.onSuccess(response); 32 | } else { 33 | widget.onFailure(response); 34 | } 35 | } 36 | }); 37 | }, 38 | 39 | onSuccess: function(response){ 40 | 41 | }, 42 | 43 | onFailure: function(response){ 44 | 45 | } 46 | 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /012-login-form-dialog/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry' 5 | ], function(require, ready, registry){ 6 | 7 | var app = {}; 8 | 9 | ready(function(){ 10 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 11 | console.log('loaded!'); 12 | }); 13 | 14 | /** 15 | * Display alert dialog. 16 | */ 17 | app.alert = function(message){ 18 | require(['dijit/Dialog'], function(Dialog){ 19 | var dialog = new Dialog({ title: 'Alert', content: message }); 20 | dialog.show(); 21 | }); 22 | }; 23 | 24 | /** 25 | * Display login dialog. 26 | */ 27 | app.login = function(options){ 28 | require(['app/dialog/LoginDialog'], function(Dialog){ 29 | var dialog = new Dialog(options); 30 | dialog.show(); 31 | }); 32 | }; 33 | 34 | /** 35 | * Button click action. 36 | */ 37 | app.onButtonClick = function(){ 38 | app.login({ 39 | url: appConfig.baseUrl + '/login.php', 40 | onSuccess: function(response){ 41 | console.log(response.message); 42 | this.onExecute(); // Hide dialog. 43 | app.alert('You are successfully logged in!'); 44 | }, 45 | onFailure: function(response){ 46 | console.log(response.message); 47 | app.alert('Invalid login or password!'); 48 | } 49 | }); 50 | }; 51 | 52 | return app; 53 | }); 54 | -------------------------------------------------------------------------------- /012-login-form-dialog/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appConfirmDialog { 12 | min-width:150px; 13 | } 14 | .appConfirmDialog .appDialogPaneButtons, 15 | .appConfirmDialog .dijitDialogPaneContent { 16 | text-align:center; 17 | background: #fff; 18 | } 19 | -------------------------------------------------------------------------------- /012-login-form-dialog/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 23 | 24 | 37 | 38 | 39 | 40 |

Username: admin

41 |

Password: secret

42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /012-login-form-dialog/login.php: -------------------------------------------------------------------------------- 1 | 'success', 5 | 'message' => 'Logged in' 6 | )); 7 | 8 | } else { 9 | echo json_encode(array( 10 | 'status' => 'failure', 11 | 'message' => 'Invalid login or password' 12 | )); 13 | } 14 | -------------------------------------------------------------------------------- /013-dojo-amd/app/asset/wtf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepa/dojo-tutorial/e46a82904b5d16686b1167887a5705aa74385930/013-dojo-amd/app/asset/wtf.jpg -------------------------------------------------------------------------------- /013-dojo-amd/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry', 5 | ], function (require, ready, registry) { 6 | 7 | var app = {}; 8 | 9 | ready(function () { 10 | console.log('loaded'); 11 | app.renderDemo(); 12 | }); 13 | 14 | app.renderDemo = function () { 15 | require(['dojo/text!app/view/hello.html', 'jQuery', 'Handlebars'], function (view) { 16 | // Render view. 17 | var template = Handlebars.compile(view); 18 | var html = template({ 19 | date: (new Date()).toString(), 20 | imageUrl: appConfig.baseUrl + '/app/asset/wtf.jpg' 21 | }); 22 | 23 | var contentPane = registry.byId('contentPane'); 24 | contentPane.setContent(html); 25 | 26 | ready(function () { 27 | $('#bClickMe').click(function () { 28 | $('.hiddenImage').show('slow'); 29 | console.log('jquery click'); 30 | }); 31 | }); 32 | }); 33 | }; 34 | 35 | return app; 36 | }); 37 | -------------------------------------------------------------------------------- /013-dojo-amd/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appContentPane { 12 | border:0 !important; 13 | padding:0 !important; 14 | } 15 | 16 | .hiddenImage { 17 | display: none; 18 | } 19 | -------------------------------------------------------------------------------- /013-dojo-amd/app/view/hello.html: -------------------------------------------------------------------------------- 1 |

Hello!

2 |

today is: {{date}}

3 |

4 |

5 | -------------------------------------------------------------------------------- /013-dojo-amd/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 39 | 40 | 43 | 44 | 45 | 46 |
47 | 48 |
49 |
50 | 51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /014-mvc-form/app/controller/FormController.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'dojo/_base/declare', 3 | 'dojo', 4 | 'dijit/registry', 5 | 'dojo/ready', 6 | 'Handlebars' 7 | ], function (declare, dojo, registry, ready) { 8 | return declare('app.controller.FormController', [], { 9 | 10 | entity: {}, 11 | formId: null, 12 | postUrl: null, 13 | 14 | constructor: function (options) { 15 | console.log('contstructor'); 16 | dojo.safeMixin(this, options); 17 | }, 18 | 19 | renderForm: function (contentPane) { 20 | var controller = this; 21 | require(['dojo/text!app/view/form.html'], function (view) { 22 | // Render view in content pane. 23 | var template = Handlebars.compile(view); 24 | contentPane.set('content', template({ 25 | formId: controller.formId, 26 | postUrl: controller.postUrl, 27 | entity: controller.entity 28 | })); 29 | 30 | // Connect button onClick action when content pane is rendered. 31 | ready(function () { 32 | dojo.connect(registry.byId('bSubmit'), 'onClick', function () { 33 | dojo.xhrPost({ 34 | form: dojo.byId(controller.formId), 35 | handleAs: 'text', 36 | load: function (response) { 37 | console.log('Success!'); 38 | controller.renderResponse(response); 39 | }, 40 | error: function () { 41 | console.log('Error!'); 42 | } 43 | }); 44 | }); 45 | }); 46 | }); 47 | }, 48 | 49 | renderResponse: function (response) { 50 | var html = '
' + response + '
'; 51 | var responseContentPane = registry.byId(this.formId + 'Response'); 52 | responseContentPane.set('content', html); 53 | } 54 | 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /014-mvc-form/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry', 5 | 'dojox/validate/web' 6 | ], function (require, ready, registry) { 7 | 8 | var app = {}; 9 | 10 | ready(function () { 11 | console.log('loaded'); 12 | require(['app/controller/FormController'], function (FormController) { 13 | var controller = new FormController({ 14 | formId: 'myForm', 15 | postUrl: appConfig.baseUrl + '/form.php', 16 | entity: { 17 | firstName: 'Santa', 18 | lastName: 'Claus', 19 | email: 'santa@claus.com' 20 | } 21 | }); 22 | controller.renderForm(registry.byId('contentPane')); 23 | }); 24 | }); 25 | 26 | return app; 27 | }); 28 | -------------------------------------------------------------------------------- /014-mvc-form/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appContentPane { 12 | border:0 !important; 13 | padding:0 !important; 14 | } 15 | -------------------------------------------------------------------------------- /014-mvc-form/app/view/form.html: -------------------------------------------------------------------------------- 1 |

Form

2 |
3 |
4 |
5 |
6 |
7 |
8 | 9 |
10 |
11 | 12 |

Server response

13 |
14 | -------------------------------------------------------------------------------- /014-mvc-form/form.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 34 | 35 | 38 | 39 | 40 | 41 |
42 | 43 |
44 |
45 | 46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /015-grid/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo/ready', 4 | 'dijit/registry' 5 | ], function (require, ready, registry) { 6 | 7 | var app = {}; 8 | 9 | app.data = { 10 | identified: 'id', 11 | items: [ 12 | { 13 | id: 1, 14 | first_name: 'Johnnie', 15 | last_name: 'Walker', 16 | email_address: 'johnnie@walker.com', 17 | age: 18 18 | }, 19 | { 20 | id: 1, 21 | first_name: 'Jack', 22 | last_name: 'Daniels', 23 | email_address: 'jack@daniels.com', 24 | age: 3 25 | }, 26 | { 27 | id: 1, 28 | first_name: 'Moonshine', 29 | last_name: 'Booze', 30 | email_address: 'get@wasted.com', 31 | age: 0 32 | }, 33 | ] 34 | }; 35 | 36 | ready(function () { 37 | console.log('loaded!'); 38 | app.showGrid('gridPlaceholder', app.data); 39 | }); 40 | 41 | app.showGrid = function (placeholderId, data) { 42 | require(['dojox/grid/EnhancedGrid', 'dojo/data/ItemFileWriteStore'], function (Grid, Store) { 43 | var store = new Store({ 44 | data: data 45 | }); 46 | 47 | var grid = new Grid({ 48 | id: 'myGrid', 49 | store: store, 50 | structure: [[ 51 | { 52 | name: 'First name', 53 | field: 'first_name', 54 | width: '200px' 55 | }, 56 | { 57 | name: 'Last name', 58 | field: 'last_name', 59 | width: '200px' 60 | }, 61 | { 62 | name: 'Email', 63 | field: 'email_address', 64 | width: '350px' 65 | }, 66 | { 67 | name: 'Age', 68 | field: 'age', 69 | width: '80px' 70 | }, 71 | ]] 72 | }); 73 | grid.placeAt(placeholderId); 74 | grid.startup(); 75 | }); 76 | }; 77 | 78 | return app; 79 | }); 80 | -------------------------------------------------------------------------------- /015-grid/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appGrid { 12 | width:100%; 13 | height:100%; 14 | } 15 | -------------------------------------------------------------------------------- /015-grid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 12 | 24 | 25 | 38 | 39 | 40 | 41 |
42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /016-dynamic-grid/app/controller/GridController.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'dojo/_base/declare', 3 | 'dijit/registry', 4 | 'handlebars' 5 | ], function (declare, registry) { 6 | return declare('app.controller.GridController', [], { 7 | 8 | renderGrid: function (title, data) { 9 | require([ 10 | 'dojox/layout/ContentPane', 11 | 'app/grid/Grid', 12 | 'dojo/data/ItemFileWriteStore', 13 | 'dojo/text!app/view/grid.html' 14 | ], function (ContentPane, Grid, Store, view) { 15 | // Generate random id. 16 | var unique = Math.abs(Math.floor(Math.random() * 0xffff)); 17 | 18 | // Create handlebars template and render content. 19 | var template = Handlebars.compile(view); 20 | var content = template({ unique: unique }); 21 | 22 | // Create content pane for grid. 23 | var contentPane = new ContentPane({ 24 | title: title, 25 | closable: true, 26 | content: content 27 | }); 28 | 29 | // Render content pane. 30 | var tabContainer = registry.byId('tabContainer'); 31 | tabContainer.addChild(contentPane); 32 | tabContainer.selectChild(contentPane); 33 | 34 | // Create grid. 35 | var grid = new Grid({ 36 | id: 'grid' + unique, 37 | store: new Store({ data: data }) 38 | }); 39 | grid.placeAt('gridPlaceholder' + unique); 40 | grid.startup(); 41 | }); 42 | } 43 | 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /016-dynamic-grid/app/grid/Grid.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'dojo/_base/declare', 3 | 'dojox/grid/EnhancedGrid' 4 | ], function (declare, EnhancedGrid) { 5 | return declare('app.grid.Grid', [EnhancedGrid], { 6 | 7 | structure: [[ 8 | { 9 | name: 'First name', 10 | field: 'first_name', 11 | width: '200px' 12 | }, 13 | { 14 | name: 'Last name', 15 | field: 'last_name', 16 | width: '200px' 17 | }, 18 | { 19 | name: 'Email', 20 | field: 'email_address', 21 | width: '350px' 22 | }, 23 | { 24 | name: 'Age', 25 | field: 'age', 26 | width: '80px' 27 | } 28 | ]] 29 | 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /016-dynamic-grid/app/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'require', 3 | 'dojo', 4 | 'dojo/ready', 5 | 'dijit/registry' 6 | ], function (require, dojo, ready, registry) { 7 | 8 | var app = {}; 9 | 10 | app.idx = 1; 11 | 12 | app.getData = function () { 13 | return { 14 | identified: 'id', 15 | items: [ 16 | { 17 | id: 1, 18 | first_name: 'Johnnie', 19 | last_name: 'Walker', 20 | email_address: 'johnnie@walker.com', 21 | age: 18 22 | }, 23 | { 24 | id: 1, 25 | first_name: 'Jack', 26 | last_name: 'Daniels', 27 | email_address: 'jack@daniels.com', 28 | age: 3 29 | }, 30 | { 31 | id: 1, 32 | first_name: 'Moonshine', 33 | last_name: 'Booze', 34 | email_address: 'get@wasted.com', 35 | age: 0 36 | }, 37 | ] 38 | }; 39 | }; 40 | 41 | ready(function () { 42 | console.log('loaded!'); 43 | 44 | dojo.connect(registry.byId('mbShowGrid'), 'onClick', function () { 45 | require(['app/controller/GridController'], function (Controller) { 46 | var controller = new Controller(); 47 | controller.renderGrid('Grid ' + app.idx++, app.getData()); 48 | }); 49 | }); 50 | }); 51 | 52 | return app; 53 | }); 54 | -------------------------------------------------------------------------------- /016-dynamic-grid/app/theme/main.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | } 10 | 11 | .appGrid { 12 | width:100%; 13 | height:100%; 14 | } 15 | 16 | .appContentPane { 17 | border:0 !important; 18 | padding:0 !important; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /016-dynamic-grid/app/view/grid.html: -------------------------------------------------------------------------------- 1 |
Grid will be displayed here.
2 | -------------------------------------------------------------------------------- /016-dynamic-grid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dojo Tutorial 7 | 8 | 9 | 10 | 11 | 12 | 35 | 36 | 39 | 40 | 41 | 42 |
43 | 44 |
45 |
46 |
Show grid
47 |
48 |
49 | 50 |
51 |
52 |
53 |
54 | 55 |
56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dojo Toolkit 1.9 Tutorial 2 | 3 | _This repository is no longer maintained!_ 4 | 5 | This is a tutorial with simple examples how to solve real life scenarios with Dojo and how to create Rich Internet Applications / Singe Page Applications mostly backend oriented. 6 | The tutorial was started because of lack of good examples that can introduce Dojo step by step, which by far is most likely one of the most powerful and comprehensive javascript toolkits in the world offering a lot more ready to use widgets than any other popular javascript framework. 7 | 8 | ## Website & examples 9 | Visit http://dojotutorial.org/ where you can find working examples from each tutorial. 10 | 11 | ## Tutorials 12 | Each lesson is in the _tutorial_ directory. 13 | 14 | * 001 - **Hello world** - Create a boilerplate app with dojo. 15 | * 002 - **Button click** - Handle button click action. 16 | * 003 - **Dialog** - Display basic dialog box. 17 | * 004 - **Menubar** - Display sample menu bar with drop down menus and icons. 18 | * 005 - **Context menu** - Display context menu triggered by mouse right button click. 19 | * 006 - **Layout** - Construct sample dijit layout. 20 | * 007 - **Custom alert dialog** - Create custom alert box widget. 21 | * 008 - **Custom confirm dialog** - Create custom confirm box widget. 22 | * 009 - **Form** - Display various types of dijit form elements. 23 | * 010 - **Form validation** - Validate form values with builtin validators. 24 | * 011 - **Form ajax validator** - Create custom form validator that talks with remote server using Ajax to validate a value. 25 | * 012 - **Login form dialog** - Create login box widget and handle submiting login data. 26 | * 013 - **Dojo AMD** - How to use Dojo AMD, how to integrate external libraries like jQuery and Handlebars. 27 | * 014 - **MVC form** - Create simple MVC app to controll a form. 28 | * 015 - **Grid** - Display basic grid. 29 | * 016 - **Dynamic grid** - Create multiple grid on fly, and embed them in content panes. 30 | 31 | ## Contributing 32 | This tutorial is far from perfect and I'm still learning while writing it, so feel free to send me pull requests if you see any mistakes, and I would love to attach more tutorials if you have any. 33 | -------------------------------------------------------------------------------- /fabfile.py: -------------------------------------------------------------------------------- 1 | import time 2 | import fabric.api as fapi 3 | import fabric.contrib.files as ffiles 4 | 5 | fapi.env.project_name = 'dojo-tutorial' 6 | fapi.env.distfile = 'dist.tar.gz' 7 | fapi.env.path = '/var/www' 8 | 9 | fapi.env.user = 'root' 10 | fapi.env.disable_known_hosts = True 11 | 12 | @fapi.task 13 | @fapi.parallel 14 | def rollout(): 15 | fapi.env.release = time.strftime('%Y%m%d%H%M%S') 16 | project_path = '%(path)s/%(project_name)s' % fapi.env 17 | release_path = project_path + '/' + fapi.env.release 18 | current_path = project_path + '/current' 19 | fapi.run('mkdir -p ' + release_path) 20 | fapi.put('%(distfile)s' % fapi.env, release_path) 21 | fapi.run('cd ' + release_path + ' && tar zxf %(distfile)s' % fapi.env) 22 | if (ffiles.exists(current_path)): 23 | fapi.run('cd ' + project_path + ' && unlink current') 24 | fapi.run('cd ' + project_path + ' && ln -s %(release)s current' % fapi.env) 25 | fapi.run('cd ' + release_path + ' && rm -f %(distfile)s' % fapi.env) 26 | 27 | @fapi.task 28 | @fapi.parallel 29 | def purge(): 30 | fapi.run('rm -rf %(path)s/%(project_name)s' % fapi.env) 31 | 32 | if 'rollout' in fapi.env.tasks: 33 | fapi.local('rm -rf {}'.format(fapi.env.distfile)) 34 | fapi.local('tar --exclude={} -zcf {} *'.format(fapi.env.distfile, fapi.env.distfile)) 35 | -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepa/dojo-tutorial/e46a82904b5d16686b1167887a5705aa74385930/favicon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dojo Tutorial 4 | 5 | 6 | 7 | Visit dojotutorial.org 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /reset.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | html, body { border:0; margin:0; padding:0; width:100%; min-height:100%; } 4 | body { font-size:12px; font-family: Helvetica, Arial, "sans-serif" } 5 | h1, h2, h3, h4, h5, h6 { margin:0; padding:0; font-weight:normal; } 6 | ul, ol { margin:0px 0 0px 16px; padding:0; } 7 | blockquote { margin:22px 40px; padding:0; } 8 | img { border:0; } 9 | a, a:visited { text-decoration:none; } 10 | form { margin:0; padding:0; } 11 | input, select, textarea { border:1px solid #888888; padding:1px; margin:0px; } 12 | textarea { line-height:1.25; } 13 | label { cursor:pointer; } 14 | table { border:0; margin:0 0 0 0; padding:0; } 15 | table tr td { padding:2px; } 16 | p { margin:0; padding:0; } 17 | pre, code { line-height:1em; padding:0; margin:0; } 18 | 19 | .left { float:left; } 20 | .right { float:right; } 21 | .clear { clear:both; } 22 | 23 | .text-left { text-align:left; } 24 | .text-right { text-align:right; } 25 | .text-center { text-align:center; } 26 | 27 | .normal { font-weight:normal; } 28 | .bold { font-weight:bold; } 29 | -------------------------------------------------------------------------------- /tutorial/001.md: -------------------------------------------------------------------------------- 1 | # 001. Hello World 2 | 3 | ## Beginning 4 | This is the first step of how to get into frontend development with Dojo Toolkit. 5 | The very first step presents how to init Dojo and how to separate the html *view* from javascript *logic*. 6 | *** 7 | 8 | 9 | ### Source code & demo 10 | 11 | [Live demo](http://demo.dojotutorial.org/001-hello-world/) 12 | 13 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/001-hello-world) 14 | 15 | *** 16 | 17 | 18 | ### Application structure 19 | The basic directory structure of the application is very simple and it will evolve later: 20 | 21 | - **/index.html** - The application entry point. 22 | - **/app** - The application module. 23 | - **/app/main.js** - The main script for *app* module. 24 | 25 | *** 26 | 27 | 28 | ### Markup 29 | The entry point of our Dojo application is index.html, here the magic starts. 30 | ~~~ html5 31 | 32 | 33 | 34 | 35 | 36 | Dojo Tutorial 37 | 38 | 39 | 40 | 41 | 53 | 54 | 67 | 68 | 69 | 70 | 71 | ~~~ 72 | 73 | First of all we choose the Dojo theme. In this example it is theme named *claro*. 74 | ~~~ html5 75 | 76 | ~~~ 77 | 78 | Next we configure the Application, in order to get the *app* module loaded we need to extract the *base path* from the current url. 79 | ~~~ javascript 80 | appConfig = { 81 | baseUrl: location.href.substring(0,location.href.lastIndexOf("/")+1) 82 | }; 83 | ~~~ 84 | 85 | And now we configure Dojo to *parse* html content on load and add required modules automagically when they are requested. 86 | ~~~ javascript 87 | dojoConfig = { 88 | parseOnLoad: true 89 | }; 90 | ~~~ 91 | 92 | At last but not least we load Dojo. 93 | ~~~ html5 94 | 95 | ~~~ 96 | *** 97 | 98 | 99 | ### Load modules with RequireJS 100 | In this tutorial from the very beginning we will use *RequireJS* to load modules and dependencies. The application will reside in the *app* folder with all of its source code. 101 | To point the location of the application correctly it was required to get the *base path* from the browser. 102 | Loading application module looks like this: 103 | ~~~ javascript 104 | require( 105 | { 106 | packages: [ 107 | { name: 'app', location: appConfig.baseUrl + '/app/' } 108 | ] 109 | }, 110 | [ 111 | "app" 112 | ] 113 | ); 114 | ~~~ 115 | The *require* function comes from *RequireJS* and the rest is pretty stratightforward. 116 | *** 117 | 118 | 119 | ### app/main.js 120 | The application module starts in file **/app/main.js** which is loaded by default by *RequireJS*. 121 | ~~~ javascript 122 | define([ 123 | 'require', 124 | 'dojo/ready' 125 | ], function(require, ready){ 126 | 127 | var app = {}; 128 | 129 | ready(function(){ 130 | app.alert('Hello World!'); 131 | }); 132 | 133 | /** 134 | * Display alert dialog. 135 | */ 136 | app.alert = function(message){ 137 | require(['dijit/Dialog'], function(Dialog){ 138 | var dialog = new Dialog({ title: 'Hello!', content: message }); 139 | dialog.show(); 140 | }); 141 | }; 142 | 143 | return app; 144 | }); 145 | ~~~ 146 | This piece of code will *define* a new object named **app** visible in the project namespace. 147 | The *app* object is our application *controller* and the closure inside *define* function works as a constructor. 148 | 149 | The first array part requests two dependencies: *require* and *dojo/ready* and they are passed to the closure. 150 | 151 | Inside the *app* object we have one method named *alert* for displaying a *Dialog* widget. When the application is loaded it will trigger the closure inside *ready* function which will load *dijit/Dialog* widget and display a dialog box. 152 | *** 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /tutorial/002.md: -------------------------------------------------------------------------------- 1 | # 002. Button Click 2 | 3 | Display dijit Button and handle onClick event. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/002-button-click/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/002-button-click) 12 | 13 | *** 14 | 15 | 16 | ### Markup 17 | In the first **001** tutorial you can see how to load and initialize Dojo Toolkit. To display a dojo button you can use the following markup: 18 | ~~~ html5 19 | 20 | 21 | 22 | 23 | 24 | ~~~ 25 | The *data-dojo-type* links the HTML tag with a dojo type, in this example dojo parser will load dijit/form/Button class. 26 | 27 | And thats all! The real logic starts in javascript part. 28 | *** 29 | 30 | 31 | ### app/main.js 32 | Because *main.js* is loaded before *body* DOM element, it is required to wait untill the document is ready before we can bind anything, this is why the *ready* method was used: 33 | ~~~ javascript 34 | ready(function(){ 35 | //... 36 | }); 37 | ~~~ 38 | Anything in this closure will be executed when the document is ready. 39 | 40 | To connect an action to buttons *onClick* event you can use *dojo.connect* method: 41 | ~~~ javascript 42 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 43 | ~~~ 44 | This line will try to find a button node in *dijit registry* by id *btnClickMe* and bind *app.onButtonClick* closure from the *app* object. 45 | 46 | When button is clicked the *app.onButtonClick* is executed, in it we have access to the *app* object so it is possible to display a custom alert box: 47 | ~~~ javascript 48 | app.onButtonClick = function(){ 49 | app.alert('You just have clicked this button!'); 50 | }; 51 | ~~~ 52 | 53 | Full code: 54 | ~~~ javascript 55 | define([ 56 | 'require', 57 | 'dojo/ready', 58 | 'dijit/registry' 59 | ], function(require, ready, registry){ 60 | 61 | var app = {}; 62 | 63 | ready(function(){ 64 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 65 | console.log('loaded!'); 66 | }); 67 | 68 | /** 69 | * Display alert dialog. 70 | */ 71 | app.alert = function(message){ 72 | require(['dijit/Dialog'], function(Dialog){ 73 | var dialog = new Dialog({ title: 'Hello!', content: message }); 74 | dialog.show(); 75 | }); 76 | }; 77 | 78 | /** 79 | * Button click action. 80 | */ 81 | app.onButtonClick = function(){ 82 | app.alert('You just have clicked this button!'); 83 | }; 84 | 85 | return app; 86 | }); 87 | ~~~ 88 | *** 89 | 90 | 91 | -------------------------------------------------------------------------------- /tutorial/003.md: -------------------------------------------------------------------------------- 1 | # 003. Dialog 2 | 3 | Display dijit Dialog with content loaded from separate html file. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/003-dialog/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/003-dialog) 12 | 13 | *** 14 | 15 | 16 | ### Markup 17 | In this example the Dialog is created dynamically in JavaScript when the *Click me!* button is clicked, the markup for the button is very simple: 18 | ~~~ html5 19 | 20 | 21 | 22 | 23 | 24 | ~~~ 25 | *** 26 | 27 | 28 | ### Bind dijit Button onClick 29 | Like in the previous tutorial, to bind a function to button's onClick event the *dojo.connect* function is used: 30 | ~~~ javascript 31 | ready(function(){ 32 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 33 | }); 34 | ~~~ 35 | *** 36 | 37 | 38 | ### Display dijit Dialog 39 | First we need to load the *dijit/Dialog* class, it is done with the *require* function, next when the class is loaded the *function(Dialog)* is executed. 40 | The *dijit/Dialog* has two interesting options, first is *content* which can be used to directly display some text on the dialog box, and the second is *href* which will load a remote file with an async http call. 41 | ~~~ javascript 42 | require(['dijit/Dialog'], function(Dialog){ 43 | var dialog = new Dialog({ 44 | title: "Some dialog", 45 | href: appConfig.baseUrl + '/app/view/dialog.html', 46 | style: "width:400px" 47 | }); 48 | dialog.show(); 49 | }); 50 | ~~~ 51 | Content file: 52 | ~~~ html5 53 |

Dialog

54 |

55 | This is a custom dialog.
56 | Content was loaded from a remote html file. 57 |

58 | ~~~ 59 | *** 60 | 61 | 62 | ### app/main.js 63 | ~~~ javascript 64 | define([ 65 | 'require', 66 | 'dojo/ready', 67 | 'dijit/registry' 68 | ], function(require, ready, registry){ 69 | 70 | var app = {}; 71 | 72 | ready(function(){ 73 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 74 | console.log('loaded!'); 75 | }); 76 | 77 | /** 78 | * Button click action. 79 | */ 80 | app.onButtonClick = function(){ 81 | require(['dijit/Dialog'], function(Dialog){ 82 | var dialog = new Dialog({ 83 | title: "Some dialog", 84 | href: appConfig.baseUrl + '/app/view/dialog.html', 85 | style: "width:400px" 86 | }); 87 | dialog.show(); 88 | }); 89 | }; 90 | 91 | return app; 92 | }); 93 | ~~~ 94 | *** 95 | 96 | -------------------------------------------------------------------------------- /tutorial/004.md: -------------------------------------------------------------------------------- 1 | # 004. Menubar 2 | 3 | Display dijit Menubar with dropdowns and custom icons. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/004-menubar/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/004-menubar) 12 | 13 | *** 14 | 15 | 16 | ### Markup 17 | ~~~ html5 18 | 19 | 20 |
21 |
22 | File 23 |
24 |
New
25 |
Open
26 |
Save
27 |
Save As...
28 |
Close
29 |
Exit
30 |
31 |
32 |
33 | Edit 34 |
35 |
Undo
36 |
Redo
37 |
38 |
Cut
39 |
Copy
40 |
Paste
41 |
42 |
43 |
44 | Help 45 |
46 |
About
47 |
48 |
49 |
50 | 51 | 52 | ~~~ 53 | *** 54 | 55 | 56 | ### app/main.js 57 | ~~~ javascript 58 | define([ 59 | 'require', 60 | 'dojo/ready', 61 | 'dijit/registry' 62 | ], function(require, ready, registry){ 63 | 64 | var app = {}; 65 | 66 | ready(function(){ 67 | dojo.connect(registry.byId('mbtnHelp'), 'onClick', app.onHelpButtonClick); 68 | console.log('loaded!'); 69 | }); 70 | 71 | /** 72 | * Display alert dialog. 73 | */ 74 | app.alert = function(message){ 75 | require(['dijit/Dialog'], function(Dialog){ 76 | var dialog = new Dialog({ title: 'Hello!', content: message }); 77 | dialog.show(); 78 | }); 79 | }; 80 | 81 | /** 82 | * Help button click action. 83 | */ 84 | app.onHelpButtonClick = function(){ 85 | app.alert('This is a Dojo MenuBar example.'); 86 | }; 87 | 88 | return app; 89 | }); 90 | ~~~ 91 | *** 92 | 93 | -------------------------------------------------------------------------------- /tutorial/005.md: -------------------------------------------------------------------------------- 1 | # 005. Context Menu 2 | 3 | Create application context menu activated with right mouse button click. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/005-contextmenu/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/005-contextmenu) 12 | 13 | *** 14 | 15 | 16 | ### Markup 17 | ~~~ html5 18 | 19 | 20 |

21 | Click somewhere with right mouse button. 22 |

23 | 24 |
25 |
Cut
26 |
Copy
27 |
Paste
28 |
29 |
30 | Submenu 31 |
32 |
Action 1
33 |
Action 2
34 |
Action 3
35 |
36 |
37 |
38 | 39 | 40 | ~~~ 41 | Dojo *dijit/Menu* has a special attribute named *contextMenuForWindow* thats binds the right mouse button click, using it you can simply create a context menu without manual handling of all kind of mouse events. 42 | When you open the live demo, you need to click right mouse button to activate the context menu. 43 | *** 44 | 45 | 46 | ### app/main.js 47 | ~~~ javascript 48 | define([ 49 | 'require', 50 | 'dojo', 51 | 'dojo/ready', 52 | 'dojo/on', 53 | 'dojo/dom' 54 | ], function(require, dojo, ready, on, dom){ 55 | 56 | var app = {}; 57 | 58 | ready(function(){ 59 | on(dom.byId('mbtnAction1'), 'click', function(){ app.alert('Click Action 1'); }); 60 | on(dom.byId('mbtnAction2'), 'click', function(){ app.alert('Click Action 2'); }); 61 | on(dom.byId('mbtnAction3'), 'click', function(){ app.alert('Click Action 3'); }); 62 | console.log('loaded!'); 63 | }); 64 | 65 | /** 66 | * Display alert dialog. 67 | */ 68 | app.alert = function(message){ 69 | require(['dijit/Dialog'], function(Dialog){ 70 | var dialog = new Dialog({ title: 'Hello!', content: message, style: 'width:200px' }); 71 | dialog.show(); 72 | }); 73 | }; 74 | 75 | return app; 76 | }); 77 | ~~~ 78 | The buttons on the *Submenu* dropdown are binded to javascript functions using *dojo/on* function. 79 | *** 80 | 81 | -------------------------------------------------------------------------------- /tutorial/006.md: -------------------------------------------------------------------------------- 1 | # 006. Layout 2 | 3 | 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/006-layout/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/006-layout) 12 | 13 | *** 14 | 15 | 16 | ### Markup 17 | ~~~ html5 18 | 19 | 20 |
21 |
22 | This is the header content pane. 23 |
24 |
25 |
26 | First pane content. 27 |
28 |
29 | Second pane content. 30 |
31 |
32 | Third pane content. 33 |
34 |
35 |
36 |
37 | First tab inline content. 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | First pane content. 47 |
48 |
49 | Second pane content. 50 |
51 |
52 |
53 | This is the footer content pane. 54 |
55 |
56 | 57 | 58 | ~~~ 59 | *** 60 | 61 | 62 | ### app/main.js 63 | ~~~ javascript 64 | define([ 65 | 'require', 66 | 'dojo/ready' 67 | ], function(require, ready){ 68 | 69 | var app = {}; 70 | 71 | ready(function(){ 72 | console.log('loaded!'); 73 | }); 74 | 75 | /** 76 | * Display alert dialog. 77 | */ 78 | app.alert = function(message){ 79 | require(['dijit/Dialog'], function(Dialog){ 80 | var dialog = new Dialog({ title: 'Hello!', content: message }); 81 | dialog.show(); 82 | }); 83 | }; 84 | 85 | return app; 86 | }); 87 | ~~~ 88 | *** 89 | 90 | 91 | ### app/view/second.html 92 | ~~~ html5 93 | This is content from a remote html file. 94 | ~~~ 95 | *** 96 | 97 | 98 | ### app/view/third.html 99 | ~~~ html5 100 | 103 | This is content from a remote html file that is being parsed by Dojo. 104 | 109 | ~~~ 110 | *** 111 | 112 | 113 | -------------------------------------------------------------------------------- /tutorial/007.md: -------------------------------------------------------------------------------- 1 | # 007. Custom Alert Dialog 2 | 3 | Create a custom alert dialog widget with overriden template. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/007-custom-alert-dialog/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/007-custom-alert-dialog) 12 | 13 | *** 14 | 15 | 16 | ### Index markup 17 | ~~~ html5 18 | 19 | 20 | ~~~ 21 | This time there is no default markup, we will display an alert dialog programatically. 22 | *** 23 | 24 | 25 | ### Custom dijit widget (app/dialog/AlertDialog.js) 26 | Dojo with RequireJS has a powerful capabilities in object oriented programming, the best feature is a simplified structured way to create custom widgets that extends other classes. 27 | Following code is the simplest declaration of a custom widget class named **AlertDialog** and places in **app/dialog/AlertDialog.js**: 28 | ~~~ javascript 29 | define([ 30 | 'dojo/_base/declare', 31 | 'dijit/Dialog', 32 | 'dijit/_WidgetsInTemplateMixin', 33 | 'dojo/text!./AlertDialog.html', 34 | 'dijit/form/Button' 35 | ], function(declare, Dialog, _WidgetsInTemplateMixin, template){ 36 | return declare('app.dialog.AlertDialog', [Dialog, _WidgetsInTemplateMixin], { 37 | title: 'Alert', 38 | templateString: template 39 | }); 40 | }); 41 | ~~~ 42 | *** 43 | 44 | 45 | ### Dijit widget template (app/dialog/AlertDialog.html) 46 | Layout of each dijit widgets is declared in markup. The difference between a common html file and a template file are properties named *data-dojo-attach-point* and *data-dojo-attach-event* which allows to bind markup to actions declared in javascript. Following template is based on the default one from dijit Dialog, with a small extension made of dijit Button. Template file is placed in **app/dialog/AlertDialog.html**. 47 | ~~~ html5 48 | 62 | ~~~ 63 | *** 64 | 65 | 66 | ### app/main.js 67 | Again we trigger the alert dialog from the main.js script. 68 | ~~~ javascript 69 | define([ 70 | 'require', 71 | 'dojo/ready' 72 | ], function(require, ready){ 73 | 74 | var app = {}; 75 | 76 | ready(function(){ 77 | app.alert('Hello World!'); 78 | }); 79 | 80 | /** 81 | * Display alert dialog. 82 | */ 83 | app.alert = function(message){ 84 | require(['app/dialog/AlertDialog'], function(Dialog){ 85 | var dialog = new Dialog({ content: message }); 86 | dialog.show(); 87 | }); 88 | }; 89 | 90 | return app; 91 | }); 92 | ~~~ 93 | *** 94 | 95 | 96 | -------------------------------------------------------------------------------- /tutorial/008.md: -------------------------------------------------------------------------------- 1 | # 008. Custom Confirm Dialog 2 | 3 | Create a custom confirm dialog widget with callbacks. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/008-custom-confirm-dialog/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/008-custom-confirm-dialog) 12 | 13 | *** 14 | 15 | 16 | ### Index markup 17 | ~~~ html5 18 | 19 | 20 | 21 | 22 | 23 | ~~~ 24 | *** 25 | 26 | 27 | ### Confirm dialog widget (app/dialog/ConfirmDialog.js) 28 | ~~~ javascript 29 | define([ 30 | 'dojo/_base/declare', 31 | 'dijit/Dialog', 32 | 'dijit/_WidgetsInTemplateMixin', 33 | 'dojo/text!./ConfirmDialog.html', 34 | 'dijit/form/Button' 35 | ], function(declare, Dialog, _WidgetsInTemplateMixin, template){ 36 | return declare('app.dialog.ConfirmDialog', [Dialog, _WidgetsInTemplateMixin], { 37 | 38 | title: 'Confirm', 39 | templateString: template, 40 | 41 | constructor: function(options){ 42 | if (options.message) { 43 | this.content = options.message; 44 | } 45 | } 46 | 47 | }); 48 | }); 49 | ~~~ 50 | *** 51 | 52 | 53 | ### Confirm dialog template (app/dialog/ConfirmDialog.html) 54 | ~~~ html5 55 | 70 | ~~~ 71 | *** 72 | 73 | 74 | ### app/main.js 75 | ~~~ javascript 76 | define([ 77 | 'require', 78 | 'dojo/ready', 79 | 'dijit/registry' 80 | ], function(require, ready, registry){ 81 | 82 | var app = {}; 83 | 84 | ready(function(){ 85 | dojo.connect(registry.byId('btnClickMe'), 'onClick', app.onButtonClick); 86 | console.log('loaded!'); 87 | }); 88 | 89 | /** 90 | * Display confirm dialog. 91 | */ 92 | app.confirm = function(options){ 93 | require(['app/dialog/ConfirmDialog'], function(Dialog){ 94 | var dialog = new Dialog(options); 95 | dialog.show(); 96 | }); 97 | }; 98 | 99 | /** 100 | * Button click action. 101 | */ 102 | app.onButtonClick = function(){ 103 | app.confirm({ 104 | message: 'Do you like this demo?', 105 | onExecute: function(){ 106 | console.log('great! :)'); 107 | }, 108 | onCancel: function(){ 109 | console.log('too bad :<'); 110 | } 111 | }); 112 | }; 113 | 114 | return app; 115 | }); 116 | ~~~ 117 | *** 118 | 119 | 120 | -------------------------------------------------------------------------------- /tutorial/009.md: -------------------------------------------------------------------------------- 1 | # 009. Form 2 | 3 | Create dijit form. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/009-form/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/009-form) 12 | 13 | *** 14 | 15 | 16 | ### Index markup 17 | ~~~ html5 18 | 19 | 20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 35 | 40 | 45 | 50 |
51 |
52 |
53 |
54 |
55 |
    56 |
  1. 0%
  2. 57 |
  3. 58 |
  4. 50%
  5. 59 |
  6. 60 |
  7. 100%
  8. 61 |
62 |
    63 |
  1. 64 |
  2. 25%
  3. 65 |
  4. 66 |
  5. 75%
  6. 67 |
  7. 68 |
69 |
70 |
71 |
    72 |
  1. 0%
  2. 73 |
  3. 74 |
  4. 50%
  5. 75 |
  6. 76 |
  7. 100%
  8. 77 |
78 |
    79 |
  1. 80 |
  2. 25%
  3. 81 |
  4. 82 |
  5. 75%
  6. 83 |
  7. 84 |
85 |
86 |
87 | 88 |
89 | 90 | 91 | ~~~ 92 | *** 93 | 94 | 95 | -------------------------------------------------------------------------------- /tutorial/010.md: -------------------------------------------------------------------------------- 1 | # 010. Form validation 2 | 3 | Validate values on dijit form and create a custom validator. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/010-form-validation/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/010-form-validation) 12 | 13 | *** 14 | 15 | 16 | ### Index markup 17 | ~~~ html5 18 | 19 | 20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 28 |
29 | 30 | 31 | ~~~ 32 | *** 33 | 34 | 35 | ### Custom form validator (app/validate/custom.js) 36 | ~~~ javascript 37 | define("app/validate/custom", ["dojo", "dojo/_base/lang"], function(dojo, lang){ 38 | var validate = lang.getObject("dojox.validate", true); 39 | 40 | validate.isOver666 = function(value, flags){ 41 | console.log('validate'); 42 | return (parseInt(value) > 666); 43 | }; 44 | 45 | return validate; 46 | }); 47 | ~~~ 48 | *** 49 | 50 | 51 | -------------------------------------------------------------------------------- /tutorial/011.md: -------------------------------------------------------------------------------- 1 | # 011. Ajax form validator 2 | 3 | Custom Ajax based validation. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/011-form-ajax-validator/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/011-form-ajax-validator) 12 | 13 | *** 14 | 15 | 16 | ### Index markup 17 | ~~~ html5 18 | 19 | 20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | ~~~ 29 | *** 30 | 31 | 32 | ### Ajax validation TextBox widget (app/form/AjaxValidationTextBox.js) 33 | ~~~ javascript 34 | define([ 35 | 'dojo/_base/declare', 36 | 'dojo', 37 | 'dijit/form/ValidationTextBox' 38 | ], function(declare, dojo, ValidationTextBox){ 39 | return declare('app.form.AjaxValidationTextBox', [ValidationTextBox], { 40 | 41 | ajaxUrl: null, 42 | ajaxLock: false, 43 | ajaxResult: false, 44 | 45 | isValid: function(){ 46 | var widget = this; 47 | if (!this.ajaxLock && this.ajaxUrl) { 48 | this.ajaxLock = true; 49 | dojo.xhrGet({ 50 | url: widget.ajaxUrl + '?value=' + widget.get('value'), 51 | handleAs: 'json', 52 | load: function(result){ 53 | widget.ajaxResult = result; 54 | widget.validate(); 55 | widget.ajaxLock = false; 56 | } 57 | }); 58 | } 59 | return this.ajaxResult; 60 | } 61 | 62 | }); 63 | }); 64 | ~~~ 65 | *** 66 | 67 | 68 | ### Server side (validate.php) 69 | ~~~ php 70 | 19 | 20 | 21 | 22 | 23 | ~~~ 24 | *** 25 | 26 | 27 | ### Login dialog widget (app/dialog/LoginDialog.js) 28 | ~~~ javascript 29 | define([ 30 | 'dojo/_base/declare', 31 | 'dojo/_base/lang', 32 | 'dojo', 33 | 'dijit/Dialog', 34 | 'dijit/_WidgetsInTemplateMixin', 35 | 'dojo/text!./LoginDialog.html', 36 | 'dijit/form/Button', 37 | 'dijit/form/Form', 38 | 'dijit/form/TextBox', 39 | 'dojox/layout/TableContainer' 40 | ], function(declare, lang, dojo, Dialog, _WidgetsInTemplateMixin, template){ 41 | return declare('app.dialog.LoginDialog', [Dialog, _WidgetsInTemplateMixin], { 42 | 43 | title: 'Login required', 44 | style: 'width:400px', 45 | templateString: template, 46 | 47 | constructor: function(options){ 48 | lang.mixin(this, options); 49 | }, 50 | 51 | onSubmit: function(){ 52 | var widget = this; 53 | dojo.xhrPost({ 54 | url: this.url, 55 | form: this.loginForm.id, 56 | handleAs: 'json', 57 | load: function(response){ 58 | if (response.status == 'success') { 59 | widget.onSuccess(response); 60 | } else { 61 | widget.onFailure(response); 62 | } 63 | } 64 | }); 65 | }, 66 | 67 | onSuccess: function(response){ 68 | 69 | }, 70 | 71 | onFailure: function(response){ 72 | 73 | } 74 | 75 | }); 76 | }); 77 | ~~~ 78 | *** 79 | 80 | 81 | ### Login widget template (app/dialog/LoginDialog.html) 82 | ~~~ html5 83 | 104 | ~~~ 105 | *** 106 | 107 | 108 | ### Server side (login.php) 109 | ~~~ php 110 | 'success', 114 | 'message' => 'Logged in' 115 | )); 116 | 117 | } else { 118 | echo json_encode(array( 119 | 'status' => 'failure', 120 | 'message' => 'Invalid login or password' 121 | )); 122 | } 123 | ~~~ 124 | *** 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /tutorial/013.md: -------------------------------------------------------------------------------- 1 | # 013. Dojo AMD 2 | 3 | This demo shows how to use Dojo loader and how to integrate Dojo application with external javascript libraries like jQuery and Handlebars. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/013-dojo-amd/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/013-dojo-amd) 12 | 13 | *** 14 | -------------------------------------------------------------------------------- /tutorial/014.md: -------------------------------------------------------------------------------- 1 | # 014. MVC form 2 | 3 | Simple MVC application, controller handles a form rendered from a view. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/014-mvc-form/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/014-mvc-form) 12 | 13 | *** 14 | -------------------------------------------------------------------------------- /tutorial/015.md: -------------------------------------------------------------------------------- 1 | # 015. Grid 2 | 3 | How to create and display basic Dojo grid and fill it with data. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/015-grid/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/015-grid) 12 | 13 | *** 14 | -------------------------------------------------------------------------------- /tutorial/016.md: -------------------------------------------------------------------------------- 1 | # 016. Dynamic grid 2 | 3 | Create a grid instance on fly and display it in a ContentPane as a tab in TabContainer. 4 | *** 5 | 6 | 7 | ### Source code & demo 8 | 9 | [Live demo](http://demo.dojotutorial.org/016-dynamic-grid/) 10 | 11 | [Source code](https://github.com/cepa/dojo-tutorial/tree/master/016-dynamic-grid) 12 | 13 | *** 14 | -------------------------------------------------------------------------------- /tutorial/about.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | ## Welcome to the Dojo Tutorial 4 | The website was created because of lack of good introduction to the latest version of Dojo, also many things are not covered in the offical documentation. The tutorial will show how to deal with many real life scenarios of using Dojo widgets and how to create custom things. 5 | 6 | The tutorial is open source, you can contribute to it by forking the project on github and sending pull request. 7 | 8 | 9 | ### Get tutorial source code 10 | ~~~ bash 11 | git clone https://github.com/cepa/dojo-tutorial 12 | ~~~ 13 | 14 | 15 | ### Get tutorial website: 16 | ~~~ bash 17 | git clone https://github.com/cepa/dojo-tutorial-web 18 | ~~~ 19 | 20 | 21 | ### Contributors 22 | 23 | - [Lukasz Cepowski](http://lukasz.cepowski.com) 24 | 25 | *** 26 | 27 | 28 | -------------------------------------------------------------------------------- /tutorial/index.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "lessons": [ 4 | { 5 | "title": "001. Hello World", 6 | "description": "Create the simplest application with Dojo Toolkit, show the dijit Dialog widget, use AMD to load the app module.", 7 | "page": "001/hello-world", 8 | "thumb": "/assets/thumbs/001.png", 9 | "demoUrl": "http://demo.dojotutorial.org/001-hello-world/", 10 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/001-hello-world" 11 | }, 12 | 13 | { 14 | "title": "002. Button Click", 15 | "description": "Display dijit Button widget and handle onClick event.", 16 | "page": "002/button-click", 17 | "thumb": "/assets/thumbs/002.png", 18 | "demoUrl": "http://demo.dojotutorial.org/002-button-click/", 19 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/002-button-click" 20 | }, 21 | 22 | { 23 | "title": "003. Dialog", 24 | "description": "Display dijit Dialog widget with remote content.", 25 | "page": "003/dialog", 26 | "thumb": "/assets/thumbs/003.png", 27 | "demoUrl": "http://demo.dojotutorial.org/003-dialog/", 28 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/003-dialog" 29 | }, 30 | 31 | { 32 | "title": "004. Menubar", 33 | "description": "Display menubar with icons and handle onClick event.", 34 | "page": "004/menubar", 35 | "thumb": "/assets/thumbs/004.png", 36 | "demoUrl": "http://demo.dojotutorial.org/004-menubar/", 37 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/004-menubar" 38 | }, 39 | 40 | { 41 | "title": "005. Context Menu", 42 | "description": "Display custom context menu on right mouse button click.", 43 | "page": "005/contextmenu", 44 | "thumb": "/assets/thumbs/005.png", 45 | "demoUrl": "http://demo.dojotutorial.org/005-contextmenu/", 46 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/005-contextmenu" 47 | }, 48 | 49 | { 50 | "title": "006. Layout", 51 | "description": "Rich Internet Application layout with dijit BorderContainer.", 52 | "page": "006/layout", 53 | "thumb": "/assets/thumbs/006.png", 54 | "demoUrl": "http://demo.dojotutorial.org/006-layout/", 55 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/006-layout" 56 | }, 57 | 58 | { 59 | "title": "007. Custom Alert Dialog", 60 | "description": "Create custom Dojo widget, an AlertDialog.", 61 | "page": "007/custom-alert-dialog", 62 | "thumb": "/assets/thumbs/007.png", 63 | "demoUrl": "http://demo.dojotutorial.org/007-custom-alert-dialog/", 64 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/007-custom-alert-dialog" 65 | }, 66 | 67 | { 68 | "title": "008. Custom Confirm Dialog", 69 | "description": "Create custom ConfirmDialog widget with programmable buttons.", 70 | "page": "008/custom-confirm-dialog", 71 | "thumb": "/assets/thumbs/008.png", 72 | "demoUrl": "http://demo.dojotutorial.org/008-custom-confirm-dialog/", 73 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/008-custom-confirm-dialog" 74 | }, 75 | 76 | { 77 | "title": "009. Form", 78 | "description": "Build responsive forms with dijit Form and dojox TableContainer.", 79 | "page": "009/form", 80 | "thumb": "/assets/thumbs/009.png", 81 | "demoUrl": "http://demo.dojotutorial.org/009-form/", 82 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/009-form" 83 | }, 84 | 85 | { 86 | "title": "010. Form validation", 87 | "description": "Validate forms with dojox validate, create custom validator.", 88 | "page": "010/form-validation", 89 | "thumb": "/assets/thumbs/010.png", 90 | "demoUrl": "http://demo.dojotutorial.org/010-form-validation/", 91 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/010-form-validation" 92 | }, 93 | 94 | { 95 | "title": "011. Ajax form validator", 96 | "description": "Create custom dojo form text box widget with server based ajax validation.", 97 | "page": "011/ajax-form-validator", 98 | "thumb": "/assets/thumbs/011.png", 99 | "demoUrl": "http://demo.dojotutorial.org/011-form-ajax-validator/", 100 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/011-form-ajax-validator" 101 | }, 102 | 103 | 104 | { 105 | "title": "012. Login form dialog", 106 | "description": "Display login form on a custom dialog and send Ajax requests with form data.", 107 | "page": "012/login-form-dialog", 108 | "thumb": "/assets/thumbs/012.png", 109 | "demoUrl": "http://demo.dojotutorial.org/012-login-form-dialog/", 110 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/012-login-form-dialog" 111 | }, 112 | 113 | { 114 | "title": "013. Dojo AMD", 115 | "description": "How to use Dojo loader, integrate Dojo with external libs like jQuery and Handlebars.", 116 | "page": "013/dojo-amd", 117 | "thumb": "/assets/thumbs/013.png", 118 | "demoUrl": "http://demo.dojotutorial.org/013-dojo-amd/", 119 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/013-dojo-amd" 120 | }, 121 | 122 | { 123 | "title": "014. MVC form", 124 | "description": "Simple MVC application, create a controller to handle a form in a view.", 125 | "page": "014/mvc-form", 126 | "thumb": "/assets/thumbs/014.png", 127 | "demoUrl": "http://demo.dojotutorial.org/014-mvc-form/", 128 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/014-mvc-form" 129 | }, 130 | 131 | { 132 | "title": "015. Grid", 133 | "description": "Build simplest Dojo grid.", 134 | "page": "015/grid", 135 | "thumb": "/assets/thumbs/015.png", 136 | "demoUrl": "http://demo.dojotutorial.org/015-grid/", 137 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/015-grid" 138 | }, 139 | 140 | { 141 | "title": "016. Dynamic grid", 142 | "description": "Create grid instance on fly and display it in a tab.", 143 | "page": "016/dynamic-grid", 144 | "thumb": "/assets/thumbs/016.png", 145 | "demoUrl": "http://demo.dojotutorial.org/016-dynamic-grid/", 146 | "githubUrl": "https://github.com/cepa/dojo-tutorial/tree/master/016-dynamic-grid" 147 | } 148 | 149 | ] 150 | 151 | } --------------------------------------------------------------------------------