diff --git a/guides/release/tutorial/part-1/automated-testing.md b/guides/release/tutorial/part-1/automated-testing.md index 188ac09199..485b59a66c 100644 --- a/guides/release/tutorial/part-1/automated-testing.md +++ b/guides/release/tutorial/part-1/automated-testing.md @@ -33,6 +33,8 @@ Once we are done patting ourselves on the back, go ahead and run the following c $ ember generate acceptance-test super-rentals installing acceptance-test create tests/acceptance/super-rentals-test.js + +Running "lint:fix" script... ``` This is called a _[generator](https://cli.emberjs.com/release/basic-use/cli-commands/#generatemorefiles)_ command in Ember CLI. Generators automatically create files for us based on Ember's conventions and populate them with the appropriate boilerplate content, similar to how `ember new` initially created a skeleton app for us. It typically follows the pattern `ember generate `, where `` is the kind of thing we are generating, and `` is what we want to call it. diff --git a/guides/release/tutorial/part-1/building-pages.md b/guides/release/tutorial/part-1/building-pages.md index 07421d4ec3..3fd80617f2 100644 --- a/guides/release/tutorial/part-1/building-pages.md +++ b/guides/release/tutorial/part-1/building-pages.md @@ -2,11 +2,11 @@ In this chapter, you will build the first few pages of your Ember app and set up links between them. By the end of this chapter, you should have two new pages – an about page and a contact page. These pages will be linked to from your landing page: -The Super Rentals app (homepage) by the end of the chapter +The Super Rentals app (homepage) by the end of the chapter -The Super Rentals app (about page) by the end of the chapter +The Super Rentals app (about page) by the end of the chapter -The Super Rentals app (contact page) by the end of the chapter +The Super Rentals app (contact page) by the end of the chapter While building these pages, you will learn about: @@ -112,7 +112,7 @@ Ember comes with strong _conventions_ and sensible defaults—if we were startin Once you have added the route and the template above, we should have the new page available to us at `http://localhost:4200/getting-in-touch`. -Contact page +Contact page ## Linking Pages with the `` Component @@ -181,11 +181,11 @@ However, when clicking on one of these special links, Ember will intercept the c -Index page after adding the link +Index page after adding the link -About page after adding the link +About page after adding the link -Contact page after adding the link +Contact page after adding the link We will learn more about how all of this works soon. In the meantime, go ahead and click on the link in the browser. Did you notice how snappy that was? diff --git a/guides/release/tutorial/part-1/component-basics.md b/guides/release/tutorial/part-1/component-basics.md index 1aa73b519e..a9ec8cac39 100644 --- a/guides/release/tutorial/part-1/component-basics.md +++ b/guides/release/tutorial/part-1/component-basics.md @@ -2,7 +2,7 @@ In this chapter, you will _[refactor](../../../components/introducing-components/#toc_breaking-it-into-pieces)_ your existing templates to use components. We will also be adding a site-wide navigation bar: -The Super Rentals app by the end of the chapter +The Super Rentals app by the end of the chapter In doing so, you will learn about: @@ -73,7 +73,7 @@ Let's try it out by editing the index template: After saving the changes, your page should automatically reload, and, _voilà_... nothing changed? Well, that's exactly what we wanted to happen this time! We successfully _[refactored](../../../components/introducing-components/#toc_breaking-components-down-further)_ our index template to use the `` component, and everything still works as expected. And the tests still pass! -Index page – nothing changed +Index page – nothing changed Tests still passing after the refactor @@ -119,9 +119,9 @@ Let's do the same for our other two pages as well. After saving, everything should look exactly the same as before, and all the tests should still pass. Very nice! -About page – nothing changed +About page – nothing changed -Contact page – nothing changed +Contact page – nothing changed Tests still passing another round of refactor @@ -135,6 +135,8 @@ Before we move on to the next component, let's write an automated test for our ` $ ember generate component-test jumbo installing component-test create tests/integration/components/jumbo-test.js + +Running "lint:fix" script... ``` Here, we used the generator to generate a _[component test](../../../testing/testing-components/)_, also known as a rendering test. These are used to render and test a single component at a time. This is in contrast to the acceptance tests that we wrote earlier, which have to navigate and render entire pages worth of content. @@ -158,7 +160,7 @@ module('Integration | Component | jumbo', function (hooks) { await render(hbs``); - assert.dom(this.element).hasText(''); + assert.dom().hasText(''); // Template block usage: await render(hbs` @@ -167,7 +169,7 @@ module('Integration | Component | jumbo', function (hooks) { `); - assert.dom(this.element).hasText('template block text'); + assert.dom().hasText('template block text'); assert.dom('.jumbo').exists(); assert.dom('.jumbo').hasText('Hello World'); assert.dom('.jumbo .tomster').exists(); @@ -248,7 +250,7 @@ Next, we will add our `` component to the top of each page: Voilà, we made another component! -Index page with nav +Index page with nav
diff --git a/guides/release/tutorial/part-1/index.md b/guides/release/tutorial/part-1/index.md index 4423b6a0de..444a17dbe5 100644 --- a/guides/release/tutorial/part-1/index.md +++ b/guides/release/tutorial/part-1/index.md @@ -4,7 +4,7 @@ Welcome to the Ember Tutorial! In this tutorial, we will use Ember to build an application called Super Rentals. This will be a website for browsing interesting places to stay during your next vacation. Check out the [finished app](https://ember-super-rentals.netlify.com) to get a sense of the scope of the project. -The finished Super Rentals app +The finished Super Rentals app Along the way, you will learn everything you need to know to build a basic Ember application. If you get stuck at any point during the tutorial, feel free to download for a complete working example. diff --git a/guides/release/tutorial/part-1/interactive-components.md b/guides/release/tutorial/part-1/interactive-components.md index 0757fbc2fc..fcb62d4e4b 100644 --- a/guides/release/tutorial/part-1/interactive-components.md +++ b/guides/release/tutorial/part-1/interactive-components.md @@ -4,7 +4,7 @@ In this chapter, you will add interactivity to the page, allowing the user to cl -The Super Rentals app by the end of the chapter (default image size) +The Super Rentals app by the end of the chapter (default image size) The Super Rentals app by the end of the chapter (large image size) @@ -34,6 +34,8 @@ Ember optionally allows us to associate JavaScript code with a component for exa $ ember generate component-class rental/image installing component-class create app/components/rental/image.js + +Running "lint:fix" script... ``` This generated a JavaScript file with the same name as our component's template at `app/components/rental/image.js`. It contains a _[JavaScript class](https://javascript.info/class)_, _[inheriting](https://javascript.info/class-inheritance)_ from `@glimmer/component`. @@ -199,7 +201,7 @@ With that, we have created our first _interactive_ component. Go ahead and try i -<Rental::Image> (default size) +<Rental::Image> (default size) <Rental::Image> (large size) diff --git a/guides/release/tutorial/part-1/more-about-components.md b/guides/release/tutorial/part-1/more-about-components.md index 955a9594ce..f7d0fd2d59 100644 --- a/guides/release/tutorial/part-1/more-about-components.md +++ b/guides/release/tutorial/part-1/more-about-components.md @@ -2,7 +2,7 @@ It's time to finally work on the rentals listing: -The Super Rentals app by the end of the chapter +The Super Rentals app by the end of the chapter While building this list of rental properties, you will learn about: @@ -19,10 +19,12 @@ Let's start by creating the `` component. This time, we will use the com $ ember generate component rental installing component create app/components/rental.hbs - skip app/components/rental.js + skip app/components/rental.ts tip to add a class, run `ember generate component-class rental` installing component-test create tests/integration/components/rental-test.js + +Running "lint:fix" script... ``` The generator created two new files for us, a component template at `app/components/rental.hbs`, and a component test file at `tests/integration/components/rental-test.js`. @@ -68,7 +70,7 @@ module('Integration | Component | rental', function (hooks) { test('it renders information about a rental property', async function (assert) { await render(hbs``); - assert.dom(this.element).hasText(''); + assert.dom().hasText(''); // Template block usage: await render(hbs` @@ -77,7 +79,7 @@ module('Integration | Component | rental', function (hooks) { `); - assert.dom(this.element).hasText('template block text'); + assert.dom().hasText('template block text'); assert.dom('article').hasClass('rental'); assert.dom('article h3').hasText('Grand Old Mansion'); assert.dom('article .detail.owner').includesText('Veruca Salt'); @@ -112,7 +114,7 @@ Finally, let's invoke this a couple of times from our index template to populate With that, we should see the `` component showing our Grand Old Mansion three times on the page: -Three Grand Old Mansions +Three Grand Old Mansions Things are looking pretty convincing already; not bad for just a little bit of work! @@ -124,10 +126,12 @@ Next, let's add the image for the rental property. We will use the component gen $ ember generate component rental/image installing component create app/components/rental/image.hbs - skip app/components/rental/image.js + skip app/components/rental/image.ts tip to add a class, run `ember generate component-class rental/image` installing component-test create tests/integration/components/rental/image-test.js + +Running "lint:fix" script... ``` This time, we had a `/` in the component's name. This resulted in the component being created at `app/components/rental/image.hbs`, which can be invoked as ``. @@ -173,7 +177,7 @@ Instead of hard-coding specific values for the `src` and `alt` attributes on the We specified a `src` and an `alt` HTML attribute here, which will be passed along to the component and attached to the element where `...attributes` is applied in the component template. You can think of this as being similar to `{{yield}}`, but for HTML attributes specifically, rather than displayed content. In fact, we have already used this feature [earlier](../building-pages/) when we passed a `class` attribute to ``. -The <Rental::Image> component in action +The <Rental::Image> component in action This way, our `` component is not coupled to any specific rental property on the site. Of course, the hard-coding problem still exists (we simply moved it to the `` component), but we will deal with that soon. We will limit all the hard-coding to the `` component, so that we will have an easier time cleaning it up when we switch to fetching real data. @@ -196,7 +200,7 @@ module('Integration | Component | rental/image', function (hooks) { await render(hbs``); - assert.dom(this.element).hasText(''); + assert.dom().hasText(''); // Template block usage: test('it renders the given image', async function (assert) { @@ -210,7 +214,7 @@ module('Integration | Component | rental/image', function (hooks) { /> `); - assert.dom(this.element).hasText('template block text'); + assert.dom().hasText('template block text'); assert .dom('.image img') .exists() diff --git a/guides/release/tutorial/part-1/orientation.md b/guides/release/tutorial/part-1/orientation.md index f3722a4f56..eb51a49c7b 100644 --- a/guides/release/tutorial/part-1/orientation.md +++ b/guides/release/tutorial/part-1/orientation.md @@ -24,8 +24,8 @@ To verify that your installation was successful, run: ```shell $ ember --version -ember-cli: 4.5.0 -node: 14.19.1 +ember-cli: 5.6.0 +node: 18.19.1 os: linux x64 ``` @@ -38,7 +38,7 @@ We can create a new project using Ember CLI's `new` command. It follows the patt ```shell $ ember new super-rentals --lang en installing app -Ember CLI v4.5.0 +Ember CLI v5.6.0 Creating a new Ember app in /home/runner/work/super-rentals-tutorial/super-rentals-tutorial/dist/code/super-rentals: create .editorconfig @@ -48,6 +48,8 @@ Creating a new Ember app in /home/runner/work/super-rentals-tutorial/super-renta create .github/workflows/ci.yml create .prettierignore create .prettierrc.js + create .stylelintignore + create .stylelintrc.js create .template-lintrc.js create .watchmanconfig create README.md @@ -75,7 +77,6 @@ Creating a new Ember app in /home/runner/work/super-rentals-tutorial/super-renta create tests/integration/.gitkeep create tests/test-helper.js create tests/unit/.gitkeep - create vendor/.gitkeep Installing packages... This might take a couple of minutes. npm: Installing dependencies ... @@ -140,8 +141,6 @@ super-rentals │ │ └── .gitkeep │ ├── index.html │ └── test-helper.js -├── vendor -│ └── .gitkeep ├── .editorconfig ├── .ember-cli ├── .eslintcache @@ -150,6 +149,8 @@ super-rentals ├── .gitignore ├── .prettierignore ├── .prettierrc.js +├── .stylelintignore +├── .stylelintrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── README.md @@ -158,17 +159,21 @@ super-rentals ├── package-lock.json └── testem.js -17 directories, 36 files +16 directories, 37 files ``` We'll learn about the purposes of these files and folders as we go. For now, just know that we'll spend most of our time working within the `app` folder. ## Starting and Stopping the Development Server -Ember CLI comes with a lot of different commands for a variety of development tasks, such as the `ember new` command that we saw earlier. It also comes with a _development server_, which we can launch with the `ember server` command: +Ember CLI comes with a lot of different commands for a variety of development tasks, such as the `ember new` command that we saw earlier. It also comes with a _development server_, which we can launch within the project with the `npm start` command: ```shell -$ ember server +$ npm start + +> super-rentals@0.0.0 start +> ember serve + building... Build successful (9761ms) – Serving on http://localhost:4200/ @@ -176,7 +181,7 @@ Build successful (9761ms) – Serving on http://localhost:4200/ The development server is responsible for compiling our app and serving it to the browsers. It may take a while to boot up. Once it's up and running, open your favorite browser and head to . You should see the following welcome page: -Welcome to Ember! +Welcome to Ember!
@@ -190,7 +195,7 @@ The development server is responsible for compiling our app and serving it to th
-You can exit out of the development server at any time by typing `Ctrl + C` into the terminal window where `ember server` is running. That is, typing the "C" key on your keyboard _while_ holding down the "Ctrl" key at the same time. Once it has stopped, you can start it back up again with the same `ember server` command. We recommend having two terminal windows open: one to run the server in background, another to type other Ember CLI commands. +You can exit out of the development server at any time by typing `Ctrl + C` into the terminal window where `npm start` is running. That is, typing the "C" key on your keyboard _while_ holding down the "Ctrl" key at the same time. Once it has stopped, you can start it back up again with the same `npm start` command. We recommend having two terminal windows open: one to run the server in background, another to type other Ember CLI commands. ## Editing Files and Live Reload @@ -201,9 +206,9 @@ As text on the welcome page pointed out, the source code for the page is located ```handlebars { data-filename="app/templates/application.hbs" data-diff="-1,-2,-3,-4,-5,-6,-7,+8" } {{page-title "SuperRentals"}} -{{!-- The following component displays Ember's default welcome message. --}} +{{! The following component displays Ember's default welcome message. }} -{{!-- Feel free to remove this! --}} +{{! Feel free to remove this! }} {{outlet}} Hello World!!! diff --git a/guides/release/tutorial/part-1/reusable-components.md b/guides/release/tutorial/part-1/reusable-components.md index 3b653370a4..49672859f0 100644 --- a/guides/release/tutorial/part-1/reusable-components.md +++ b/guides/release/tutorial/part-1/reusable-components.md @@ -2,7 +2,7 @@ The last missing feature for the `` component is a map to show the location of the rental, which is what we're going to work on next: -The Super Rentals app by the end of the chapter +The Super Rentals app by the end of the chapter While adding the map, you will learn about: @@ -24,17 +24,18 @@ If you're curious, you can explore the options available on Mapbox by using the Once you have signed up for the service, grab your _[default public token](https://account.mapbox.com/access-tokens/)_ and paste it into `config/environment.js`: -```js { data-filename="config/environment.js" data-diff="+47,+48" } +```js { data-filename="config/environment.js" data-diff="+48,+49" } 'use strict'; module.exports = function (environment) { - let ENV = { + const ENV = { modulePrefix: 'super-rentals', environment, rootURL: '/', locationType: 'history', EmberENV: { RAISE_ON_DEPRECATION: true, + EXTEND_PROTOTYPES: false, FEATURES: { // Here you can enable experimental features on an ember canary build // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true @@ -95,10 +96,14 @@ After saving the changes to our configuration file, we will need to restart our -You can stop the server by finding the terminal window where `ember server` is running, then type `Ctrl + C`. That is, typing the "C" key on your keyboard _while_ holding down the "Ctrl" key at the same time. Once it has stopped, you can start it back up again with the same `ember server` command. +You can stop the server by finding the terminal window where `npm start` is running, then type `Ctrl + C`. That is, typing the "C" key on your keyboard _while_ holding down the "Ctrl" key at the same time. Once it has stopped, you can start it back up again with the same `npm start` command. ```shell -$ ember server +$ npm start + +> super-rentals@0.0.0 start +> ember serve + building... Build successful (13286ms) – Serving on http://localhost:4200/ @@ -115,6 +120,8 @@ installing component create app/components/map.hbs installing component-test create tests/integration/components/map-test.js + +Running "lint:fix" script... ``` Since not every component will necessarily have some defined behavior associated with it, the component generator does not generate a JavaScript file for us by default. As we saw earlier, we can always use the `component-class` generator to add a JavaScript file for a component later on. @@ -223,7 +230,7 @@ module('Integration | Component | map', function (hooks) { .hasAttribute('width', '150') .hasAttribute('height', '120'); - assert.dom(this.element).hasText(''); + assert.dom().hasText(''); let { src } = find('.map img'); let token = encodeURIComponent(ENV.MAPBOX_ACCESS_TOKEN); @@ -235,23 +242,23 @@ module('Integration | Component | map', function (hooks) { `); assert.ok( src.startsWith('https://api.mapbox.com/'), - 'the src starts with "https://api.mapbox.com/"' + 'the src starts with "https://api.mapbox.com/"', ); - assert.dom(this.element).hasText('template block text'); + assert.dom().hasText('template block text'); assert.ok( src.includes('-122.4184,37.7797,10'), - 'the src should include the lng,lat,zoom parameter' + 'the src should include the lng,lat,zoom parameter', ); assert.ok( src.includes('150x120@2x'), - 'the src should include the width,height and @2x parameter' + 'the src should include the width,height and @2x parameter', ); assert.ok( src.includes(`access_token=${token}`), - 'the src should include the escaped access token' + 'the src should include the escaped access token', ); }); @@ -331,7 +338,7 @@ Hey, all the tests passed! But does that mean it actually works in practice? Let Hey! That's a map! -Three Grand Old Mansions +Three Grand Old Mansions @@ -472,22 +479,22 @@ module('Integration | Component | map', function (hooks) { assert.ok( src.startsWith('https://api.mapbox.com/'), - 'the src starts with "https://api.mapbox.com/"' + 'the src starts with "https://api.mapbox.com/"', ); assert.ok( src.includes('-122.4184,37.7797,10'), - 'the src should include the lng,lat,zoom parameter' + 'the src should include the lng,lat,zoom parameter', ); assert.ok( src.includes('150x120@2x'), - 'the src should include the width,height and @2x parameter' + 'the src should include the width,height and @2x parameter', ); assert.ok( src.includes(`access_token=${token}`), - 'the src should include the escaped access token' + 'the src should include the escaped access token', ); }); @@ -512,12 +519,12 @@ module('Integration | Component | map', function (hooks) { assert.ok( img.src.includes('-122.4194,37.7749,10'), - 'the src should include the lng,lat,zoom parameter' + 'the src should include the lng,lat,zoom parameter', ); assert.ok( img.src.includes('150x120@2x'), - 'the src should include the width,height and @2x parameter' + 'the src should include the width,height and @2x parameter', ); this.setProperties({ @@ -528,12 +535,12 @@ module('Integration | Component | map', function (hooks) { assert.ok( img.src.includes('-122.4194,37.7749,12'), - 'the src should include the lng,lat,zoom parameter' + 'the src should include the lng,lat,zoom parameter', ); assert.ok( img.src.includes('300x200@2x'), - 'the src should include the width,height and @2x parameter' + 'the src should include the width,height and @2x parameter', ); this.setProperties({ @@ -543,12 +550,12 @@ module('Integration | Component | map', function (hooks) { assert.ok( img.src.includes('-122.3321,47.6062,12'), - 'the src should include the lng,lat,zoom parameter' + 'the src should include the lng,lat,zoom parameter', ); assert.ok( img.src.includes('300x200@2x'), - 'the src should include the width,height and @2x parameter' + 'the src should include the width,height and @2x parameter', ); }); diff --git a/guides/release/tutorial/part-1/working-with-data.md b/guides/release/tutorial/part-1/working-with-data.md index 665f746a58..e5aa814af8 100644 --- a/guides/release/tutorial/part-1/working-with-data.md +++ b/guides/release/tutorial/part-1/working-with-data.md @@ -2,7 +2,7 @@ In this chapter, we will remove the hard-coded data from our `` component. By the end, your app would finally be displaying real data that came from the server: -The Super Rentals app by the end of the chapter +The Super Rentals app by the end of the chapter In this chapter, you will learn about: @@ -427,7 +427,7 @@ Inside of the block we have access to the item of the _current_ iteration with t Now, let's go over to our browser and see what our index route looks like with this change. -Three different rental properties +Three different rental properties Hooray! Finally we're seeing different rental properties in our list. And we got to play with `fetch` and write a loop. Pretty productive, if you ask me. diff --git a/guides/release/tutorial/part-2/ember-data.md b/guides/release/tutorial/part-2/ember-data.md index 72b3d93961..05da01c8a9 100644 --- a/guides/release/tutorial/part-2/ember-data.md +++ b/guides/release/tutorial/part-2/ember-data.md @@ -1,18 +1,18 @@ -In this chapter, we will work on removing some code duplication in our route handlers, by switching to using Ember Data to manage our data. The end result looks exactly the same as before: +In this chapter, we will work on removing some code duplication in our route handlers, by switching to using EmberData to manage our data. The end result looks exactly the same as before: -The Super Rentals app by the end of the chapter +The Super Rentals app by the end of the chapter During this refactor, you will learn about: -- Ember Data models +- EmberData models - Testing models - Loading models in routes -- The Ember Data store +- The EmberData store - Working with adapters and serializers -## What is Ember Data? +## What is EmberData? Now that we've added some features, it's time to do some clean up again! @@ -72,13 +72,13 @@ This duplication incurred a bit of _technical debt_ for us, making our code base Chances are, as we keep working on this app, we will need to add more routes that fetch data from the server. Since all of our server's API endpoints follow the [JSON:API](https://jsonapi.org/) format, we'd have to keep copying this boilerplate for every single new route we add to the app! -Fortunately, we're not going to do any of that. As it turns out, there's a much better solution here: we can use Ember Data! As its name implies, [Ember Data](../../../models/) is a library that helps manage data and _application state_ in Ember applications. +Fortunately, we're not going to do any of that. As it turns out, there's a much better solution here: we can use EmberData! As its name implies, [EmberData](../../../models/) is a library that helps manage data and _application state_ in Ember applications. -There's a lot to learn about Ember Data, but let's start by uncovering features that help with our immediate problem. +There's a lot to learn about EmberData, but let's start by uncovering features that help with our immediate problem. -## Ember Data Models +## EmberData Models -Ember Data is built around the idea of organizing your app's data into _[model objects](../../../models/defining-models/)_. These objects represent units of information that our application presents to the user. For example, the rental property data we have been working with would be a good candidate. +EmberData is built around the idea of organizing your app's data into _[model objects](../../../models/defining-models/)_. These objects represent units of information that our application presents to the user. For example, the rental property data we have been working with would be a good candidate. Enough talking, why don't we give that a try! @@ -107,7 +107,7 @@ export default class RentalModel extends Model { } ``` -Here, we created a `RentalModel` class that extends Ember Data's `Model` superclass. When fetching the listing data from the server, each individual rental property will be represented by an instance (also known as a _[record](../../../models/finding-records/)_ of our `RentalModel` class. +Here, we created a `RentalModel` class that extends EmberData's `Model` superclass. When fetching the listing data from the server, each individual rental property will be represented by an instance (also known as a _[record](../../../models/finding-records/)_ of our `RentalModel` class. We used the `@attr` decorator to declare the attributes of a rental property. These attributes correspond directly to the `attributes` data we expect the server to provide in its responses: @@ -135,7 +135,7 @@ We used the `@attr` decorator to declare the attributes of a rental property. Th We can access these attributes for an instance of `RentalModel` using standard dot notation, such as `model.title` or `model.location.lat`. In addition to the attributes we declared here, there will always be an implicit _id_ attribute as well, which is used to uniquely identify the model object and can be accessed using `model.id`. -Model classes in Ember Data are no different than any other classes we've worked with so far, in that they allow for a convenient place for adding custom behavior. We took advantage of this feature to move our `type` logic (which is a major source of unnecessary duplication in our route handlers) into a getter on our model class. Once we have everything working here, we will go back to clean that up. +Model classes in EmberData are no different than any other classes we've worked with so far, in that they allow for a convenient place for adding custom behavior. We took advantage of this feature to move our `type` logic (which is a major source of unnecessary duplication in our route handlers) into a getter on our model class. Once we have everything working here, we will go back to clean that up. Attributes declared with the `@attr` decorator work with the auto-track feature (which we learned about [in a previous chapter](../../part-1/reusable-components/)). Therefore, we are free to reference any model attributes in our getter (`this.category`), and Ember will know when to invalidate its result. @@ -147,6 +147,8 @@ So far, we haven't had a good place to write tests for the rental property's `ty $ ember generate model-test rental installing model-test create tests/unit/models/rental-test.js + +Running "lint:fix" script... ```
@@ -163,8 +165,9 @@ installing model-test The generator created some boilerplate code for us, which serves as a pretty good starting point for writing our test: -```js { data-filename="tests/unit/models/rental-test.js" data-diff="-7,-8,+9,-11,-12,+13,+14,+15,+16,+17,+18,+19,+20,+21,+22,+23,+24,+25,+26,+27,+28,+29,+30,+31,+32,+33,+34,+35,+36,+37,+38,+39,+40,+41,+42" } +```js { data-filename="tests/unit/models/rental-test.js" data-diff="-8,-9,+10,-12,-13,+14,+15,+16,+17,+18,+19,+20,+21,+22,+23,+24,+25,+26,+27,+28,+29,+30,+31,+32,+33,+34,+35,+36,+37,+38,+39,+40,+41,+42,+43" } import { module, test } from 'qunit'; + import { setupTest } from 'super-rentals/tests/helpers'; module('Unit | Model | rental', function (hooks) { @@ -212,7 +215,11 @@ module('Unit | Model | rental', function (hooks) { This model test is also known as a _[unit test](../../../testing/testing-models/)_. Unlike any of the other tests that we've written thus far, this test doesn't actually _render_ anything. It just instantiates the rental model object and tests the model object directly, manipulating its attributes and asserting their value. -It is worth pointing out that Ember Data provides a `store` _[service](../../../services/)_, also known as the Ember Data store. In our test, we used the `this.owner.lookup('service:store')` API to get access to the Ember Data store. The store provides a `createRecord` method to instantiate our model object for us. +It is worth pointing out that EmberData provides a `store` _[service](../../../services/)_, also known as the EmberData store. In our test, we used the `this.owner.lookup('service:store')` API to get access to the EmberData store. The store provides a `createRecord` method to instantiate our model object for us. To make this `store` service available, we must add the following file: + +``` +export { default } from 'ember-data/store'; +``` Running the tests in the browser confirms that everything is working as intended: @@ -220,7 +227,7 @@ Running the tests in the browser confirms that everything is working as intended ## Loading Models in Routes -Alright, now that we have our model set up, it's time to refactor our route handlers to use Ember Data and remove the duplication! +Alright, now that we have our model set up, it's time to refactor our route handlers to use EmberData and remove the duplication! ```js { data-filename="app/routes/index.js" data-diff="-2,-3,+4,-7,-8,-9,-10,-11,-12,-13,+14,-16,-17,-18,-19,-20,-21,-22,-23,+24,+25" } import Route from '@ember/routing/route'; @@ -282,11 +289,11 @@ export default class RentalRoute extends Route { Wow... that removed a lot of code! This is all possible thanks to the power of conventions! -## The Ember Data Store +## The EmberData Store -As mentioned above, Ember Data provides a `store` service, which we can inject into our route using the `@service store;` declaration, making the Ember Data store available as `this.store`. It provides the `find` and `findAll` methods for loading records. Specifically, the [`findRecord` method](../../../models/finding-records/#toc_retrieving-a-single-record) takes a model type (`rental` in our case) and a model ID (for us, that would be `params.rental_id` from the URL) as arguments and fetches a single record from the store. On the other hand, the [`findAll` method](../../../models/finding-records/#toc_retrieving-multiple-records) takes the model type as an argument and fetches all records of that type from the store. +As mentioned above, EmberData provides a `store` service, which we can inject into our route using the `@service store;` declaration, making the EmberData store available as `this.store`. It provides the `find` and `findAll` methods for loading records. Specifically, the [`findRecord` method](../../../models/finding-records/#toc_retrieving-a-single-record) takes a model type (`rental` in our case) and a model ID (for us, that would be `params.rental_id` from the URL) as arguments and fetches a single record from the store. On the other hand, the [`findAll` method](../../../models/finding-records/#toc_retrieving-multiple-records) takes the model type as an argument and fetches all records of that type from the store. -The Ember Data store acts as a kind of intermediary between our app and the server; it does many important things, including caching the responses that were fetched from the server. If we request some records (instances of model classes) that we had _already_ fetched from the server in the past, Ember Data's store ensures that we can access the records immediately, without having to fetch them again unnecessarily and wait for the server to respond. But, if we don't already have that response cached in our store, then it will go off and fetches it from the server. Pretty nice, right? +The EmberData store acts as a kind of intermediary between our app and the server; it does many important things, including caching the responses that were fetched from the server. If we request some records (instances of model classes) that we had _already_ fetched from the server in the past, EmberData's store ensures that we can access the records immediately, without having to fetch them again unnecessarily and wait for the server to respond. But, if we don't already have that response cached in our store, then it will go off and fetches it from the server. Pretty nice, right? That's a lot of theory, but is this going to work in our app? Let's run the tests and find out! @@ -299,17 +306,17 @@ Looking at the failure messages, the problem appears to be that the store went t - When performing the `findAll('rental')` query, it requested the data from `/rentals`, instead of `/api/rentals.json`. - When performing the `find('rental', 'grand-old-mansion')` query, it requested the data from `/rentals/grand-old-mansion`, instead of `/api/rentals/grand-old-mansion.json`. -Hm, okay, so we have to teach Ember Data to fetch data from the correct location. But how does Ember Data know how to fetch data from our server in the first place? +Hm, okay, so we have to teach EmberData to fetch data from the correct location. But how does EmberData know how to fetch data from our server in the first place? ## Working with Adapters and Serializers -Ember Data uses an _[adapter](../../../models/customizing-adapters/)_ and _[serializer](../../../models/customizing-serializers/)_ architecture. Adapters deal with _how_ and _where_ Ember Data should fetch data from your servers, such as whether to use HTTP, HTTPS, WebSockets or local storage, as well as the URLs, headers and parameters to use for these requests. On the other hand, serializers are in charge of converting the data returned by the server into a format Ember Data can understand. +EmberData uses an _[adapter](../../../models/customizing-adapters/)_ and _[serializer](../../../models/customizing-serializers/)_ architecture. Adapters deal with _how_ and _where_ EmberData should fetch data from your servers, such as whether to use HTTP, HTTPS, WebSockets or local storage, as well as the URLs, headers and parameters to use for these requests. On the other hand, serializers are in charge of converting the data returned by the server into a format EmberData can understand. The idea is that, provided that your backend exposes a _consistent_ protocol and interchange format to access its data, we can write a single adapter-serializer pair to handle all data fetches for the entire application. -As it turns out, JSON:API just happens to be Ember Data's default data protocol and interchange format. Out of the box, Ember Data provides a default JSON:API adapter and serializer. This is great news for us, since that is also what our server has implemented. What a wonderful coincidence! +As it turns out, JSON:API just happens to be EmberData's default data protocol and interchange format. Out of the box, EmberData provides a default JSON:API adapter and serializer. This is great news for us, since that is also what our server has implemented. What a wonderful coincidence! -However, as mentioned above, there are some minor differences between how our server works and Ember Data's default assumptions. We can customize the default behavior by defining our own adapter and serializer: +However, as mentioned above, there are some minor differences between how our server works and EmberData's default assumptions. We can customize the default behavior by defining our own adapter and serializer: ```js { data-filename="app/adapters/application.js" } import JSONAPIAdapter from '@ember-data/adapter/json-api'; @@ -338,7 +345,7 @@ Inside this newly created file, we defined an `ApplicationAdapter` class, inheri Adding a namespace prefix happens to be pretty common across Ember apps, so the `JSONAPIAdapter` has an API to do just that. All we need to do is to set the `namespace` property to the prefix we want, which is `api` in our case. -Adding the `.json` extension is a bit less common, and doesn't have a declarative configuration API of its own. Instead, we will need to _override_ Ember Data's [`buildURL`](https://api.emberjs.com/ember-data/release/classes/JSONAPIAdapter/methods/buildURL?anchor=buildURL) method. Inside of `buildURL`, we will call `super.buildURL(...args)` to invoke the `JSONAPIAdapter` default implementation of `buildURL`. This will give us the URL that the adapter _would have built_, which would be something like `/api/rentals` and `/api/rentals/grand-old-mansion` after configuring the `namespace` above. All we have to do is to append `.json` to this URL and return it. +Adding the `.json` extension is a bit less common, and doesn't have a declarative configuration API of its own. Instead, we will need to _override_ EmberData's [`buildURL`](https://api.emberjs.com/ember-data/release/classes/JSONAPIAdapter/methods/buildURL?anchor=buildURL) method. Inside of `buildURL`, we will call `super.buildURL(...args)` to invoke the `JSONAPIAdapter` default implementation of `buildURL`. This will give us the URL that the adapter _would have built_, which would be something like `/api/rentals` and `/api/rentals/grand-old-mansion` after configuring the `namespace` above. All we have to do is to append `.json` to this URL and return it. Similarly, serializers are located at `app/serializers`. Adapters and serializers are always added together as a pair. We added an `application` adapter, so we also added a corresponding serializer to go with it as well. Since the JSON data returned by our server is JSON:API-compliant, the default [`JSONAPISerializer`](https://api.emberjs.com/ember-data/release/classes/JSONAPISerializer) work just fine for us without further customization. @@ -348,8 +355,8 @@ With our adapter and serializer in place, all our tests should pass again. The UI works exactly the same as before as well, just with much less code! -The homepage works exactly the same as before, but with much less code! +The homepage works exactly the same as before, but with much less code! -The details page works exactly the same as before, but with much less code! +The details page works exactly the same as before, but with much less code! -Ember Data offers many, many features (like managing the _relationships_ between different models) and there's a lot more we can learn about it. For example, if your backend's have some inconsistencies across different endpoints, Ember Data allows you to define more specific, per-model adapters and serializers too! We are just scratching the surface here. If you want to learn more about Ember Data, check out [its own dedicated section](../../../models/) in the guides! +EmberData offers many, many features (like managing the _relationships_ between different models) and there's a lot more we can learn about it. For example, if your backend's have some inconsistencies across different endpoints, EmberData allows you to define more specific, per-model adapters and serializers too! We are just scratching the surface here. If you want to learn more about EmberData, check out [its own dedicated section](../../../models/) in the guides! diff --git a/guides/release/tutorial/part-2/index.md b/guides/release/tutorial/part-2/index.md index 55a6896a7d..36e556d77c 100644 --- a/guides/release/tutorial/part-2/index.md +++ b/guides/release/tutorial/part-2/index.md @@ -4,13 +4,13 @@ Hooray, you've made it to the second part of the tutorial! In the following sect Along the way, we'll also add some new features to our Super Rentals app. By the end of this section, we'll have implemented some search functionality and refactored a good bit of our code to use some new Ember concepts -Search functionality in the Super Rentals app +Search functionality in the Super Rentals app In part two, we'll cover the following concepts: - Dynamic segments - Ember services -- Ember Data +- EmberData - Adapters and serializers - The provider component pattern diff --git a/guides/release/tutorial/part-2/provider-components.md b/guides/release/tutorial/part-2/provider-components.md index d5a82394ba..3948a90fd7 100644 --- a/guides/release/tutorial/part-2/provider-components.md +++ b/guides/release/tutorial/part-2/provider-components.md @@ -4,7 +4,7 @@ In this chapter, we'll work on adding a new search feature, and refactor our `in -The Super Rentals app by the end of the chapter +The Super Rentals app by the end of the chapter During this refactor, you will learn about: @@ -42,7 +42,7 @@ Well, we can start simple. Before we worry about implementing the "search" part Now if we refresh the UI, it has an `` element on the page. -The homepage with a search box, but it doesn't work yet. +The homepage with a search box, but it doesn't work yet. Awesome, one step done. Now, this input looks great, but it doesn't actually _do_ anything. @@ -99,7 +99,7 @@ Remember the small change we made in the markup when we extracted our ` Let's check our UI as well to make sure that we didn't break anything during this refactor... -The homepage looks exactly the same as before! +The homepage looks exactly the same as before! Awesome, it looks exactly the same! @@ -330,7 +330,7 @@ This is called the _provider component pattern_, which we see in action with one Okay, now that we have a better sense of which component is rendering what and the theory behind why all of this is happening, let's answer the big unanswered question: does this even work? If we try out our search box in the UI, what happens? -Trying out the search box. +Trying out the search box. Hooray, it works! Awesome. Now that we've tried this out manually in the UI, let's write a test for this new behavior as well. diff --git a/guides/release/tutorial/part-2/recap.md b/guides/release/tutorial/part-2/recap.md index 0f7cd59cf9..5cf9cc2843 100644 --- a/guides/release/tutorial/part-2/recap.md +++ b/guides/release/tutorial/part-2/recap.md @@ -21,10 +21,10 @@ There was a lot of concepts to cover in part two. To recap, here is what you lea

Chapter 11

-- Ember Data models +- EmberData models - Testing models - Loading models in routes -- The Ember Data store +- The EmberData store - Working with adapters and serializers

Chapter 12

diff --git a/guides/release/tutorial/part-2/route-params.md b/guides/release/tutorial/part-2/route-params.md index 7b4f586c10..111120dcd7 100644 --- a/guides/release/tutorial/part-2/route-params.md +++ b/guides/release/tutorial/part-2/route-params.md @@ -2,7 +2,7 @@ Now that we are fetching real data from our "server", let's add a new feature — dedicated pages for each of our rentals: -The Super Rentals app (rentals page) by the end of the chapter +The Super Rentals app (rentals page) by the end of the chapter While adding these rental pages, you will learn about: @@ -81,7 +81,7 @@ Since we know that we're linking to the `rental` route that we just created, we Let's see this in action. If we go back to our browser and refresh the page, we should see our links, but something isn't quite right yet! -Broken links +Broken links The links are all pointing to `/rentals/undefined`. Yikes! This is because `` tries to use the `id` property from our model in order to replace the dynamic segment and generate the URL. @@ -224,10 +224,12 @@ Next, let's make a `` component. $ ember generate component rental/detailed installing component create app/components/rental/detailed.hbs - skip app/components/rental/detailed.js + skip app/components/rental/detailed.ts tip to add a class, run `ember generate component-class rental/detailed` installing component-test create tests/integration/components/rental/detailed-test.js + +Running "lint:fix" script... ``` ```handlebars { data-filename="app/components/rental/detailed.hbs" data-diff="-1,+2,+3,+4,+5,+6,+7,+8,+9,+10,+11,+12,+13,+14,+15,+16,+17,+18,+19,+20,+21,+22,+23,+24,+25,+26,+27,+28,+29,+30,+31,+32,+33,+34,+35,+36,+37,+38,+39,+40,+41,+42,+43,+44,+45" } @@ -327,7 +329,7 @@ module('Integration | Component | rental/detailed', function (hooks) { test('it renders a header with a share button', async function (assert) { await render(hbs``); - assert.dom(this.element).hasText(''); + assert.dom().hasText(''); assert.dom('.jumbo').exists(); assert.dom('.jumbo h2').containsText('Grand Old Mansion'); assert @@ -345,7 +347,7 @@ module('Integration | Component | rental/detailed', function (hooks) { test('it renders detailed information about a rental property', async function (assert) { await render(hbs``); - assert.dom(this.element).hasText('template block text'); + assert.dom().hasText('template block text'); assert.dom('article').hasClass('rental'); assert.dom('article h3').containsText('About Grand Old Mansion'); assert.dom('article .detail.owner').containsText('Veruca Salt'); @@ -472,7 +474,7 @@ module('Acceptance | super rentals', function (hooks) { Now, when we visit `http://localhost:4200/rentals/grand-old-mansion`, this is what we see: -A dedicated page for the Grand Old Mansion +A dedicated page for the Grand Old Mansion And if we run our tests now... diff --git a/guides/release/tutorial/part-2/service-injection.md b/guides/release/tutorial/part-2/service-injection.md index 6de1320928..91e8d952df 100644 --- a/guides/release/tutorial/part-2/service-injection.md +++ b/guides/release/tutorial/part-2/service-injection.md @@ -4,7 +4,7 @@ As promised, we will now work on implementing the share button! -The working share button by the end of the chapter +The working share button by the end of the chapter While adding the share button, you will learn about: @@ -51,6 +51,8 @@ installing component create app/components/share-button.hbs installing component-test create tests/integration/components/share-button-test.js + +Running "lint:fix" script... ``` Let's start with the template that was generated for this component. We already have some markup for the share button in the `` component we made earlier, so let's just copy that over into our new `` component. @@ -172,7 +174,7 @@ Let's put this component to use by invoking it from the `` com With that, we should have a working share button! -A share button that works! +A share button that works!
@@ -238,7 +240,7 @@ module('Acceptance | super rentals', function (hooks) { assert.strictEqual( tweetURL.searchParams.get('url'), - `${window.location.origin}/rentals/grand-old-mansion` + `${window.location.origin}/rentals/grand-old-mansion`, ); }); @@ -393,7 +395,7 @@ module('Integration | Component | share-button', function (hooks) { setupRenderingTest(hooks); const MOCK_URL = new URL( '/foo/bar?baz=true#some-section', - window.location.origin + window.location.origin, ); test('it renders', async function (assert) { @@ -409,7 +411,7 @@ class MockRouterService extends Service { module('Integration | Component | share-button', function (hooks) { setupRenderingTest(hooks); - assert.dom(this.element).hasText(''); + assert.dom().hasText(''); hooks.beforeEach(function () { this.owner.register('service:router', MockRouterService); }); @@ -423,7 +425,7 @@ module('Integration | Component | share-button', function (hooks) { test('basic usage', async function (assert) { await render(hbs`Tweet this!`); - assert.dom(this.element).hasText('template block text'); + assert.dom().hasText('template block text'); assert .dom('a') .hasAttribute('target', '_blank') @@ -457,7 +459,7 @@ import { hbs } from 'ember-cli-htmlbars'; const MOCK_URL = new URL( '/foo/bar?baz=true#some-section', - window.location.origin + window.location.origin, ); class MockRouterService extends Service { @@ -500,7 +502,7 @@ module('Integration | Component | share-button', function (hooks) { test('it supports passing @text', async function (assert) { await render( - hbs`Tweet this!` + hbs`Tweet this!`, ); assert.strictEqual(this.tweetParam('text'), 'Hello Twitter!'); @@ -508,7 +510,7 @@ module('Integration | Component | share-button', function (hooks) { test('it supports passing @hashtags', async function (assert) { await render( - hbs`Tweet this!` + hbs`Tweet this!`, ); assert.strictEqual(this.tweetParam('hashtags'), 'foo,bar,baz'); @@ -521,7 +523,7 @@ module('Integration | Component | share-button', function (hooks) { test('it supports adding extra classes', async function (assert) { await render( - hbs`Tweet this!` + hbs`Tweet this!`, ); assert @@ -534,7 +536,7 @@ module('Integration | Component | share-button', function (hooks) { test('the target, rel and href attributes cannot be overridden', async function (assert) { await render( - hbs`Not a Tweet!` + hbs`Not a Tweet!`, ); assert diff --git a/public/downloads/style.css b/public/downloads/style.css index 8e6f89a255..04943f2349 100644 --- a/public/downloads/style.css +++ b/public/downloads/style.css @@ -1,4 +1,5 @@ -@import url(https://fonts.googleapis.com/css?family=Lato:300,300italic,400,700,700italic); +/* stylelint-disable no-descending-specificity, media-feature-range-notation */ +@import url("https://fonts.googleapis.com/css?family=Lato:300,300italic,400,700,700italic"); /** * Base Elements @@ -21,7 +22,8 @@ div, span, a, button { - font-family: 'Lato', 'Open Sans', 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif; + font-family: Lato, "Open Sans", "Helvetica Neue", "Segoe UI", Helvetica, Arial, + sans-serif; line-height: 1.5; } @@ -48,7 +50,7 @@ p { */ .button { - padding: 10px 30px 10px; + padding: 10px 30px; text-decoration: none; color: #fff; background: #016aba; @@ -63,6 +65,7 @@ p { .button:hover { opacity: 1; } + /** * Body Container */ @@ -73,14 +76,13 @@ p { background: #f9f9f9; margin: 0 auto; } + /** * Top Navigation */ .menu { height: 4em; - background-color: #677ae4; - background-color: #05526A; background-color: #e46855; } @@ -132,7 +134,7 @@ p { font-size: 18px; width: 500px; margin: 20px auto 50px; - background-color: rgba(255, 255, 255, 0.75); + background-color: rgb(255 255 255 / 75%); border: solid 1px lightgray; display: block; } @@ -166,8 +168,8 @@ p { top: 54px; left: 10px; background-color: #f6f6f6; - border-right: 1px solid rgba(0, 0, 0, 0.05); - border-bottom: 1px solid rgba(0, 0, 0, 0.05); + border-right: 1px solid rgb(0 0 0 / 5%); + border-bottom: 1px solid rgb(0 0 0 / 5%); } .results { @@ -182,6 +184,7 @@ p { .menu .results li:hover { background: #f3f3f3; } + /** * Content Area */ @@ -189,6 +192,7 @@ p { .body { padding: 15px; } + /** * Similar to Jumbotron */ @@ -260,7 +264,7 @@ p { outline: none; } -.rental button.image:after { +.rental button.image::after { content: ""; position: absolute; top: 0; @@ -276,7 +280,8 @@ p { transition: opacity 0.25s ease-in-out; } -.rental button.image:focus:after, .rental button.image:hover:after { +.rental button.image:focus::after, +.rental button.image:hover::after { opacity: 0.1; } @@ -285,7 +290,7 @@ p { } .rental .image.large { - margin: 30px 25px 50px 25px; + margin: 30px 25px 50px; flex-basis: 100%; } @@ -302,7 +307,7 @@ p { .rental .image.large small { margin-top: 10px; - margin-bottom: 0px; + margin-bottom: 0; font-size: 110%; } @@ -312,9 +317,8 @@ p { display: flex; height: 150px; margin: 20px 25px; - justify-content: space-between; + place-content: space-around space-between; flex-wrap: wrap; - align-content: space-around; } .rental h3 { @@ -341,7 +345,7 @@ p { flex-grow: 0; flex-basis: 150px; font-size: 0; - margin: 0px 25px; + margin: 0 25px; } .rental .map img { @@ -359,7 +363,7 @@ p { } .rental.detailed .image.large { - margin: 30px 25px 50px 25px; + margin: 30px 25px 50px; flex-basis: 100%; } @@ -373,7 +377,7 @@ p { } .rental.detailed .detail { - margin: 5px 0px; + margin: 5px 0; flex-basis: 100%; flex-shrink: 2; } @@ -386,7 +390,7 @@ p { .rental.detailed .map { flex-basis: 100%; - margin: 50px 25px 25px 25px; + margin: 50px 25px 25px; } .rental.detailed .map img { @@ -395,8 +399,9 @@ p { } @media only screen and (max-width: 919px) { - .rental.detailed .image, .rental.detailed .image.large { - margin: 30px 25px 25px 25px; + .rental.detailed .image, + .rental.detailed .image.large { + margin: 30px 25px 25px; flex-basis: 100%; cursor: default; } @@ -410,11 +415,11 @@ p { display: none; } - .rental.detailed button.image:hover:after { + .rental.detailed button.image:hover::after { opacity: 0; } - .rental.detailed button.image:focus:after { + .rental.detailed button.image:focus::after { opacity: 0.1; } @@ -448,20 +453,24 @@ p { } .tomster { - background: url(../assets/images/teaching-tomster.png); + background: url("../assets/images/teaching-tomster.png"); background-size: contain; background-repeat: no-repeat; height: 200px; width: 200px; - position: relative; top: -25px; } -.screen-reader{ +.screen-reader { position: absolute; overflow: hidden; clip: rect(0 0 0 0); - height: 1px; width: 1px; - margin: -1px; padding: 0; border: 0; + height: 1px; + width: 1px; + margin: -1px; + padding: 0; + border: 0; } + +/* stylelint-enable no-descending-specificity, media-feature-range-notation */ diff --git a/public/images/tutorial/part-1/automated-testing/fail@2x.png b/public/images/tutorial/part-1/automated-testing/fail@2x.png index 1b172660cf..04b13ea337 100644 Binary files a/public/images/tutorial/part-1/automated-testing/fail@2x.png and b/public/images/tutorial/part-1/automated-testing/fail@2x.png differ diff --git a/public/images/tutorial/part-1/automated-testing/pass-2@2x.png b/public/images/tutorial/part-1/automated-testing/pass-2@2x.png index 4d04d25b20..fe894f36b2 100644 Binary files a/public/images/tutorial/part-1/automated-testing/pass-2@2x.png and b/public/images/tutorial/part-1/automated-testing/pass-2@2x.png differ diff --git a/public/images/tutorial/part-1/automated-testing/pass@2x.png b/public/images/tutorial/part-1/automated-testing/pass@2x.png index a268eb6688..40b697368e 100644 Binary files a/public/images/tutorial/part-1/automated-testing/pass@2x.png and b/public/images/tutorial/part-1/automated-testing/pass@2x.png differ diff --git a/public/images/tutorial/part-1/building-pages/about-with-link@2x.png b/public/images/tutorial/part-1/building-pages/about-with-link@2x.png index d1d4ddc1c0..3b0e3daf54 100644 Binary files a/public/images/tutorial/part-1/building-pages/about-with-link@2x.png and b/public/images/tutorial/part-1/building-pages/about-with-link@2x.png differ diff --git a/public/images/tutorial/part-1/building-pages/contact-with-link@2x.png b/public/images/tutorial/part-1/building-pages/contact-with-link@2x.png index 21ba1595b1..02ec421edc 100644 Binary files a/public/images/tutorial/part-1/building-pages/contact-with-link@2x.png and b/public/images/tutorial/part-1/building-pages/contact-with-link@2x.png differ diff --git a/public/images/tutorial/part-1/building-pages/contact@2x.png b/public/images/tutorial/part-1/building-pages/contact@2x.png index 5c5b842470..9a01aa1e25 100644 Binary files a/public/images/tutorial/part-1/building-pages/contact@2x.png and b/public/images/tutorial/part-1/building-pages/contact@2x.png differ diff --git a/public/images/tutorial/part-1/building-pages/index-with-link@2x.png b/public/images/tutorial/part-1/building-pages/index-with-link@2x.png index 4c97c47e06..19349d310a 100644 Binary files a/public/images/tutorial/part-1/building-pages/index-with-link@2x.png and b/public/images/tutorial/part-1/building-pages/index-with-link@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/about@2x.png b/public/images/tutorial/part-1/component-basics/about@2x.png index d1d4ddc1c0..3b0e3daf54 100644 Binary files a/public/images/tutorial/part-1/component-basics/about@2x.png and b/public/images/tutorial/part-1/component-basics/about@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/contact@2x.png b/public/images/tutorial/part-1/component-basics/contact@2x.png index 21ba1595b1..02ec421edc 100644 Binary files a/public/images/tutorial/part-1/component-basics/contact@2x.png and b/public/images/tutorial/part-1/component-basics/contact@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/index-with-nav@2x.png b/public/images/tutorial/part-1/component-basics/index-with-nav@2x.png index bf0ab77464..ac6810a9c1 100644 Binary files a/public/images/tutorial/part-1/component-basics/index-with-nav@2x.png and b/public/images/tutorial/part-1/component-basics/index-with-nav@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/index@2x.png b/public/images/tutorial/part-1/component-basics/index@2x.png index 4c97c47e06..19349d310a 100644 Binary files a/public/images/tutorial/part-1/component-basics/index@2x.png and b/public/images/tutorial/part-1/component-basics/index@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/pass-2@2x.png b/public/images/tutorial/part-1/component-basics/pass-2@2x.png index 4d04d25b20..fe894f36b2 100644 Binary files a/public/images/tutorial/part-1/component-basics/pass-2@2x.png and b/public/images/tutorial/part-1/component-basics/pass-2@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/pass-3@2x.png b/public/images/tutorial/part-1/component-basics/pass-3@2x.png index db5060c966..fbb35a736d 100644 Binary files a/public/images/tutorial/part-1/component-basics/pass-3@2x.png and b/public/images/tutorial/part-1/component-basics/pass-3@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/pass-4@2x.png b/public/images/tutorial/part-1/component-basics/pass-4@2x.png index 2b1c3863bb..cd1d164736 100644 Binary files a/public/images/tutorial/part-1/component-basics/pass-4@2x.png and b/public/images/tutorial/part-1/component-basics/pass-4@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/pass-5@2x.png b/public/images/tutorial/part-1/component-basics/pass-5@2x.png index 2b1c3863bb..cd1d164736 100644 Binary files a/public/images/tutorial/part-1/component-basics/pass-5@2x.png and b/public/images/tutorial/part-1/component-basics/pass-5@2x.png differ diff --git a/public/images/tutorial/part-1/component-basics/pass@2x.png b/public/images/tutorial/part-1/component-basics/pass@2x.png index 4d04d25b20..fe894f36b2 100644 Binary files a/public/images/tutorial/part-1/component-basics/pass@2x.png and b/public/images/tutorial/part-1/component-basics/pass@2x.png differ diff --git a/public/images/tutorial/part-1/interactive-components/is-large-true@2x.png b/public/images/tutorial/part-1/interactive-components/is-large-true@2x.png index c2585c11b0..143a2f9870 100644 Binary files a/public/images/tutorial/part-1/interactive-components/is-large-true@2x.png and b/public/images/tutorial/part-1/interactive-components/is-large-true@2x.png differ diff --git a/public/images/tutorial/part-1/interactive-components/pass-2@2x.png b/public/images/tutorial/part-1/interactive-components/pass-2@2x.png index 6a087166ed..e66243d2bd 100644 Binary files a/public/images/tutorial/part-1/interactive-components/pass-2@2x.png and b/public/images/tutorial/part-1/interactive-components/pass-2@2x.png differ diff --git a/public/images/tutorial/part-1/interactive-components/pass@2x.png b/public/images/tutorial/part-1/interactive-components/pass@2x.png index 6a087166ed..e66243d2bd 100644 Binary files a/public/images/tutorial/part-1/interactive-components/pass@2x.png and b/public/images/tutorial/part-1/interactive-components/pass@2x.png differ diff --git a/public/images/tutorial/part-1/interactive-components/rental-image-default@2x.png b/public/images/tutorial/part-1/interactive-components/rental-image-default@2x.png index 36fe0ac64f..15a3b4fcb3 100644 Binary files a/public/images/tutorial/part-1/interactive-components/rental-image-default@2x.png and b/public/images/tutorial/part-1/interactive-components/rental-image-default@2x.png differ diff --git a/public/images/tutorial/part-1/interactive-components/rental-image-large@2x.png b/public/images/tutorial/part-1/interactive-components/rental-image-large@2x.png index d5a010eb96..e2bb80e87c 100644 Binary files a/public/images/tutorial/part-1/interactive-components/rental-image-large@2x.png and b/public/images/tutorial/part-1/interactive-components/rental-image-large@2x.png differ diff --git a/public/images/tutorial/part-1/more-about-components/pass-2@2x.png b/public/images/tutorial/part-1/more-about-components/pass-2@2x.png index 9f6a139091..2328ce3404 100644 Binary files a/public/images/tutorial/part-1/more-about-components/pass-2@2x.png and b/public/images/tutorial/part-1/more-about-components/pass-2@2x.png differ diff --git a/public/images/tutorial/part-1/more-about-components/pass@2x.png b/public/images/tutorial/part-1/more-about-components/pass@2x.png index 74ba59dbe7..f391c7e143 100644 Binary files a/public/images/tutorial/part-1/more-about-components/pass@2x.png and b/public/images/tutorial/part-1/more-about-components/pass@2x.png differ diff --git a/public/images/tutorial/part-1/more-about-components/rental-image@2x.png b/public/images/tutorial/part-1/more-about-components/rental-image@2x.png index 9fb506ea3e..dc4cf1e6a3 100644 Binary files a/public/images/tutorial/part-1/more-about-components/rental-image@2x.png and b/public/images/tutorial/part-1/more-about-components/rental-image@2x.png differ diff --git a/public/images/tutorial/part-1/more-about-components/three-old-mansions@2x.png b/public/images/tutorial/part-1/more-about-components/three-old-mansions@2x.png index 993c1c1f0a..8a34748588 100644 Binary files a/public/images/tutorial/part-1/more-about-components/three-old-mansions@2x.png and b/public/images/tutorial/part-1/more-about-components/three-old-mansions@2x.png differ diff --git a/public/images/tutorial/part-1/orientation/welcome@2x.png b/public/images/tutorial/part-1/orientation/welcome@2x.png index 2f6f2eab1c..9fa64257dd 100644 Binary files a/public/images/tutorial/part-1/orientation/welcome@2x.png and b/public/images/tutorial/part-1/orientation/welcome@2x.png differ diff --git a/public/images/tutorial/part-1/reusable-components/pass-2@2x.png b/public/images/tutorial/part-1/reusable-components/pass-2@2x.png index d2f535ddd8..68b68e9838 100644 Binary files a/public/images/tutorial/part-1/reusable-components/pass-2@2x.png and b/public/images/tutorial/part-1/reusable-components/pass-2@2x.png differ diff --git a/public/images/tutorial/part-1/reusable-components/pass-3@2x.png b/public/images/tutorial/part-1/reusable-components/pass-3@2x.png index d45fca0b97..7d320399c7 100644 Binary files a/public/images/tutorial/part-1/reusable-components/pass-3@2x.png and b/public/images/tutorial/part-1/reusable-components/pass-3@2x.png differ diff --git a/public/images/tutorial/part-1/reusable-components/pass@2x.png b/public/images/tutorial/part-1/reusable-components/pass@2x.png index f17876c911..1412b545bb 100644 Binary files a/public/images/tutorial/part-1/reusable-components/pass@2x.png and b/public/images/tutorial/part-1/reusable-components/pass@2x.png differ diff --git a/public/images/tutorial/part-1/reusable-components/three-old-mansions@2x.png b/public/images/tutorial/part-1/reusable-components/three-old-mansions@2x.png index b8c6605480..a12a18283f 100644 Binary files a/public/images/tutorial/part-1/reusable-components/three-old-mansions@2x.png and b/public/images/tutorial/part-1/reusable-components/three-old-mansions@2x.png differ diff --git a/public/images/tutorial/part-1/working-with-data/data@2x.png b/public/images/tutorial/part-1/working-with-data/data@2x.png index 70d8f8073d..8c826c4f0e 100644 Binary files a/public/images/tutorial/part-1/working-with-data/data@2x.png and b/public/images/tutorial/part-1/working-with-data/data@2x.png differ diff --git a/public/images/tutorial/part-1/working-with-data/model-header@2x.png b/public/images/tutorial/part-1/working-with-data/model-header@2x.png index 102c748cd2..2de082727c 100644 Binary files a/public/images/tutorial/part-1/working-with-data/model-header@2x.png and b/public/images/tutorial/part-1/working-with-data/model-header@2x.png differ diff --git a/public/images/tutorial/part-1/working-with-data/pass-2@2x.png b/public/images/tutorial/part-1/working-with-data/pass-2@2x.png index d45fca0b97..7d320399c7 100644 Binary files a/public/images/tutorial/part-1/working-with-data/pass-2@2x.png and b/public/images/tutorial/part-1/working-with-data/pass-2@2x.png differ diff --git a/public/images/tutorial/part-1/working-with-data/pass@2x.png b/public/images/tutorial/part-1/working-with-data/pass@2x.png index d45fca0b97..7d320399c7 100644 Binary files a/public/images/tutorial/part-1/working-with-data/pass@2x.png and b/public/images/tutorial/part-1/working-with-data/pass@2x.png differ diff --git a/public/images/tutorial/part-1/working-with-data/three-properties@2x.png b/public/images/tutorial/part-1/working-with-data/three-properties@2x.png index 68cdeb5be3..3965b327e4 100644 Binary files a/public/images/tutorial/part-1/working-with-data/three-properties@2x.png and b/public/images/tutorial/part-1/working-with-data/three-properties@2x.png differ diff --git a/public/images/tutorial/part-1/working-with-data/using-model-data@2x.png b/public/images/tutorial/part-1/working-with-data/using-model-data@2x.png index e90f0d92ea..be915f9415 100644 Binary files a/public/images/tutorial/part-1/working-with-data/using-model-data@2x.png and b/public/images/tutorial/part-1/working-with-data/using-model-data@2x.png differ diff --git a/public/images/tutorial/part-2/ember-data/detailed@2x.png b/public/images/tutorial/part-2/ember-data/detailed@2x.png index 562d316d0a..e282747d66 100644 Binary files a/public/images/tutorial/part-2/ember-data/detailed@2x.png and b/public/images/tutorial/part-2/ember-data/detailed@2x.png differ diff --git a/public/images/tutorial/part-2/ember-data/fail-1@2x.png b/public/images/tutorial/part-2/ember-data/fail-1@2x.png index ffba6e0674..6c8fb2de23 100644 Binary files a/public/images/tutorial/part-2/ember-data/fail-1@2x.png and b/public/images/tutorial/part-2/ember-data/fail-1@2x.png differ diff --git a/public/images/tutorial/part-2/ember-data/homepage@2x.png b/public/images/tutorial/part-2/ember-data/homepage@2x.png index bae12f9c74..5ff5d8e287 100644 Binary files a/public/images/tutorial/part-2/ember-data/homepage@2x.png and b/public/images/tutorial/part-2/ember-data/homepage@2x.png differ diff --git a/public/images/tutorial/part-2/ember-data/pass-1@2x.png b/public/images/tutorial/part-2/ember-data/pass-1@2x.png index 6b670377eb..510167a632 100644 Binary files a/public/images/tutorial/part-2/ember-data/pass-1@2x.png and b/public/images/tutorial/part-2/ember-data/pass-1@2x.png differ diff --git a/public/images/tutorial/part-2/ember-data/pass-2@2x.png b/public/images/tutorial/part-2/ember-data/pass-2@2x.png index 6b670377eb..510167a632 100644 Binary files a/public/images/tutorial/part-2/ember-data/pass-2@2x.png and b/public/images/tutorial/part-2/ember-data/pass-2@2x.png differ diff --git a/public/images/tutorial/part-2/provider-components/filtered-results@2x.png b/public/images/tutorial/part-2/provider-components/filtered-results@2x.png index 5fe74a37b4..42ed4a406a 100644 Binary files a/public/images/tutorial/part-2/provider-components/filtered-results@2x.png and b/public/images/tutorial/part-2/provider-components/filtered-results@2x.png differ diff --git a/public/images/tutorial/part-2/provider-components/homepage-with-inert-search@2x.png b/public/images/tutorial/part-2/provider-components/homepage-with-inert-search@2x.png index d5d3256932..82165289be 100644 Binary files a/public/images/tutorial/part-2/provider-components/homepage-with-inert-search@2x.png and b/public/images/tutorial/part-2/provider-components/homepage-with-inert-search@2x.png differ diff --git a/public/images/tutorial/part-2/provider-components/homepage-with-rentals-component@2x.png b/public/images/tutorial/part-2/provider-components/homepage-with-rentals-component@2x.png index 7057304ddb..82165289be 100644 Binary files a/public/images/tutorial/part-2/provider-components/homepage-with-rentals-component@2x.png and b/public/images/tutorial/part-2/provider-components/homepage-with-rentals-component@2x.png differ diff --git a/public/images/tutorial/part-2/provider-components/pass-1@2x.png b/public/images/tutorial/part-2/provider-components/pass-1@2x.png index 25dfae41b1..8560cda41a 100644 Binary files a/public/images/tutorial/part-2/provider-components/pass-1@2x.png and b/public/images/tutorial/part-2/provider-components/pass-1@2x.png differ diff --git a/public/images/tutorial/part-2/provider-components/pass-2@2x.png b/public/images/tutorial/part-2/provider-components/pass-2@2x.png index 9aa6d85387..c43a24a366 100644 Binary files a/public/images/tutorial/part-2/provider-components/pass-2@2x.png and b/public/images/tutorial/part-2/provider-components/pass-2@2x.png differ diff --git a/public/images/tutorial/part-2/route-params/broken-links@2x.png b/public/images/tutorial/part-2/route-params/broken-links@2x.png index 6092ca4d46..5ff5d8e287 100644 Binary files a/public/images/tutorial/part-2/route-params/broken-links@2x.png and b/public/images/tutorial/part-2/route-params/broken-links@2x.png differ diff --git a/public/images/tutorial/part-2/route-params/data@2x.png b/public/images/tutorial/part-2/route-params/data@2x.png index 70d8f8073d..8c826c4f0e 100644 Binary files a/public/images/tutorial/part-2/route-params/data@2x.png and b/public/images/tutorial/part-2/route-params/data@2x.png differ diff --git a/public/images/tutorial/part-2/route-params/grand-old-mansion@2x.png b/public/images/tutorial/part-2/route-params/grand-old-mansion@2x.png index 562d316d0a..e282747d66 100644 Binary files a/public/images/tutorial/part-2/route-params/grand-old-mansion@2x.png and b/public/images/tutorial/part-2/route-params/grand-old-mansion@2x.png differ diff --git a/public/images/tutorial/part-2/route-params/pass-2@2x.png b/public/images/tutorial/part-2/route-params/pass-2@2x.png index 7b3baa0ff8..a15a656a79 100644 Binary files a/public/images/tutorial/part-2/route-params/pass-2@2x.png and b/public/images/tutorial/part-2/route-params/pass-2@2x.png differ diff --git a/public/images/tutorial/part-2/route-params/pass-3@2x.png b/public/images/tutorial/part-2/route-params/pass-3@2x.png index 5719f61e7d..0efa4a48b3 100644 Binary files a/public/images/tutorial/part-2/route-params/pass-3@2x.png and b/public/images/tutorial/part-2/route-params/pass-3@2x.png differ diff --git a/public/images/tutorial/part-2/route-params/pass@2x.png b/public/images/tutorial/part-2/route-params/pass@2x.png index 41882bf794..6b2375dee0 100644 Binary files a/public/images/tutorial/part-2/route-params/pass@2x.png and b/public/images/tutorial/part-2/route-params/pass@2x.png differ diff --git a/public/images/tutorial/part-2/service-injection/fail@2x.png b/public/images/tutorial/part-2/service-injection/fail@2x.png index e94b8a9e19..55ac3f3cdc 100644 Binary files a/public/images/tutorial/part-2/service-injection/fail@2x.png and b/public/images/tutorial/part-2/service-injection/fail@2x.png differ diff --git a/public/images/tutorial/part-2/service-injection/pass-1@2x.png b/public/images/tutorial/part-2/service-injection/pass-1@2x.png index 94131cdeca..d5390cf1bd 100644 Binary files a/public/images/tutorial/part-2/service-injection/pass-1@2x.png and b/public/images/tutorial/part-2/service-injection/pass-1@2x.png differ diff --git a/public/images/tutorial/part-2/service-injection/pass-2@2x.png b/public/images/tutorial/part-2/service-injection/pass-2@2x.png index 1fa9b22663..7b05b979ad 100644 Binary files a/public/images/tutorial/part-2/service-injection/pass-2@2x.png and b/public/images/tutorial/part-2/service-injection/pass-2@2x.png differ diff --git a/public/images/tutorial/part-2/service-injection/share-button@2x.png b/public/images/tutorial/part-2/service-injection/share-button@2x.png index 562d316d0a..68b217548b 100644 Binary files a/public/images/tutorial/part-2/service-injection/share-button@2x.png and b/public/images/tutorial/part-2/service-injection/share-button@2x.png differ