├── .gitignore ├── sass ├── config.rb ├── example │ ├── theme.html │ ├── fashion.html │ └── render.js └── src │ └── Application.scss ├── app.js ├── app ├── Application.js └── view │ └── main │ ├── Main.js │ ├── MainViewModel.js │ ├── FilterForm.js │ ├── MainViewController.js │ ├── Hero.js │ └── Devcards.js ├── index.html ├── README.md ├── workspace.json ├── app.json └── resources └── devs.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | ext/ 3 | build/ 4 | bootstrap.* -------------------------------------------------------------------------------- /sass/config.rb: -------------------------------------------------------------------------------- 1 | cur_dir = File.dirname(__FILE__) 2 | output_style = :nested 3 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | Ext.application({ 2 | extend: 'MyApp.Application', 3 | name: 'MyApp' 4 | }); 5 | -------------------------------------------------------------------------------- /app/Application.js: -------------------------------------------------------------------------------- 1 | Ext.define('MyApp.Application', { 2 | extend: 'Ext.app.Application', 3 | namespace: 'MyApp', 4 | 5 | requires: [ 6 | 'MyApp.*' 7 | ], 8 | 9 | // The name of the initial view to create. With the classic toolkit this class 10 | // will gain a "viewport" plugin if it does not extend Ext.Viewport. With the 11 | // modern toolkit, the main view will be added to the Viewport. 12 | // 13 | mainView: 'MyApp.view.main.Main' 14 | }); 15 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Modern Tutorial 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/view/main/Main.js: -------------------------------------------------------------------------------- 1 | Ext.define('MyApp.view.main.Main', { 2 | extend: 'Ext.Container', 3 | controller: 'main', 4 | viewModel: 'main', 5 | 6 | // list the classes required by the Main class so that 7 | // Cmd loads them ahead of this class when building the app 8 | requires: [ 9 | 'MyApp.view.main.Hero', 10 | 'MyApp.view.main.Devcards', 11 | 'MyApp.view.main.MainViewController', 12 | 'MyApp.view.main.MainViewModel' 13 | ], 14 | 15 | layout: { 16 | type: 'card', 17 | animation: { 18 | type: 'slide', 19 | direction: 'up' 20 | } 21 | }, 22 | 23 | items: [{ 24 | // our hero (landing) page that we’ll define later 25 | xtype: 'hero' 26 | }, { 27 | // our developer list / details cards that we’ll define later 28 | xtype: 'devcards' 29 | }] 30 | }); -------------------------------------------------------------------------------- /sass/example/theme.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Ext JS Theme Harness 8 | 9 | 10 | 11 | 14 | 15 | 16 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/view/main/MainViewModel.js: -------------------------------------------------------------------------------- 1 | Ext.define('MyApp.view.main.MainViewModel', { 2 | extend: 'Ext.app.ViewModel', 3 | alias: 'viewmodel.main', // the alias for this view model 4 | 5 | // the initial values for our views' data bindings 6 | data: { 7 | extjs: true, 8 | touch: true, 9 | architect: true, 10 | themer: true, 11 | inspector: true, 12 | devsCount: 0 13 | }, 14 | stores: { 15 | // the 'devs' store is described here and 16 | // used via binding by our developers List 17 | devs: { 18 | autoLoad: true, // load the data immediately 19 | proxy: { 20 | type: 'ajax', 21 | // the URL for our remote data 22 | url: 'resources/devs.json', 23 | reader: { 24 | type: 'json', 25 | // the root property from which all of our data is read 26 | rootProperty: 'results' 27 | } 28 | }, 29 | // a load event listener used to communicate 30 | // how many records were read in 31 | listeners: { 32 | load: 'onDevsLoad' 33 | } 34 | } 35 | } 36 | }); -------------------------------------------------------------------------------- /sass/example/fashion.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Ext JS Theme Harness 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Taking the Modern Tutorial to Production 2 | 3 | Let's walk through the steps of creating the app we've been working on above in a real world environment. 4 | 5 | ##Download the Ext JS Framework 6 | 7 | If you have not already done so, download and unpack the Ext JS framework from either the Products section 8 | of the main Sencha website [sencha.com](www.sencha.com) or from the downloads section of the Sencha Support portal. 9 | 10 | ##Add Cmd to your App 11 | 12 | Once you have your application where you want it, "cd" into its directory in your Command Line Interface (CLI). Then, 13 | issue the following command: 14 | 15 | sencha app install --framework=/path/to/extjs/ 16 | 17 | This command will wrap your app code folder with a Sencha Cmd framework that allows your application to benefit 18 | from Cmd's many features. 19 | 20 | **Note:** "/path/to/extjs/" should be replaced with the path to wherever you unzipped the Ext JS framework on your machine. 21 | 22 | **Hint:** If you're having trouble getting Sencha Cmd installed, see the following Cmd Starter Overview. 23 | 24 | ##Download the Sample Application 25 | Download the contents of this repository that we're currently in. 26 | 27 | ##Move Zip to Application 28 | Copy the contents of the downloaded application into the ModernTutorial folder. 29 | 30 | ##Build Your Application 31 | Finally, cd into your ModernTutorial folder and run: 32 | 33 | sencha app build 34 | 35 | You can now visit your application at its local address on your web server. You can also run this command so 36 | that Cmd will generate a web server for you: 37 | 38 | sencha app watch 39 | 40 | You can now visit the resulting address displayed in your console. It will usually be found here: 41 | 42 | http://localhost:1841 43 | -------------------------------------------------------------------------------- /workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * An object containing key value pair framework descriptors. 4 | * 5 | * The value can be a string or an object containing at least one of "dir" or "pkg", 6 | * where "dir" can be a filesystem path to the framework sources and "pkg" can be a 7 | * package name. For example: 8 | * 9 | * "frameworks": { 10 | * 11 | * "ext-x": "/absolute/path/to/ext", 12 | * "ext-y": { 13 | * "source": "../relative/path/to/ext", 14 | * "path": "ext" 15 | * }, 16 | * "ext-z": { 17 | * "package": "ext@n.n.n", 18 | * "path": "ext-n.n.n" 19 | * }, 20 | * "touch": "touch" 21 | * } 22 | * 23 | */ 24 | "frameworks": { 25 | "ext": { 26 | "path":"ext", 27 | "version":"7.0.0.116" 28 | } 29 | 30 | 31 | }, 32 | 33 | /** 34 | * This is the folder for build outputs in the workspace. 35 | */ 36 | "build": { 37 | "dir": "${workspace.dir}/build" 38 | }, 39 | 40 | /** 41 | * These configs determine where packages are generated and extracted to (when downloaded). 42 | */ 43 | "packages": { 44 | /** 45 | * This folder contains all local packages. 46 | * If a comma-separated string is used as value the first path will be used as the path to generate new packages. 47 | */ 48 | "dir": "${workspace.dir}/packages/local,${workspace.dir}/packages", 49 | 50 | /** 51 | * This folder contains all extracted (remote) packages. 52 | */ 53 | "extract": "${workspace.dir}/packages/remote" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/view/main/FilterForm.js: -------------------------------------------------------------------------------- 1 | Ext.define('MyApp.view.main.FilterForm', { 2 | extend: 'Ext.form.Panel', 3 | xtype: 'filterform', // the alias used by the List and its Container 4 | // configuration options set in the defaults config will be applied 5 | // to all child components in the items array below (unless a config is 6 | // overridden explicitly in an item's config) 7 | defaults: { 8 | xtype: 'checkboxfield', 9 | labelWidth: 100, 10 | // we'll go ahead and point to a checkbox change handler method that 11 | // we'll author later in the guide for filtering the developer List 12 | listeners: { 13 | change: 'onFilterChange' 14 | } 15 | }, 16 | cls: 'filter-form', 17 | bodyPadding: 8, 18 | items: [ 19 | { 20 | xtype: 'titlebar', 21 | title: 'Filter By', 22 | docked: 'top', 23 | platformConfig: { 24 | '!phone': { 25 | hidden: true 26 | } 27 | }, 28 | items: { 29 | xtype: 'button', 30 | iconCls: 'md-icon-close', 31 | align: 'right', 32 | listeners: { 33 | tap: 'onFilterMenuCloseButtonTap' 34 | } 35 | } 36 | }, 37 | { 38 | // each checkboxfield has a form field label corresponding to the 39 | // skill it will filter by. Additionally, we'll set up the data 40 | // binding to point to a data value on the main View Model we'll 41 | // describe a bit later in the tutorial 42 | label: 'Ext JS', 43 | bind: { 44 | checked: '{extjs}' 45 | } 46 | }, { 47 | label: 'Touch', 48 | bind: { 49 | checked: '{touch}' 50 | } 51 | }, { 52 | label: 'Architect', 53 | bind: { 54 | checked: '{architect}' 55 | } 56 | }, { 57 | label: 'Themer', 58 | bind: { 59 | checked: '{themer}' 60 | } 61 | }, { 62 | label: 'Inspector', 63 | bind: { 64 | checked: '{inspector}' 65 | } 66 | }] 67 | }); -------------------------------------------------------------------------------- /app/view/main/MainViewController.js: -------------------------------------------------------------------------------- 1 | Ext.define('MyApp.view.main.MainViewController', { 2 | extend: 'Ext.app.ViewController', 3 | alias: 'controller.main', 4 | 5 | onFilterMenuButtonTap: function() { 6 | var filtersMenu = this.lookup('filters'); 7 | filtersMenu.show(); 8 | }, 9 | 10 | onFilterMenuCloseButtonTap: function() { 11 | var filtersMenu = this.lookup('filters'); 12 | filtersMenu.hide(); 13 | }, 14 | 15 | onGetStarted: function() { 16 | this.getView().setActiveItem(1); 17 | }, 18 | 19 | // when a developer item is tapped in the developer List 20 | // 1) set the record of the developer tapped on the View Model 21 | // 2) show the developer details view 22 | onDevTap: function(list, i, el, rec) { 23 | this.getViewModel().set('dev', rec); 24 | var active = this.lookup('devcards').animateActiveItem(1, 'slide'); 25 | if (active.rec !== rec) { 26 | active.down('tabpanel').setActiveItem(0); 27 | } 28 | active.rec = rec; 29 | }, 30 | 31 | // return to the developers list from the details view 32 | showDevList: function () { 33 | this.lookup('devcards').animateActiveItem(0, {type: 'slide', direction: 'right'}); 34 | }, 35 | 36 | // any change to the filter checkboxes will update the filtering 37 | // applied to the developers List store using the checked skills 38 | // we've used the Ext.function.createBuffered method to handle 39 | // rapidly fired checkbox change events in a controlled manner 40 | // - a byproduct of having two filter forms operating in sync 41 | onFilterChange: Ext.Function.createBuffered(function() { 42 | var devsStore = this.lookup('devslist').getStore(), 43 | vm = this.getViewModel(), 44 | allFilters = ['extjs', 'touch', 'architect', 'themer', 'inspector'], 45 | filters = []; 46 | 47 | // collect up an array of checked checkboxes 48 | Ext.each(allFilters, function(item) { 49 | if (vm.get(item)) { 50 | filters.push(item); 51 | } 52 | }); 53 | 54 | // clear any filtering on the Store 55 | devsStore.clearFilter(); 56 | // if there are any checkboxes checked 57 | if (filters.length) { 58 | // filter the developers Store using only the checked filters 59 | devsStore.filterBy(function(rec) { 60 | var skills = Ext.Array.map(rec.get('skills'), function(item) { 61 | return item.toLowerCase().replace(/ /g, ''); 62 | }); 63 | 64 | return Ext.Array.intersect(filters, skills).length; 65 | }); 66 | } 67 | }, 10), 68 | 69 | // when the developers Store loads update the 'devsCount' value on the 70 | // View Model in order to update the developers count on the Hero page 71 | onDevsLoad: function(store) { 72 | this.getViewModel().set('devsCount', store.getCount()); 73 | } 74 | }); -------------------------------------------------------------------------------- /app/view/main/Hero.js: -------------------------------------------------------------------------------- 1 | Ext.define('MyApp.view.main.Hero', { 2 | extend: 'Ext.container.Container', 3 | // the component reference name used when instantiating our hero component in the top-level carousel 4 | xtype: 'hero', 5 | 6 | // not needed out of the box, but helpful when it comes to styling the hero component 7 | cls: 'hero-card', 8 | // vertical / centered container layout for all child items 9 | layout: { 10 | type: 'vbox', 11 | align: 'center' 12 | }, 13 | items: [{ 14 | // a transparent container used to help with layout allowing the user Login button 15 | // to float to the right of the app while the remaining content is centered 16 | xtype: 'container', 17 | layout: 'hbox', 18 | width: '100%', 19 | padding: '12 16', 20 | items: [{ 21 | // in an hbox layout the flex: 1 configuration forces additional components 22 | // to the right by taking up all available space 23 | xtype: 'component', 24 | flex: 1 25 | }, { 26 | // our button used for login 27 | xtype: 'button', 28 | // here we'll set the data binding for the button text and icon 29 | // (covered later in the guide) 30 | bind: { 31 | text: '{loginText}', 32 | iconCls: '{userCls}' 33 | }, 34 | // a CSS class used for custom styling of the button 35 | cls: 'clear-white', 36 | // we'll go ahead and set a handler on the button for when it's tapped. The logic 37 | // used to handle the button tap will come later when we set up the main view's View Controller 38 | handler: 'onLoginPress' 39 | }] 40 | }, { 41 | // in a vbox layout the flex: 1 configuration forces additional components 42 | // down by taking up all available space 43 | xtype: 'component', 44 | flex: 1 45 | }, { 46 | // our hero page title 47 | xtype: 'component', 48 | html: 'Sencha Devs', 49 | cls: 'hero-card-title' 50 | }, { 51 | // our hero page description / tagline 52 | xtype: 'component', 53 | html: 'Worldwide Sencha developers database. Find your developer here.', 54 | padding: 10, 55 | cls: 'hero-card-sub-title' 56 | }, { 57 | // the button used to navigate to the developers list 58 | xtype: 'button', 59 | text: 'Get Started', 60 | iconCls: 'x-fa fa-arrow-circle-o-down', 61 | cls: 'get-started', 62 | margin: '60 0 0 0', 63 | handler: 'onGetStarted' 64 | }, { 65 | xtype: 'component', 66 | flex: 1 67 | }, { 68 | // display a count of all available developers. We'll set up the logic that 69 | // displays this count further in the guide 70 | xtype: 'component', 71 | bind: { 72 | html: 'Devs: {devsCount}' 73 | }, 74 | cls: 'dev-count', 75 | padding: 12 76 | }] 77 | }); -------------------------------------------------------------------------------- /sass/src/Application.scss: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Raleway:400,600,500,300,700|Lato:400,700"); 2 | 3 | /* VP Modal Mask */ 4 | #ext-viewport > .x-body > .x-mask { 5 | opacity: .4; 6 | background-color: #fff; 7 | } 8 | 9 | /* Buttons */ 10 | .clear-white { 11 | background-color: transparent; 12 | border-color: transparent; 13 | color: white; 14 | } 15 | 16 | .clear-white .x-button-icon { 17 | color: white; 18 | } 19 | 20 | .clear-white.x-button.x-button-pressing, 21 | .clear-white.x-button.x-button-pressed { 22 | color: #919191; 23 | background-color: transparent; 24 | border-color: transparent; 25 | } 26 | 27 | .clear-white.x-button.x-button-pressing .x-button-icon, 28 | .clear-white.x-button.x-button-pressed .x-button-icon { 29 | color: #919191; 30 | } 31 | 32 | /* Hero Card */ 33 | .hero-card { 34 | background: #3e536d url(https://s3.amazonaws.com/uploads.hipchat.com/9804/276555/WpAlblU22yspraZ/hero-bg3.jpg) no-repeat center bottom; 35 | background-size: cover; 36 | } 37 | 38 | .hero-card-title { 39 | text-align: center; 40 | color: white; 41 | font-size: 80px; 42 | line-height: 80px; 43 | font-family: Raleway; 44 | font-weight: 500; 45 | } 46 | 47 | .hero-card-sub-title { 48 | text-align: center; 49 | color: white; 50 | font-size: 36px; 51 | font-family: Raleway; 52 | font-weight: 300; 53 | } 54 | 55 | .get-started { 56 | font-size: 2em; 57 | opacity: .3; 58 | border-radius: 32px; 59 | background: #1d1d1d; 60 | color: #bdbdbd; 61 | } 62 | 63 | .get-started .x-button-icon { 64 | color: #777777; 65 | } 66 | 67 | .dev-count { 68 | color: white; 69 | font-size: 16px; 70 | } 71 | 72 | .dev-count-label { 73 | color: #bdbdbd; 74 | text-transform: uppercase; 75 | letter-spacing: 2px; 76 | font-size: 13px; 77 | } 78 | 79 | /* Filter Form */ 80 | .filter-form { 81 | z-index: 10; 82 | } 83 | 84 | .filter-form-left { 85 | border-right: 1px solid #e6e6e6 !important; 86 | } 87 | 88 | /* Devs List */ 89 | 90 | .list-item-dev { 91 | display: -webkit-box; 92 | display: flex; 93 | -webkit-flex-direction: row; 94 | flex-direction: row; 95 | 96 | } 97 | .list-item-image { 98 | border: 3px solid #efefef; 99 | float: left; 100 | height: 48px; 101 | width: 48px; 102 | border-radius: 50%; 103 | margin: 10px 20px 0 0; 104 | } 105 | 106 | .list-item-name { 107 | font-size: 24px; 108 | line-height: 32px; 109 | color: #404040; 110 | } 111 | 112 | .list-item-skill-tag, 113 | .dev-card-skill-tag { 114 | display: inline-block; 115 | padding: 3px 6px; 116 | border-radius: 3px; 117 | background-color: #ef359a; 118 | color: #f5f5f5; 119 | margin: 6px 6px 0 0; 120 | font-family: Lato; 121 | } 122 | 123 | /* Dev Card */ 124 | .dev-card-image { 125 | border-radius: 50%; 126 | width: 128px; 127 | height: 128px; 128 | border: 6px solid #bfbfbf; 129 | } 130 | 131 | .dev-card-name { 132 | font-size: 24px; 133 | line-height: 32px; 134 | color: #8a8a8a; 135 | } 136 | 137 | .dev-card-info, 138 | .dev-card-contact { 139 | font-size: 16px; 140 | color: #4a4a4a; 141 | } 142 | 143 | .dev-card-divider { 144 | background-image: repeating-linear-gradient(45deg,#fafafa,#fafafa 5px,#dcdcdc 5px,#dcdcdc 7px); 145 | } 146 | 147 | .dev-card-skills-ct { 148 | background-color: #efefef; 149 | padding: 8px 4px; 150 | margin-top: 16px; 151 | } 152 | /* .dev-card-skill-tag see above */ 153 | 154 | -------------------------------------------------------------------------------- /app/view/main/Devcards.js: -------------------------------------------------------------------------------- 1 | Ext.define('MyApp.view.main.Devcards', { 2 | extend: 'Ext.container.Container', 3 | xtype: 'devcards', 4 | 5 | // list the classes required by this class 6 | requires: ['MyApp.view.main.FilterForm'], 7 | 8 | // the card layout displays one view at a time from the items array. Think of a tab 9 | // panel where the views are shown programmatically -vs- using tabs in a tab bar 10 | layout: { 11 | type: 'card', 12 | animation: 'slide' 13 | }, 14 | // we'll set a reference config for easy access to this container from within our 15 | // view controller logic we'll define further on in the guide 16 | reference: 'devcards', 17 | items: [{ 18 | // a container to horizontally lay out the developers list and filter 19 | // form in landscape mode and just the list (with its child filter form) 20 | // when oriented in portrait 21 | xtype: 'container', 22 | layout: { 23 | type: 'hbox', 24 | align: 'stretch' 25 | }, 26 | items: [{ 27 | xtype: 'titlebar', 28 | title: 'Developers', 29 | docked: 'top', 30 | items: { 31 | iconCls: 'md-icon-filter-list', 32 | align: 'right', 33 | platformConfig: { 34 | '!phone': { 35 | hidden: true 36 | } 37 | }, 38 | listeners: { 39 | tap: 'onFilterMenuButtonTap' 40 | } 41 | } 42 | }, { 43 | // 'filterform' is the xtype of a custom component we'll 44 | // define in the next part of the guide 45 | xtype: 'filterform', 46 | reference: 'filters', 47 | platformConfig: { 48 | phone: { 49 | floated: true, 50 | width: '100%', 51 | height: '100%', 52 | showAnimation: { 53 | type: 'slide', 54 | direction: 'down' 55 | }, 56 | hideAnimation: { 57 | type: 'slideOut', 58 | direction: 'up' 59 | } 60 | }, 61 | '!phone': { 62 | width: 150, 63 | cls: 'filter-form-left' 64 | } 65 | } 66 | }, { 67 | // List components are great ways to show a column of data using a 68 | // user-define HTML template 69 | xtype: 'list', 70 | reference: 'devslist', 71 | striped: true, // striped to tint every other row 72 | disableSelection: true, // disable row selection for this app 73 | flex: 1, // take up available horizontal space 74 | minWidth: 300, 75 | itemTpl: '
' + 76 | '' + 77 | '
' + 78 | '
{name.first:capitalize} {name.last:capitalize}
' + 79 | '' + 80 | '
{.}
' + 81 | '
' + 82 | '
' + 83 | '
', 84 | // we'll get the data Store for the List component from the 85 | // ancestor container's View Model. We'll set that up a bit 86 | // later in the guide. 87 | bind: { 88 | store: '{devs}' 89 | }, 90 | // When we set up the tap event handler logic this listener 91 | // will cause tapping on a developer to show its details view 92 | listeners: { 93 | itemtap: 'onDevTap' 94 | } 95 | }] 96 | }, { 97 | xtype: 'container', 98 | // vertically lay out all child items and center them 99 | layout: { 100 | type: 'vbox', 101 | align: 'center' 102 | }, 103 | items: [{ 104 | xtype: 'toolbar', 105 | // docked positions a component above or below all other items 106 | docked: 'top', 107 | items: [{ 108 | // button to navigate back to the developers list 109 | // note that toolbars’ default child item type is button 110 | // so we didn’t have to specify the xtype 111 | text: 'Dev List', 112 | handler: 'showDevList' 113 | }] 114 | }, { 115 | // a larger developer avatar image 116 | xtype: 'component', 117 | bind: { 118 | html: '' 119 | }, 120 | margin: 20 121 | }, { 122 | // the developer's full name 123 | xtype: 'component', 124 | bind: { 125 | html: '
{dev.name.first:capitalize} {dev.name.last:capitalize}
' 126 | }, 127 | margin: '0 0 20 0' 128 | }, { 129 | // a Tab Panel displaying: 130 | // 1) a developer bio and Sencha skills 131 | // 2) contact information 132 | xtype: 'tabpanel', 133 | width: '100%', // take up all available width 134 | flex: 1, 135 | items: [{ 136 | // the developer bio and skills tab 137 | title: 'Info', 138 | scrollable: 'vertical', 139 | padding: 20, 140 | cls: 'dev-card-info', 141 | defaults: { 142 | xtype: 'component', 143 | margin: '0 0 10 0' 144 | }, 145 | items: [{ 146 | html: 'Registered since: July 12, 2013', 147 | margin: '0 0 29 0' 148 | }, { 149 | // dummy bio 150 | html: '

Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts.


Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean.


A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.


Even the all-powerful Pointing has no control about the blind texts it is an almost unorthographic life One day however a small line of blind text by the name of Lorem Ipsum decided to

' 151 | }, { 152 | bind: { 153 | data: '{dev.skills}' 154 | }, 155 | tpl: '
{.}
' 156 | }] 157 | }, { 158 | // the contact tab using data from the developer record 159 | title: 'Contact', 160 | padding: 20, 161 | scrollable: 'vertical', 162 | cls: 'dev-card-contact', 163 | bind: { 164 | html: 'e-mail: {dev.email}

phone: {dev.cell}

Loc: {dev.location.city:capitalize}, {dev.location.state:capitalize}   {dev.nat:uppercase}' 165 | } 166 | }] 167 | }] 168 | }] 169 | }); 170 | -------------------------------------------------------------------------------- /sass/example/render.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is generated by Sencha Cmd and should NOT be edited. It will be replaced 3 | * during an upgrade. 4 | */ 5 | 6 | // This flag is checked by many Components to avoid compatibility warnings when 7 | // the code is running under the slicer 8 | Ext.slicer = true; 9 | 10 | Ext.require([ 11 | 'Ext.layout.Context' 12 | ]); 13 | 14 | Ext.theme = Ext.apply(Ext.theme || {}, { 15 | /** 16 | * The array of all component manifests. These objects have the following set of 17 | * properties recognized by the slicer: 18 | * @private 19 | */ 20 | _manifest: [], 21 | 22 | /** 23 | * The collection of shortcuts for a given alias (e.g., 'widget.panel'). This is an 24 | * object keyed by alias whose values are arrays of shortcut definitions. 25 | * @private 26 | */ 27 | _shortcuts: {}, 28 | 29 | doRequire : function(xtype) { 30 | if(xtype.indexOf("widget.") != 0) { 31 | xtype = "widget." + xtype; 32 | } 33 | Ext.require([xtype]); 34 | }, 35 | 36 | /** 37 | * Adds one ore more component entries to the theme manifest. These entries will be 38 | * instantiated by the `Ext.theme.render` method when the page is ready. 39 | * 40 | * Usage: 41 | * 42 | * Ext.theme.addManifest({ 43 | * xtype: 'widget.menu', 44 | * folder: 'menu', 45 | * delegate: '.x-menu-item-link', 46 | * filename: 'menu-item-active', 47 | * config: { 48 | * floating: false, 49 | * width: 200, 50 | * items: [{ 51 | * text: 'test', 52 | * cls: 'x-menu-item-active' 53 | * }] 54 | * } 55 | * },{ 56 | * //... 57 | * }); 58 | * 59 | * @param manifest {Object} An object with type of component, slicing information and 60 | * component configuration. If this parameter is an array, each element is treated as 61 | * a manifest entry. Otherwise, each argument passed is treated as a manifest entry. 62 | * 63 | * @param manifest.xtype {String} The xtype ('grid') or alias ('widget.grid'). This 64 | * is used to specify the type of component to create as well as a potential key to 65 | * any `shortcuts` defined for the xtype. 66 | * 67 | * @param manifest.config {Object} The component configuration object. The properties 68 | * of this depend on the `xtype` of the component. 69 | * 70 | * @param [manifest.delegate] {String} The DOM query to use to select the element to 71 | * slice. The default is to slice the primary element of the component. 72 | * 73 | * @param [manifest.parentCls] An optional CSS class to add to the parent of the 74 | * component. 75 | * 76 | * @param [manifest.setup] {Function} An optional function to be called to initialize 77 | * the component. 78 | * @param manifest.setup.component {Ext.Component} The component instance 79 | * @param manifest.setup.container {Element} The component's container. 80 | * 81 | * @param [manifest.folder] {String} The folder in to which to produce image slices. 82 | * Only applies to Ext JS 4.1 (removed in 4.2). 83 | * 84 | * @param [manifest.filename] {String} The base filename for slices. 85 | * Only applies to Ext JS 4.1 (removed in 4.2). 86 | * 87 | * @param [manifest.reverse] {Boolean} True to position the slices for linear gradient 88 | * background at then opposite "end" (right or bottom) and apply the stretch to the 89 | * area before it (left or top). Only applies to Ext JS 4.1 (removed in 4.2). 90 | */ 91 | addManifest: function (manifest) { 92 | var all = Ext.theme._manifest; 93 | var add = Ext.isArray(manifest) ? manifest : arguments; 94 | 95 | if(manifest.xtype) { 96 | Ext.theme.doRequire(manifest.xtype); 97 | } 98 | 99 | for (var i = 0, n = add.length; i < n; ++i) { 100 | if(add[i].xtype) { 101 | Ext.theme.doRequire(add[i].xtype); 102 | } 103 | all.push(add[i]); 104 | } 105 | }, 106 | 107 | /** 108 | * Adds one or more shortcuts to the rendering process. A `shortcut` is an object that 109 | * looks the same as a `manifest` entry. These are combined by copying the properties 110 | * from the shortcut over those of the manifest entry. In basic terms: 111 | * 112 | * var config = Ext.apply(Ext.apply({}, manfiest.config), shortcut.config); 113 | * var entry = Ext.apply(Ext.apply({}, manfiest), shortcut); 114 | * entry.config = config; 115 | * 116 | * This is not exactly the process, but the idea is the same. The difference is that 117 | * the `ui` of the manifest entry is used to replace any `"{ui}"` substrings found in 118 | * any string properties of the shortcut or its `config` object. 119 | * 120 | * Usage: 121 | * 122 | * Ext.theme.addShortcuts({ 123 | * 'widget.foo': [{ 124 | * config: { 125 | * } 126 | * },{ 127 | * config: { 128 | * } 129 | * }], 130 | * 131 | * 'widget.bar': [ ... ] 132 | * }); 133 | */ 134 | addShortcuts: function (shortcuts) { 135 | var all = Ext.theme._shortcuts; 136 | 137 | for (var key in shortcuts) { 138 | 139 | var add = shortcuts[key]; 140 | var xtype = Ext.theme.addWidget(key); 141 | var existing = all[xtype]; 142 | 143 | Ext.theme.doRequire(xtype); 144 | for(var i=0; i < add.length; i++) { 145 | var config = add[i]; 146 | if(config.xtype) { 147 | Ext.theme.doRequire(config.xtype); 148 | } 149 | } 150 | 151 | if (!existing) { 152 | all[xtype] = existing = []; 153 | } 154 | 155 | existing.push.apply(existing, add); 156 | } 157 | }, 158 | 159 | /** 160 | * This method ensures that a given string has the specified prefix (e.g., "widget."). 161 | * @private 162 | */ 163 | addPrefix: function (prefix, s) { 164 | if (!s || (s.length > prefix.length && s.substring(0,prefix.length) === prefix)) { 165 | return s; 166 | } 167 | return prefix + s; 168 | }, 169 | 170 | /** 171 | * This method returns the given string with "widget." added to the front if that is 172 | * not already present. 173 | * @private 174 | */ 175 | addWidget: function (str) { 176 | return Ext.theme.addPrefix('widget.', str); 177 | }, 178 | 179 | /** 180 | * This method accepts an manifest entry and a shortcut entry and returns the merged 181 | * version. 182 | * @private 183 | */ 184 | applyShortcut: function (manifestEntry, shortcut) { 185 | var ui = manifestEntry.ui; 186 | var config = Ext.theme.copyProps({}, manifestEntry.config); 187 | var entry = Ext.theme.copyProps({}, manifestEntry); 188 | 189 | if (ui && !config.ui) { 190 | config.ui = ui; 191 | } 192 | if (shortcut) { 193 | var tpl = { ui: ui }; 194 | Ext.theme.copyProps(entry, shortcut, tpl); 195 | Ext.theme.copyProps(config, shortcut.config, tpl); 196 | } 197 | 198 | entry.xtype = Ext.theme.addWidget(entry.xtype); 199 | entry.config = config; // both guys have "config" so smash merged one on now... 200 | return entry; 201 | }, 202 | 203 | /** 204 | * This method copies property from a `src` object to a `dest` object and reaplces 205 | * `"{foo}"` fragments of any string properties as defined in the `tpl` object. 206 | * 207 | * var obj = Ext.theme.copyProps({}, { 208 | * foo: 'Hello-{ui}' 209 | * }, { 210 | * ui: 'World' 211 | * }); 212 | * 213 | * console.log('obj.foo: ' + obj.foo); // logs "Hello-World" 214 | * 215 | * @return {Object} The `dest` object or a new object (if `dest` was null). 216 | * @private 217 | */ 218 | copyProps: function (dest, src, tpl) { 219 | var out = dest || {}; 220 | var replacements = []; 221 | var token; 222 | 223 | if (src) { 224 | if (tpl) { 225 | for (token in tpl) { 226 | replacements.push({ 227 | re: new RegExp('\\{' + token + '\\}', 'g'), 228 | value: tpl[token] 229 | }); 230 | } 231 | } 232 | 233 | for (var key in src) { 234 | var val = src[key]; 235 | if (tpl && typeof val === 'string') { 236 | for (var i = 0; i < replacements.length; ++ i) { 237 | val = val.replace(replacements[i].re, replacements[i].value); 238 | } 239 | } 240 | out[key] = val; 241 | } 242 | } 243 | 244 | return out; 245 | }, 246 | 247 | /** 248 | * Renders a component given its manifest and shortcut entries. 249 | * @private 250 | */ 251 | renderWidget: function (manifestEntry, shortcut) { 252 | var entry = Ext.theme.applyShortcut(manifestEntry, shortcut); 253 | var config = entry.config; 254 | var widget = Ext.create(entry.xtype, config); 255 | var ct = Ext.fly(document.body).createChild({ cls: 'widget-container' }); 256 | 257 | Ext.theme.currentWidget = widget; 258 | 259 | if (widget.floating === true) { 260 | widget.floating = { shadow: false }; 261 | } 262 | if (widget.floating) { 263 | widget.focusOnToFront = false; 264 | } 265 | 266 | if (entry.setup) { 267 | entry.setup.call(widget, widget, ct); 268 | } else { 269 | widget.render(ct); 270 | if (widget.floating) { 271 | widget.showAt(0, 0); 272 | ct.setHeight(widget.getHeight()); 273 | } 274 | } 275 | 276 | var el = widget.el; 277 | if (entry.delegate) { 278 | el = el.down(entry.delegate); 279 | } 280 | 281 | el.addCls('x-slicer-target'); // this is what generateSlicerManifest looks for 282 | 283 | if (entry.over) { 284 | widget.addOverCls(); 285 | } 286 | if (config.parentCls) { 287 | el.parent().addCls(config.parentCls); 288 | } 289 | 290 | if (Ext.theme.legacy) { 291 | // The 4.1 approach has some interesting extra pieces 292 | // 293 | var data = {}; 294 | if (entry.reverse) { 295 | data.reverse = true; 296 | } 297 | if (entry.filename) { 298 | data.filename = entry.filename; 299 | } 300 | if (entry.folder) { 301 | data.folder = entry.folder; 302 | } 303 | if (entry.offsets) { 304 | data.offsets = entry.offsets; 305 | } 306 | 307 | Ext.theme.setData(el.dom, data); 308 | } 309 | 310 | Ext.theme.currentWidget = null; 311 | }, 312 | 313 | /** 314 | * Renders all of the components that have been added to the manifest. 315 | * @private 316 | */ 317 | render: function () { 318 | console.log("rendering widgets...") 319 | var manifest = Ext.theme._manifest; 320 | var shortcuts = Ext.theme._shortcuts; 321 | 322 | for (var k = 0, n = manifest ? manifest.length : 0; k < n; ++k) { 323 | var manifestEntry = manifest[k]; 324 | var xtype = Ext.theme.addWidget(manifestEntry.xtype); 325 | var widgetShortcuts = xtype ? shortcuts[xtype] : null; 326 | 327 | if (xtype && manifestEntry.ui && widgetShortcuts) { 328 | for (var i = 0; i < widgetShortcuts.length; i++) { 329 | Ext.theme.renderWidget(manifestEntry, widgetShortcuts[i]); 330 | } 331 | } else { 332 | Ext.theme.renderWidget(manifestEntry); 333 | } 334 | } 335 | }, 336 | 337 | /** 338 | * Renders all components (see `render`) and notifies the Slicer that things are ready. 339 | * @private 340 | */ 341 | run: function () { 342 | var extjsVer = Ext.versions.extjs; 343 | var globalData = {}; 344 | 345 | if (Ext.layout.Context) { 346 | Ext.override(Ext.layout.Context, { 347 | run: function () { 348 | var ok = this.callParent(), 349 | widget = Ext.theme.currentWidget; 350 | if (!ok && widget) { 351 | Ext.Error.raise("Layout run failed: " + widget.id); 352 | } 353 | return ok; 354 | } 355 | }); 356 | } 357 | 358 | console.log("loading widget definitions..."); 359 | 360 | // Previous to Ext JS 4.2, themes and their manifests where defined differently. 361 | // So pass this along if we are hosting a pre-4.2 theme. 362 | // 363 | if (extjsVer && extjsVer.isLessThan(new Ext.Version("4.2"))) { 364 | globalData.format = "1.0"; // tell the Slicer tool 365 | Ext.theme.legacy = true; // not for our own data collection 366 | 367 | // Check for the Cmd3.0/ExtJS4.1 variables: 368 | // 369 | if (Ext.manifest && Ext.manifest.widgets) { 370 | Ext.theme.addManifest(Ext.manifest.widgets); 371 | } 372 | if (Ext.shortcuts) { 373 | Ext.theme.addShortcuts(Ext.shortcuts); 374 | } 375 | if (Ext.userManifest && Ext.userManifest.widgets) { 376 | Ext.theme.addManifest(Ext.userManifest.widgets); 377 | } 378 | } 379 | 380 | Ext.theme.setData(document.body, globalData); 381 | Ext.theme.render(); 382 | Ext.theme.generateSlicerManifest(); 383 | }, 384 | 385 | generateSlicerManifest: function() { 386 | var now = new Date().getTime(), 387 | me = Ext.theme, 388 | // This function is defined by slicer.js (the framework-independent piece) 389 | gsm = window && window['generateSlicerManifest'], 390 | delta; 391 | 392 | me.generateStart = me.generateStart || now; 393 | delta = now - me.generateStart; 394 | 395 | if(gsm) { 396 | gsm(); 397 | } else if(delta < (10 * 1000)){ 398 | // allow the outer script wrapper a chance to inject the capture function 399 | // but stop trying after 10 seconds 400 | Ext.defer(Ext.theme.generateSlicerManifest, 100); 401 | } 402 | }, 403 | 404 | /** 405 | * Sets the `data-slicer` attribute to the JSON-encoded value of the provided data. 406 | * @private 407 | */ 408 | setData: function (el, data) { 409 | if (data) { 410 | var json = Ext.encode(data); 411 | if (json !== '{}') { 412 | el.setAttribute('data-slicer', json); 413 | } 414 | } 415 | }, 416 | 417 | /** 418 | * This used to be `loadExtStylesheet`. 419 | * @private 420 | */ 421 | loadCss: function (src, callback) { 422 | var xhr = new XMLHttpRequest(); 423 | 424 | xhr.open('GET', src); 425 | 426 | xhr.onload = function() { 427 | var css = xhr.responseText, 428 | head = document.getElementsByTagName('head')[0], 429 | style = document.createElement('style'); 430 | 431 | // There's bugginess in the next gradient syntax in WebKit r84622 432 | // This might be fixed in a later WebKit, but for now we're going to 433 | // strip it out here since compass generates it. 434 | // 435 | // TODO: Upgrade to later WebKit revision 436 | css = css.replace(/background(-image)?: ?-webkit-linear-gradient(?:.*?);/g, ''); 437 | 438 | style.type = 'text/css'; 439 | style.innerText = css; 440 | 441 | head.appendChild(style); 442 | callback(); 443 | }; 444 | 445 | xhr.send(null); 446 | } 447 | }); 448 | 449 | console.log("registering ready listener..."); 450 | Ext.onReady(Ext.theme.run, Ext.theme); 451 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * The application's namespace. 4 | */ 5 | "name": "MyApp", 6 | 7 | /** 8 | * The version of the application. 9 | */ 10 | "version": "1.0.0.0", 11 | 12 | /** 13 | * The relative path to the application's markup file (html, jsp, asp, etc.). 14 | */ 15 | "indexHtmlPath": "index.html", 16 | 17 | /** 18 | * Comma-separated string with the paths of directories or files to search. Any classes 19 | * declared in these locations will be available in your class "requires" or in calls 20 | * to "Ext.require". The "app.dir" variable below is expanded to the path where the 21 | * application resides (the same folder in which this file is located). 22 | */ 23 | "classpath": [ 24 | "app" 25 | ], 26 | 27 | /** 28 | * Comma-separated string with the paths of directories or files to search. Any classes 29 | * declared in these locations will be automatically required and included in the build. 30 | * If any file defines an Ext JS override (using Ext.define with an "override" property), 31 | * that override will in fact only be included in the build if the target class specified 32 | * in the "override" property is also included. 33 | */ 34 | "overrides": [ 35 | "overrides" 36 | ], 37 | 38 | /** 39 | * The Sencha Framework for this application: "ext" or "touch". 40 | */ 41 | "framework": "ext", 42 | 43 | 44 | /** 45 | * The toolkit to use. Select either "classic" or "modern". 46 | */ 47 | "toolkit": "modern", 48 | 49 | 50 | 51 | /** 52 | * The name of the theme for this application. 53 | */ 54 | 55 | "theme": "theme-material", 56 | 57 | 58 | /** 59 | * The list of required packages (with optional versions; default is "latest"). 60 | * 61 | * For example, 62 | * 63 | * "requires": [ 64 | * "charts" 65 | * ] 66 | */ 67 | "requires": [], 68 | 69 | /** 70 | * Fashion build configuration properties. 71 | */ 72 | "fashion": { 73 | "inliner": { 74 | /** 75 | * Disable resource inliner. Production builds enable this by default. 76 | */ 77 | "enable": false 78 | } 79 | }, 80 | 81 | /** 82 | * Sass configuration properties. 83 | */ 84 | "sass": { 85 | /** 86 | * The root namespace to use when mapping *.scss files to classes in the 87 | * sass/src and sass/var directories. For example, "MyApp.view.Foo" would 88 | * map to "sass/src/view/Foo.scss". If we changed this to "MyApp.view" then 89 | * it would map to "sass/src/Foo.scss". To style classes outside the app's 90 | * root namespace, change this to "". Doing so would change the mapping of 91 | * "MyApp.view.Foo" to "sass/src/MyApp/view/Foo.scss". 92 | */ 93 | "namespace": "MyApp", 94 | 95 | /** 96 | * Generated sass source settings 97 | * 98 | * "generated": { 99 | * // The file used to save sass variables edited via Sencha Inspector and Sencha Themer. 100 | * // This file will automatically be applied to the end of the scss build. 101 | * "var": "sass/save.scss", 102 | * 103 | * // The directory used to save generated sass sources. 104 | * // This directory will automatically be applied to the end of the scss build. 105 | * "src": "sass/save" 106 | * } 107 | * 108 | */ 109 | 110 | "generated": { 111 | "var": "sass/save.scss", 112 | "src": "sass/save" 113 | }, 114 | 115 | 116 | /** 117 | * Comma-separated list of files or folders containing extra Sass. These 118 | * files are automatically included in the Sass compilation. By default this 119 | * is just "etc/all.scss" to allow import directives to control the order 120 | * other files are included. 121 | * 122 | * All "etc" files are included at the top of the Sass compilation in their 123 | * dependency order: 124 | * 125 | * +-------+---------+ 126 | * | | base | 127 | * | theme +---------+ 128 | * | | derived | 129 | * +-------+---------+ 130 | * | packages | (in package dependency order) 131 | * +-----------------+ 132 | * | application | 133 | * +-----------------+ 134 | */ 135 | "etc": [ 136 | "sass/etc/all.scss" 137 | ], 138 | 139 | /** 140 | * Comma-separated list of folders containing Sass variable definitions 141 | * files. These file can also define Sass mixins for use by components. 142 | * 143 | * All "var" files are included after "etc" files in the Sass compilation in 144 | * dependency order: 145 | * 146 | * +-------+---------+ 147 | * | | base | 148 | * | theme +---------+ 149 | * | | derived | 150 | * +-------+---------+ 151 | * | packages | (in package dependency order) 152 | * +-----------------+ 153 | * | application | 154 | * +-----------------+ 155 | * 156 | * The "sass/var/all.scss" file is always included at the start of the var 157 | * block before any files associated with JavaScript classes. 158 | */ 159 | "var": [ 160 | "sass/var/all.scss", 161 | "sass/var" 162 | ], 163 | 164 | /** 165 | * Comma-separated list of folders containing Sass rule files. 166 | * 167 | * All "src" files are included after "var" files in the Sass compilation in 168 | * dependency order (the same order as "etc"): 169 | * 170 | * +-------+---------+ 171 | * | | base | 172 | * | theme +---------+ 173 | * | | derived | 174 | * +-------+---------+ 175 | * | packages | (in package dependency order) 176 | * +-----------------+ 177 | * | application | 178 | * +-----------------+ 179 | */ 180 | "src": [ 181 | "sass/src" 182 | ] 183 | }, 184 | 185 | /** 186 | * List of all JavaScript assets in the right execution order. 187 | * 188 | * Each item is an object with the following format: 189 | * 190 | * { 191 | * // Path to file. If the file is local this must be a relative path from 192 | * // this app.json file. 193 | * // 194 | * "path": "path/to/script.js", // REQUIRED 195 | * 196 | * // Set to true on one file to indicate that it should become the container 197 | * // for the concatenated classes. 198 | * // 199 | * "bundle": false, // OPTIONAL 200 | * 201 | * // Set to true to include this file in the concatenated classes. 202 | * // 203 | * "includeInBundle": false, // OPTIONAL 204 | * 205 | * // Specify as true if this file is remote and should not be copied into the 206 | * // build folder. Defaults to false for a local file which will be copied. 207 | * // 208 | * "remote": false, // OPTIONAL 209 | * 210 | * // If not specified, this file will only be loaded once, and cached inside 211 | * // localStorage until this value is changed. You can specify: 212 | * // 213 | * // - "delta" to enable over-the-air delta update for this file 214 | * // - "full" means full update will be made when this file changes 215 | * // 216 | * "update": "", // OPTIONAL 217 | * 218 | * // A value of true indicates that is a development mode only dependency. 219 | * // These files will not be copied into the build directory or referenced 220 | * // in the generate app.json manifest for the micro loader. 221 | * // 222 | * "bootstrap": false // OPTIONAL 223 | * } 224 | * 225 | */ 226 | "js": [ 227 | { 228 | "path": "${framework.dir}/build/ext-modern-all-debug.js" 229 | }, 230 | { 231 | "path": "app.js", 232 | "bundle": true 233 | } 234 | ], 235 | 236 | 237 | 238 | /** 239 | * List of all CSS assets in the right inclusion order. 240 | * 241 | * Each item is an object with the following format: 242 | * 243 | * { 244 | * // Path to file. If the file is local this must be a relative path from 245 | * // this app.json file. 246 | * // 247 | * "path": "path/to/stylesheet.css", // REQUIRED 248 | * 249 | * // Specify as true if this file is remote and should not be copied into the 250 | * // build folder. Defaults to false for a local file which will be copied. 251 | * // 252 | * "remote": false, // OPTIONAL 253 | * 254 | * // If not specified, this file will only be loaded once, and cached inside 255 | * // localStorage until this value is changed. You can specify: 256 | * // 257 | * // - "delta" to enable over-the-air delta update for this file 258 | * // - "full" means full update will be made when this file changes 259 | * // 260 | * "update": "" // OPTIONAL 261 | * } 262 | */ 263 | "css": [ 264 | { 265 | // this entry uses an ant variable that is the calculated 266 | // value of the generated output css file for the app, 267 | // defined in .sencha/app/defaults.properties 268 | "path": "${build.out.css.path}", 269 | "bundle": true, 270 | "exclude": ["fashion"] 271 | } 272 | ], 273 | 274 | /** 275 | * This option is used to configure the dynamic loader. At present these options 276 | * are supported. 277 | * 278 | */ 279 | "loader": { 280 | // This property controls how the loader manages caching for requests: 281 | // 282 | // - true: allows requests to receive cached responses 283 | // - false: disable cached responses by adding a random "cache buster" 284 | // - other: a string (such as the build.timestamp shown here) to allow 285 | // requests to be cached for this build. 286 | // 287 | "cache": false, 288 | 289 | // When "cache" is not true, this value is the request parameter used 290 | // to control caching. 291 | // 292 | "cacheParam": "_dc" 293 | }, 294 | 295 | /** 296 | * Settings specific to production builds. 297 | */ 298 | "production": { 299 | "output": { 300 | "appCache": { 301 | "enable": true, 302 | "path": "cache.appcache" 303 | } 304 | }, 305 | "loader": { 306 | "cache": "${build.timestamp}" 307 | }, 308 | "cache": { 309 | "enable": true 310 | }, 311 | "compressor": { 312 | "type": "yui" 313 | } 314 | }, 315 | 316 | /** 317 | * Settings specific to testing builds. 318 | */ 319 | "testing": { 320 | }, 321 | 322 | /** 323 | * Settings specific to development builds. 324 | */ 325 | "development": { 326 | "watch": { 327 | "delay": 250 328 | } 329 | }, 330 | 331 | /** 332 | * Controls the output structure of development-mode (bootstrap) artifacts. May 333 | * be specified by a string: 334 | * 335 | * "bootstrap": "${app.dir}" 336 | * 337 | * This will adjust the base path for all bootstrap objects, or expanded into object 338 | * form: 339 | * 340 | * "bootstrap": { 341 | * "base": "${app.dir}, 342 | * "manifest": "bootstrap.json", 343 | * "microloader": "bootstrap.js", 344 | * "css": "bootstrap.css" 345 | * } 346 | * 347 | * You can optionally exclude entries from the manifest. For example, to exclude 348 | * the "loadOrder" (to help development load approximate a build) you can add: 349 | * 350 | * "bootstrap": { 351 | * "manifest": { 352 | * "path": "bootstrap.json", 353 | * "exclude": "loadOrder" 354 | * } 355 | * } 356 | * 357 | */ 358 | "bootstrap": { 359 | "base": "${app.dir}", 360 | 361 | "microloader": "bootstrap.js", 362 | "css": "bootstrap.css" 363 | }, 364 | 365 | /** 366 | * Controls the output directory for build resources. May be set with 367 | * either a string: 368 | * 369 | * "${workspace.build.dir}/${build.environment}/${app.name}" 370 | * 371 | * or an object containing values for various types of build artifacts: 372 | * 373 | * { 374 | * "base": "${workspace.build.dir}/${build.environment}/${app.name}", 375 | * "page": { 376 | * "path": "../index.html", 377 | * "enable": false 378 | * }, 379 | * "css": "${app.output.resources}/${app.name}-all.css", 380 | * "js": "app.js", 381 | * "microloader": { 382 | * "path": "microloader.js", 383 | * "embed": true, 384 | * "enable": true 385 | * }, 386 | * "manifest": { 387 | * "path": "app.json", 388 | * "embed": false, 389 | * "enable": "${app.output.microloader.enable}" 390 | * }, 391 | * "resources": "resources", 392 | * "slicer": { 393 | * "path": "${app.output.resources}/images", 394 | * "enable": false 395 | * }, 396 | * // Setting the "enable" property of this object to a Truthy value will cause a Application Cache 397 | * // manifest file to be generated based on this files appCache object. This file will then be injected 398 | * // into the index.html file of the built application 399 | * "appCache":{ 400 | * "enable": false" 401 | * } 402 | * } 403 | * 404 | */ 405 | 406 | "output": { 407 | "base": "${workspace.build.dir}/${build.environment}/${app.name}", 408 | "appCache": { 409 | "enable": false 410 | } 411 | }, 412 | 413 | 414 | /** 415 | * Controls for localStorage caching 416 | * "cache": { 417 | * // This property controls whether localStorage caching of this manifest file is on or off. 418 | * // if disabled no deltas will be generated during a build and full updates will be disabled 419 | * "enable": false, 420 | * 421 | * // This property allows for global toggle of deltas. 422 | * // If set to a string the value will be used as the path to where deltas will be generated relative to you build. 423 | * // If set to a Truthy Value the default path ok "deltas" will be used 424 | * // If set to a Falsey value or if this property is not present deltas will be disabled and not generated. 425 | * 426 | * "deltas": "deltas" 427 | * } 428 | */ 429 | 430 | "cache": { 431 | "enable": false, 432 | "deltas": true 433 | }, 434 | 435 | 436 | /** 437 | * Used to automatically generate cache.manifest (HTML 5 application cache manifest) 438 | * file when you build. 439 | */ 440 | "appCache": { 441 | /** 442 | * List of items in the CACHE MANIFEST section 443 | */ 444 | "cache": [ 445 | "index.html" 446 | ], 447 | /** 448 | * List of items in the NETWORK section 449 | */ 450 | "network": [ 451 | "*" 452 | ], 453 | /** 454 | * List of items in the FALLBACK section 455 | */ 456 | "fallback": [] 457 | }, 458 | 459 | /** 460 | * Extra resources to be copied into the resource folder as specified in the "resources" 461 | * property of the "output" object. Folders specified in this list will be deeply copied. 462 | */ 463 | "resources": [ 464 | { 465 | "path": "resources", 466 | "output": "shared" 467 | } 468 | ], 469 | 470 | /** 471 | * Directory path to store all previous production builds. Note that the content 472 | * generated inside this directory must be kept intact for proper generation of 473 | * deltas between updates. 474 | */ 475 | 476 | "archivePath": "archive", 477 | 478 | 479 | 480 | "slicer": null, 481 | 482 | 483 | /** 484 | * Build Profiles. This object's properties are each a "build profile". You can 485 | * add as many as you need to produce optimized builds for devices, themes, locales 486 | * or other criteria. Your "Ext.beforeLoad" hook (see index.html) is responsible for 487 | * selecting the desired build profile by setting "Ext.manifest" to one of these 488 | * names. 489 | * 490 | */ 491 | 492 | 493 | /** 494 | * File / directory name patttern to ignore when copying to the builds. Must be a 495 | * valid regular expression. 496 | */ 497 | "ignore": [ 498 | "(^|/)CVS(/?$|/.*?$)" 499 | ], 500 | 501 | /** 502 | * Uniquely generated id for this application, used as prefix for localStorage keys. 503 | * Normally you should never change this value. 504 | */ 505 | "id": "26085d72-4f91-4fa2-8ae4-6a52d73f4fa6" 506 | } 507 | -------------------------------------------------------------------------------- /resources/devs.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "gender": "female", 4 | "name": { 5 | "title": "mrs", 6 | "first": "آنیتا", 7 | "last": "مرادی" 8 | }, 9 | "location": { 10 | "street": "2233 یادگار امام", 11 | "city": "مشهد", 12 | "state": "ایلام", 13 | "postcode": 72013 14 | }, 15 | "email": "آنیتا.مرادی@example.com", 16 | "registered": 981937960, 17 | "phone": "000-95867341", 18 | "cell": "0990-625-8270", 19 | "picture": { 20 | "large": "https://randomuser.me/api/portraits/women/4.jpg", 21 | "medium": "https://randomuser.me/api/portraits/med/women/4.jpg", 22 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/4.jpg" 23 | }, 24 | "nat": "IR", 25 | "skills": ["Ext JS", "Touch", "Architect"] 26 | }, { 27 | "gender": "female", 28 | "name": { 29 | "title": "miss", 30 | "first": "clara", 31 | "last": "rasmussen" 32 | }, 33 | "location": { 34 | "street": "9595 sandagervej", 35 | "city": "gjern", 36 | "state": "sjælland", 37 | "postcode": 47809 38 | }, 39 | "email": "clara.rasmussen@example.com", 40 | "registered": 1435970894, 41 | "phone": "83667618", 42 | "cell": "14386226", 43 | "picture": { 44 | "large": "https://randomuser.me/api/portraits/women/63.jpg", 45 | "medium": "https://randomuser.me/api/portraits/med/women/63.jpg", 46 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/63.jpg" 47 | }, 48 | "nat": "DK", 49 | "skills": ["Ext JS"] 50 | }, { 51 | "gender": "male", 52 | "name": { 53 | "title": "mr", 54 | "first": "scott", 55 | "last": "daniels" 56 | }, 57 | "location": { 58 | "street": "3191 lakeview st", 59 | "city": "mackay", 60 | "state": "victoria", 61 | "postcode": 4216 62 | }, 63 | "email": "scott.daniels@example.com", 64 | "registered": 1100913238, 65 | "phone": "03-0976-0137", 66 | "cell": "0476-727-335", 67 | "picture": { 68 | "large": "https://randomuser.me/api/portraits/men/63.jpg", 69 | "medium": "https://randomuser.me/api/portraits/med/men/63.jpg", 70 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/63.jpg" 71 | }, 72 | "nat": "AU", 73 | "skills": ["Ext JS", "Themer", "Inspector"] 74 | }, { 75 | "gender": "female", 76 | "name": { 77 | "title": "ms", 78 | "first": "laura", 79 | "last": "kelley" 80 | }, 81 | "location": { 82 | "street": "5030 the grove", 83 | "city": "gorey", 84 | "state": "meath", 85 | "postcode": 61294 86 | }, 87 | "email": "laura.kelley@example.com", 88 | "registered": 1086131809, 89 | "phone": "071-756-7136", 90 | "cell": "081-245-7966", 91 | "picture": { 92 | "large": "https://randomuser.me/api/portraits/women/34.jpg", 93 | "medium": "https://randomuser.me/api/portraits/med/women/34.jpg", 94 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/34.jpg" 95 | }, 96 | "nat": "IE", 97 | "skills": ["Touch", "Architect", "Themer", "Inspector"] 98 | }, { 99 | "gender": "female", 100 | "name": { 101 | "title": "mrs", 102 | "first": "josefa", 103 | "last": "moya" 104 | }, 105 | "location": { 106 | "street": "2678 calle de atocha", 107 | "city": "pontevedra", 108 | "state": "canarias", 109 | "postcode": 20297 110 | }, 111 | "email": "josefa.moya@example.com", 112 | "registered": 1262826756, 113 | "phone": "992-764-676", 114 | "cell": "683-944-461", 115 | "picture": { 116 | "large": "https://randomuser.me/api/portraits/women/51.jpg", 117 | "medium": "https://randomuser.me/api/portraits/med/women/51.jpg", 118 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/51.jpg" 119 | }, 120 | "nat": "ES", 121 | "skills": ["Touch", "Architect"] 122 | }, { 123 | "gender": "female", 124 | "name": { 125 | "title": "ms", 126 | "first": "nalan", 127 | "last": "orbay" 128 | }, 129 | "location": { 130 | "street": "5955 necatibey cd", 131 | "city": "denizli", 132 | "state": "mardin", 133 | "postcode": 15900 134 | }, 135 | "email": "nalan.orbay@example.com", 136 | "registered": 1110543022, 137 | "phone": "(168)-619-9533", 138 | "cell": "(565)-775-7094", 139 | "picture": { 140 | "large": "https://randomuser.me/api/portraits/women/43.jpg", 141 | "medium": "https://randomuser.me/api/portraits/med/women/43.jpg", 142 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/43.jpg" 143 | }, 144 | "nat": "TR", 145 | "skills": ["Ext JS", "Inspector"] 146 | }, { 147 | "gender": "female", 148 | "name": { 149 | "title": "mrs", 150 | "first": "alexis", 151 | "last": "williams" 152 | }, 153 | "location": { 154 | "street": "6776 balmoral st", 155 | "city": "fauquier", 156 | "state": "nunavut", 157 | "postcode": 44317 158 | }, 159 | "email": "alexis.williams@example.com", 160 | "registered": 1242547554, 161 | "phone": "468-827-8351", 162 | "cell": "081-301-8166", 163 | "picture": { 164 | "large": "https://randomuser.me/api/portraits/women/64.jpg", 165 | "medium": "https://randomuser.me/api/portraits/med/women/64.jpg", 166 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/64.jpg" 167 | }, 168 | "nat": "CA", 169 | "skills": ["Architect", "Themer"] 170 | }, { 171 | "gender": "male", 172 | "name": { 173 | "title": "mr", 174 | "first": "wesley", 175 | "last": "dunn" 176 | }, 177 | "location": { 178 | "street": "1103 victoria road", 179 | "city": "chester", 180 | "state": "buckinghamshire", 181 | "postcode": "C76 7LN" 182 | }, 183 | "email": "wesley.dunn@example.com", 184 | "registered": 1257651371, 185 | "phone": "017683 47210", 186 | "cell": "0726-622-046", 187 | "picture": { 188 | "large": "https://randomuser.me/api/portraits/men/13.jpg", 189 | "medium": "https://randomuser.me/api/portraits/med/men/13.jpg", 190 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/13.jpg" 191 | }, 192 | "nat": "GB", 193 | "skills": ["Touch", "Architect"] 194 | }, { 195 | "gender": "male", 196 | "name": { 197 | "title": "mr", 198 | "first": "byron", 199 | "last": "elliott" 200 | }, 201 | "location": { 202 | "street": "7020 richmond park", 203 | "city": "cobh", 204 | "state": "mayo", 205 | "postcode": 61467 206 | }, 207 | "email": "byron.elliott@example.com", 208 | "registered": 1017793969, 209 | "phone": "071-757-5851", 210 | "cell": "081-480-9062", 211 | "picture": { 212 | "large": "https://randomuser.me/api/portraits/men/14.jpg", 213 | "medium": "https://randomuser.me/api/portraits/med/men/14.jpg", 214 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/14.jpg" 215 | }, 216 | "nat": "IE", 217 | "skills": ["Ext JS"] 218 | }, { 219 | "gender": "female", 220 | "name": { 221 | "title": "mrs", 222 | "first": "rhonda", 223 | "last": "fuller" 224 | }, 225 | "location": { 226 | "street": "9007 lovers ln", 227 | "city": "pomona", 228 | "state": "mississippi", 229 | "postcode": 28255 230 | }, 231 | "email": "rhonda.fuller@example.com", 232 | "registered": 1040528620, 233 | "phone": "(779)-624-9233", 234 | "cell": "(233)-598-9804", 235 | "picture": { 236 | "large": "https://randomuser.me/api/portraits/women/51.jpg", 237 | "medium": "https://randomuser.me/api/portraits/med/women/51.jpg", 238 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/51.jpg" 239 | }, 240 | "nat": "US", 241 | "skills": ["Touch", "Architect", "Inspector"] 242 | }, { 243 | "gender": "male", 244 | "name": { 245 | "title": "mr", 246 | "first": "edwin", 247 | "last": "mitchell" 248 | }, 249 | "location": { 250 | "street": "9740 herbert road", 251 | "city": "laytown-bettystown-mornington", 252 | "state": "mayo", 253 | "postcode": 68255 254 | }, 255 | "email": "edwin.mitchell@example.com", 256 | "registered": 1149677403, 257 | "phone": "021-496-8244", 258 | "cell": "081-917-4018", 259 | "picture": { 260 | "large": "https://randomuser.me/api/portraits/men/81.jpg", 261 | "medium": "https://randomuser.me/api/portraits/med/men/81.jpg", 262 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/81.jpg" 263 | }, 264 | "nat": "IE", 265 | "skills": ["Ext JS", "Inspector"] 266 | }, { 267 | "gender": "male", 268 | "name": { 269 | "title": "mr", 270 | "first": "alfonso", 271 | "last": "jimenez" 272 | }, 273 | "location": { 274 | "street": "6066 calle de la almudena", 275 | "city": "granada", 276 | "state": "aragón", 277 | "postcode": 12933 278 | }, 279 | "email": "alfonso.jimenez@example.com", 280 | "registered": 1363696315, 281 | "phone": "984-928-051", 282 | "cell": "624-175-398", 283 | "picture": { 284 | "large": "https://randomuser.me/api/portraits/men/45.jpg", 285 | "medium": "https://randomuser.me/api/portraits/med/men/45.jpg", 286 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/45.jpg" 287 | }, 288 | "nat": "ES", 289 | "skills": ["Architect", "Inspector"] 290 | }, { 291 | "gender": "male", 292 | "name": { 293 | "title": "monsieur", 294 | "first": "dorian", 295 | "last": "dumas" 296 | }, 297 | "location": { 298 | "street": "4294 rue louis-garrand", 299 | "city": "renens vd 1", 300 | "state": "genève", 301 | "postcode": 9377 302 | }, 303 | "email": "dorian.dumas@example.com", 304 | "registered": 1134806701, 305 | "phone": "(217)-574-0234", 306 | "cell": "(988)-834-3149", 307 | "picture": { 308 | "large": "https://randomuser.me/api/portraits/men/18.jpg", 309 | "medium": "https://randomuser.me/api/portraits/med/men/18.jpg", 310 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/18.jpg" 311 | }, 312 | "nat": "CH", 313 | "skills": ["Ext JS", "Touch", "Architect", "Themer", "Inspector"] 314 | }, { 315 | "gender": "female", 316 | "name": { 317 | "title": "ms", 318 | "first": "celia", 319 | "last": "herrero" 320 | }, 321 | "location": { 322 | "street": "9667 calle de argumosa", 323 | "city": "gandía", 324 | "state": "comunidad valenciana", 325 | "postcode": 59398 326 | }, 327 | "email": "celia.herrero@example.com", 328 | "registered": 1165737413, 329 | "phone": "931-253-643", 330 | "cell": "622-270-157", 331 | "picture": { 332 | "large": "https://randomuser.me/api/portraits/women/79.jpg", 333 | "medium": "https://randomuser.me/api/portraits/med/women/79.jpg", 334 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/79.jpg" 335 | }, 336 | "nat": "ES", 337 | "skills": ["Ext JS", "Touch", "Architect", "Themer"] 338 | }, { 339 | "gender": "male", 340 | "name": { 341 | "title": "mr", 342 | "first": "eugenio", 343 | "last": "campos" 344 | }, 345 | "location": { 346 | "street": "5709 calle de pedro bosch", 347 | "city": "toledo", 348 | "state": "comunidad valenciana", 349 | "postcode": 54790 350 | }, 351 | "email": "eugenio.campos@example.com", 352 | "registered": 1087042761, 353 | "phone": "956-230-182", 354 | "cell": "607-314-519", 355 | "picture": { 356 | "large": "https://randomuser.me/api/portraits/men/60.jpg", 357 | "medium": "https://randomuser.me/api/portraits/med/men/60.jpg", 358 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/60.jpg" 359 | }, 360 | "nat": "ES", 361 | "skills": ["Ext JS", "Architect"] 362 | }, { 363 | "gender": "male", 364 | "name": { 365 | "title": "mr", 366 | "first": "eren", 367 | "last": "kuday" 368 | }, 369 | "location": { 370 | "street": "9387 doktorlar cd", 371 | "city": "sivas", 372 | "state": "çorum", 373 | "postcode": 50819 374 | }, 375 | "email": "eren.kuday@example.com", 376 | "registered": 938918387, 377 | "phone": "(464)-012-2573", 378 | "cell": "(688)-357-6758", 379 | "picture": { 380 | "large": "https://randomuser.me/api/portraits/men/81.jpg", 381 | "medium": "https://randomuser.me/api/portraits/med/men/81.jpg", 382 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/81.jpg" 383 | }, 384 | "nat": "TR", 385 | "skills": ["Architect", "Inspector"] 386 | }, { 387 | "gender": "female", 388 | "name": { 389 | "title": "ms", 390 | "first": "maria", 391 | "last": "müller" 392 | }, 393 | "location": { 394 | "street": "4367 birkenstraße", 395 | "city": "mönchengladbach", 396 | "state": "niedersachsen", 397 | "postcode": 49067 398 | }, 399 | "email": "maria.müller@example.com", 400 | "registered": 1134863750, 401 | "phone": "0219-5654567", 402 | "cell": "0178-8084884", 403 | "picture": { 404 | "large": "https://randomuser.me/api/portraits/women/86.jpg", 405 | "medium": "https://randomuser.me/api/portraits/med/women/86.jpg", 406 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/86.jpg" 407 | }, 408 | "nat": "DE", 409 | "skills": ["Touch"] 410 | }, { 411 | "gender": "female", 412 | "name": { 413 | "title": "madame", 414 | "first": "leana", 415 | "last": "legrand" 416 | }, 417 | "location": { 418 | "street": "2084 rue de l'abbé-patureau", 419 | "city": "romanel-sur-morges", 420 | "state": "bern", 421 | "postcode": 9094 422 | }, 423 | "email": "leana.legrand@example.com", 424 | "registered": 1017709518, 425 | "phone": "(857)-939-6129", 426 | "cell": "(719)-002-9483", 427 | "picture": { 428 | "large": "https://randomuser.me/api/portraits/women/20.jpg", 429 | "medium": "https://randomuser.me/api/portraits/med/women/20.jpg", 430 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/20.jpg" 431 | }, 432 | "nat": "CH", 433 | "skills": ["Ext JS", "Themer", "Inspector"] 434 | }, { 435 | "gender": "male", 436 | "name": { 437 | "title": "mr", 438 | "first": "william", 439 | "last": "rasmussen" 440 | }, 441 | "location": { 442 | "street": "7244 ridderhatten", 443 | "city": "ulsted, hals", 444 | "state": "danmark", 445 | "postcode": 88846 446 | }, 447 | "email": "william.rasmussen@example.com", 448 | "registered": 1312994805, 449 | "phone": "60305590", 450 | "cell": "08044701", 451 | "picture": { 452 | "large": "https://randomuser.me/api/portraits/men/93.jpg", 453 | "medium": "https://randomuser.me/api/portraits/med/men/93.jpg", 454 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/93.jpg" 455 | }, 456 | "nat": "DK", 457 | "skills": ["Architect"] 458 | }, { 459 | "gender": "male", 460 | "name": { 461 | "title": "mr", 462 | "first": "udo", 463 | "last": "fogaça" 464 | }, 465 | "location": { 466 | "street": "5418 rua são paulo ", 467 | "city": "paranaguá", 468 | "state": "distrito federal", 469 | "postcode": 66556 470 | }, 471 | "email": "udo.fogaça@example.com", 472 | "registered": 1304514894, 473 | "phone": "(95) 1080-6180", 474 | "cell": "(92) 5634-1998", 475 | "picture": { 476 | "large": "https://randomuser.me/api/portraits/men/83.jpg", 477 | "medium": "https://randomuser.me/api/portraits/med/men/83.jpg", 478 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/83.jpg" 479 | }, 480 | "nat": "BR", 481 | "skills": ["Touch"] 482 | }, { 483 | "gender": "male", 484 | "name": { 485 | "title": "mr", 486 | "first": "umit", 487 | "last": "polderman" 488 | }, 489 | "location": { 490 | "street": "8406 neude", 491 | "city": "deurne", 492 | "state": "utrecht", 493 | "postcode": 42964 494 | }, 495 | "email": "umit.polderman@example.com", 496 | "registered": 1369329139, 497 | "phone": "(566)-652-4345", 498 | "cell": "(329)-436-2686", 499 | "picture": { 500 | "large": "https://randomuser.me/api/portraits/men/23.jpg", 501 | "medium": "https://randomuser.me/api/portraits/med/men/23.jpg", 502 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/23.jpg" 503 | }, 504 | "nat": "NL", 505 | "skills": ["Ext JS"] 506 | }, { 507 | "gender": "male", 508 | "name": { 509 | "title": "mr", 510 | "first": "derrick", 511 | "last": "simmmons" 512 | }, 513 | "location": { 514 | "street": "1913 karen dr", 515 | "city": "chicago", 516 | "state": "rhode island", 517 | "postcode": 68934 518 | }, 519 | "email": "derrick.simmmons@example.com", 520 | "registered": 1220029946, 521 | "phone": "(752)-864-3066", 522 | "cell": "(663)-031-2805", 523 | "picture": { 524 | "large": "https://randomuser.me/api/portraits/men/98.jpg", 525 | "medium": "https://randomuser.me/api/portraits/med/men/98.jpg", 526 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/98.jpg" 527 | }, 528 | "nat": "US", 529 | "skills": ["Ext JS", "Inspector"] 530 | }, { 531 | "gender": "male", 532 | "name": { 533 | "title": "mr", 534 | "first": "thiago", 535 | "last": "fabre" 536 | }, 537 | "location": { 538 | "street": "8318 rue dubois", 539 | "city": "avignon", 540 | "state": "alpes-maritimes", 541 | "postcode": 48154 542 | }, 543 | "email": "thiago.fabre@example.com", 544 | "registered": 1036032941, 545 | "phone": "04-13-58-24-57", 546 | "cell": "06-46-53-98-99", 547 | "picture": { 548 | "large": "https://randomuser.me/api/portraits/men/97.jpg", 549 | "medium": "https://randomuser.me/api/portraits/med/men/97.jpg", 550 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/97.jpg" 551 | }, 552 | "nat": "FR", 553 | "skills": ["Ext JS", "Themer", "Inspector"] 554 | }, { 555 | "gender": "female", 556 | "name": { 557 | "title": "miss", 558 | "first": "maria", 559 | "last": "johansen" 560 | }, 561 | "location": { 562 | "street": "2001 landlystvej", 563 | "city": "aarhus n", 564 | "state": "syddanmark", 565 | "postcode": 24118 566 | }, 567 | "email": "maria.johansen@example.com", 568 | "registered": 1173317526, 569 | "phone": "07431093", 570 | "cell": "19247420", 571 | "picture": { 572 | "large": "https://randomuser.me/api/portraits/women/86.jpg", 573 | "medium": "https://randomuser.me/api/portraits/med/women/86.jpg", 574 | "thumbnail": "https://randomuser.me/api/portraits/thumb/women/86.jpg" 575 | }, 576 | "nat": "DK", 577 | "skills": ["Ext JS", "Themer"] 578 | }, { 579 | "gender": "male", 580 | "name": { 581 | "title": "mr", 582 | "first": "benjamin", 583 | "last": "christiansen" 584 | }, 585 | "location": { 586 | "street": "5831 baldersvej", 587 | "city": "hornbæk", 588 | "state": "hovedstaden", 589 | "postcode": 68948 590 | }, 591 | "email": "benjamin.christiansen@example.com", 592 | "registered": 1124892789, 593 | "phone": "00803519", 594 | "cell": "75830042", 595 | "picture": { 596 | "large": "https://randomuser.me/api/portraits/men/55.jpg", 597 | "medium": "https://randomuser.me/api/portraits/med/men/55.jpg", 598 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/55.jpg" 599 | }, 600 | "nat": "DK", 601 | "skills": ["Ext JS", "Inspector"] 602 | }, { 603 | "gender": "male", 604 | "name": { 605 | "title": "mr", 606 | "first": "elliot", 607 | "last": "grewal" 608 | }, 609 | "location": { 610 | "street": "7334 richmond ave", 611 | "city": "bath", 612 | "state": "british columbia", 613 | "postcode": 66850 614 | }, 615 | "email": "elliot.grewal@example.com", 616 | "registered": 945339428, 617 | "phone": "743-264-6236", 618 | "cell": "765-113-6571", 619 | "picture": { 620 | "large": "https://randomuser.me/api/portraits/men/75.jpg", 621 | "medium": "https://randomuser.me/api/portraits/med/men/75.jpg", 622 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/75.jpg" 623 | }, 624 | "nat": "CA", 625 | "skills": ["Touch"] 626 | }, { 627 | "gender": "male", 628 | "name": { 629 | "title": "mr", 630 | "first": "محمدطاها", 631 | "last": "نجاتی" 632 | }, 633 | "location": { 634 | "street": "3366 دستغیب", 635 | "city": "قرچک", 636 | "state": "مازندران", 637 | "postcode": 64211 638 | }, 639 | "email": "محمدطاها.نجاتی@example.com", 640 | "registered": 1093712781, 641 | "phone": "053-20321869", 642 | "cell": "0973-855-0667", 643 | "picture": { 644 | "large": "https://randomuser.me/api/portraits/men/47.jpg", 645 | "medium": "https://randomuser.me/api/portraits/med/men/47.jpg", 646 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/47.jpg" 647 | }, 648 | "nat": "IR", 649 | "skills": ["Ext JS", "Themer", "Inspector"] 650 | }, { 651 | "gender": "male", 652 | "name": { 653 | "title": "mr", 654 | "first": "vedat", 655 | "last": "abanuz" 656 | }, 657 | "location": { 658 | "street": "4319 abanoz sk", 659 | "city": "konya", 660 | "state": "kilis", 661 | "postcode": 27947 662 | }, 663 | "email": "vedat.abanuz@example.com", 664 | "registered": 935174224, 665 | "phone": "(830)-683-9397", 666 | "cell": "(665)-483-0603", 667 | "picture": { 668 | "large": "https://randomuser.me/api/portraits/men/62.jpg", 669 | "medium": "https://randomuser.me/api/portraits/med/men/62.jpg", 670 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/62.jpg" 671 | }, 672 | "nat": "TR", 673 | "skills": ["Touch", "Architect"] 674 | }, { 675 | "gender": "male", 676 | "name": { 677 | "title": "mr", 678 | "first": "elmer", 679 | "last": "cavalcanti" 680 | }, 681 | "location": { 682 | "street": "2287 rua castro alves ", 683 | "city": "florianópolis", 684 | "state": "roraima", 685 | "postcode": 39910 686 | }, 687 | "email": "elmer.cavalcanti@example.com", 688 | "registered": 915306551, 689 | "phone": "(62) 9460-6223", 690 | "cell": "(78) 7966-7481", 691 | "picture": { 692 | "large": "https://randomuser.me/api/portraits/men/14.jpg", 693 | "medium": "https://randomuser.me/api/portraits/med/men/14.jpg", 694 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/14.jpg" 695 | }, 696 | "nat": "BR", 697 | "skills": ["Ext JS", "Architect"] 698 | }, { 699 | "gender": "male", 700 | "name": { 701 | "title": "mr", 702 | "first": "valentin", 703 | "last": "sanchez" 704 | }, 705 | "location": { 706 | "street": "4434 avenida del planetario", 707 | "city": "logroño", 708 | "state": "extremadura", 709 | "postcode": 58385 710 | }, 711 | "email": "valentin.sanchez@example.com", 712 | "registered": 1161473236, 713 | "phone": "926-471-696", 714 | "cell": "648-748-237", 715 | "picture": { 716 | "large": "https://randomuser.me/api/portraits/men/96.jpg", 717 | "medium": "https://randomuser.me/api/portraits/med/men/96.jpg", 718 | "thumbnail": "https://randomuser.me/api/portraits/thumb/men/96.jpg" 719 | }, 720 | "nat": "ES", 721 | "skills": ["Ext JS"] 722 | }], 723 | "info": { 724 | "seed": "rwc", 725 | "results": 30, 726 | "page": 1, 727 | "version": "1.0" 728 | } 729 | } --------------------------------------------------------------------------------