Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨amp-consent: Added a default loading placeholder for the consent UI #19841

Merged
merged 14 commits into from Dec 19, 2018

Conversation

torch2424
Copy link
Contributor

relates to #18828

This adds a loading spinner provided by @sparhami , and available as a jsbin: https://jsbin.com/yerevoz/1/edit?html,output

Simply adds this svg and styling whenever a loading placeholder is not provided. Note: This placeholder is 30px x 30px as that is the only default height we can guarantee for the amp consent footer thing. Any ideas on how to size the placeholder would be appreciated 😄 👍

loadingplaceholderampconsent

<defs>
<linearGradient id="grad">
<stop stop-color="rgb(105, 105, 105)"></stop>
<stop offset="100%" stop-color="rgba(105, 105, 105, 0)"></stop>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to update the code to make it work on Safari correctly. You'll need to do:

stop-color="rgb(105, 105, 105) stop-opacity="0"

instead here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Will update now 😄

Copy link
Contributor

@zhouyx zhouyx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me with a few nits. Before merging the change, please make sure to sync with @spacedino and show them the demo on several real devices.

placeholder: 'i-amphtml-consent-placeholder',
loading: 'i-amphtml-consent-ui-loading',
fill: 'i-amphtml-consent-ui-fill',
loadingPlaceholder: 'i-amphtml-consent-ui-loading-placeholder',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Well, placeholder by default means loading placeholder to me. Can we name it placeholder: i-amphtml-consent-ui-placeholder instead : ) A shorter name

classList.add(consentUiClasses.placeholder);
classList.add(consentUiClasses.loadingPlaceholder);

const loadingSpinner = htmlFor(placeholder)`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Is it possible to declare the string as a const at the top of the file?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe @kristoferbaxter was looking into doing a compilation pass to do this, so it may not be worth worrying about.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I originally had it as a const at the top of the file, but from what @kristoferbaxter showed me, it appeared to be using the htmlFor keyword in order to find the template strings to then be optimized. Thus I did it this way to help with that.

Though I may be wrong, we will see what Kris says 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this htmlFor usage is within a method, it will be hoisted automatically in the single pass build. Makes the most sense within source code to place it where it is easiest to understand.

Please note: This optimization is only true in the single-pass build.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thanks!

So I tried hoisting this to the top of the file, and the linter then throws syntax errors. Also, tried binding it with ${placeholderHtml}, but the template can't take in variables. I think we may need to do some additional work to allow the codebase to handle this.

Doing a quick project search, seems htmlFor() always has the template immediately after it.

@@ -41,19 +41,35 @@ amp-consent.amp-hidden {
visibility: hidden;
}

amp-consent.i-amphtml-consent-loading {
/* TODO: Finalize the placeholder design */
@keyframes loading-placeholder-spin {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe prefix with amp-consent into the name of this, since keyframe names are global

// Pop onto the back of the event queue,
// so we expect() once our mutate element in show() resolves
return mockInstance.mutateElement(() => {}).then(() => {
expect(placeholder.hasAttribute('hidden')).to.not.be.ok;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about expect(placeholder.hidden).to.be.false?

// so we expect() once our mutate element in show() resolves
return mockInstance.mutateElement(() => {}).then(() => {
expect(placeholder.hasAttribute('hidden')).to.not.be.ok;
expect(placeholder.childNodes.length).to.be.above(0);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try expect(placeholder.childNodes).to.not.be.empty

@@ -238,12 +239,25 @@ export class ConsentUI {
* @return {!Element}
*/
createPlaceholder_() {
// TODO(@zhouyx): Allow publishers to provide placeholder upon request
const placeholder = this.parent_.ownerDocument.createElement('placeholder');
toggle(placeholder, false);
const {classList} = placeholder;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And can remove this now.

Suggested change
const {classList} = placeholder;

const placeholder = this.parent_.ownerDocument.createElement('placeholder');
toggle(placeholder, false);
const {classList} = placeholder;
classList.add(consentUiClasses.fill);
classList.add(consentUiClasses.placeholder);
classList.add(consentUiClasses.loadingPlaceholder);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're only adding a single class to the classList, you can remove the line above and just call directly.

Suggested change
classList.add(consentUiClasses.loadingPlaceholder);
placeholder.classList.add(consentUiClasses.loadingPlaceholder);

</linearGradient>
</defs>
<path d="M11,4.4 A18,18, 0,1,0, 38,20" stroke="url(#grad)"></path>
</svg>`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're using this definition in multiple places, it also might be a good idea to store it externally and import into this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of now, we are only thinking of using this here. Was asking @sparhami about this in the past, if we had a system in place for re-used html elements, and it appears that we do not. So we should probably do that as well if we continue to add more HTML literals.

Copy link
Contributor

@kristoferbaxter kristoferbaxter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some details about htmlFor and a change for the classList usage.

@torch2424
Copy link
Contributor Author

@sparhami @zhouyx @kristoferbaxter

Replied to comments / Made requested changes 😄

toggle(dev().assertElement(this.ui_), false);
this.win_.addEventListener('message', this.boundHandleIframeMessages_);
insertAfterOrAtStart(this.parent_, dev().assertElement(this.ui_), null);
return this.iframeReady_.promise;

return this.baseInstance_.mutateElement(() => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be a bit more natural as:

return Promise.all([
  this.iframeReady_.promise,
  this.baseInstance_.mutateElement(() => {
    toggle(dev().assertElement(this.placeholder_), true);
  }),
]);

Its not really a performance difference in this case, but seems to more clearly communicate that the two async things are independent.

@@ -238,12 +239,24 @@ export class ConsentUI {
* @return {!Element}
*/
createPlaceholder_() {
// TODO(@zhouyx): Allow publishers to provide placeholder upon request
const placeholder = this.parent_.ownerDocument.createElement('placeholder');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it is too late to change this, but you shouldn't use a tag name like placeholder. A browser could add one with certain semantics that might be a problem. You should only ever use valid html tag names or include a dash in the name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should change this.

However, @zhouyx do you see any problem in changing this? Is there more code already in place around this idea?

@@ -142,6 +145,32 @@ describes.realWin('consent-ui', {
});
});

describe('placeholder', () => {
it('should add a placeholder element' +

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having placeholder here feels a bit redundant. The test will read as "consent-ui placeholder should add a placeholder element while loading CMP Iframe". Consider something like "consent-ui placeholder should be present while loading CMP Iframe".


const placeholder = consentUI.placeholder_;
expect(placeholder).to.be.ok;
expect(placeholder.hasAttribute('hidden')).to.be.ok;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expect(placeholder.hidden).to.be.true;


// Pop onto the back of the event queue,
// so we expect() once our mutate element in show() resolves
return mockInstance.mutateElement(() => {}).then(() => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be better to write this as an async test. Since it is just a test, no need to worry about the code generated to transform async/await into promises. That is:

should('...', async () => {
   ...
  await mockInstance.mutateElement(() => {});
  expect(...);
});

@torch2424
Copy link
Contributor Author

@sparhami @zhouyx @kristoferbaxter

Replied to comments / Made requested changes 😄

@torch2424
Copy link
Contributor Author

Thanks for the approval @sparhami !

Going to wait for a design approval from @spacedino and then pull this in (for anyone wondering)

@torch2424
Copy link
Contributor Author

Had the design review, Loading Placeholder and transition were approved. With some last design changes to be implemented documented here: #19969

Merging...

@torch2424 torch2424 merged commit a8d1fd3 into ampproject:master Dec 19, 2018
@torch2424 torch2424 deleted the amp-consent-loading-placeholder branch December 19, 2018 01:08
@torch2424 torch2424 mentioned this pull request Dec 19, 2018
5 tasks
bramanudom pushed a commit to bramanudom/amphtml that referenced this pull request Dec 19, 2018
…mpproject#19841)

* Added the loading placeholder html

* Added the svg, and renamed some classes for consistency

* Finished styles for the placeholder spinner

* Need to stop the height flash/jump thing

* Finished up the loading placeholder

* Started tests, used htmlFor

* Added tests for placeholder

* Fixed precommit checks

* Added fix for safari on svg

* Another safari fix for svg

* Made all requested changes

* Made requested changes

* Made all requested changes
noranazmy pushed a commit to noranazmy/amphtml that referenced this pull request Mar 22, 2019
…mpproject#19841)

* Added the loading placeholder html

* Added the svg, and renamed some classes for consistency

* Finished styles for the placeholder spinner

* Need to stop the height flash/jump thing

* Finished up the loading placeholder

* Started tests, used htmlFor

* Added tests for placeholder

* Fixed precommit checks

* Added fix for safari on svg

* Another safari fix for svg

* Made all requested changes

* Made requested changes

* Made all requested changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants