Skip to content

Commit

Permalink
✨ Interactive poll can have options with two lines (ampproject#30153)
Browse files Browse the repository at this point in the history
* Added base for two lines

* Sizing works for options on polls

* Added tests to check sizes (and extra tests for polls)

* Using Array.some for hasTwoLines
  • Loading branch information
mszylkowski authored and ed-bird committed Dec 10, 2020
1 parent 7ba780e commit 475626c
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 3 deletions.
2 changes: 1 addition & 1 deletion examples/amp-story/interactive_polls.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ <h1>What adorable animal are you?</h1>
chip-style="shadow"
option-1-text="Stretching your back" option-1-results-category="Cat"
option-2-text="Caressing your mustache" option-2-results-category="Mouse"
option-3-text="Jumping all over the place" option-3-results-category="Bunny"
option-3-text="Jumping all over the place nonstop because they want and they can do that because they are free" option-3-results-category="Bunny"
option-4-text="Running behind a ball" option-4-results-category="Dog">
</amp-story-interactive-poll>
</amp-story-grid-layer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,18 @@
z-index: 1 !important;
transition: transform var(--i-amphtml-interactive-animation-time) var(--i-amphtml-interactive-ease-out-curve) !important;
transform-origin: left !important;
white-space: nowrap !important;
line-height: 1.3em !important;
word-wrap: break-word !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 2 !important;
-webkit-box-orient: vertical !important;
max-height: 2.6em !important;
}

.i-amphtml-story-interactive-poll-two-lines .i-amphtml-story-interactive-option-text {
font-size: 1.125em !important;
}

.i-amphtml-story-interactive-poll-container[dir="rtl"] .i-amphtml-story-interactive-option-text{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import {
InteractiveType,
} from './amp-story-interactive-abstract';
import {CSS} from '../../../build/amp-story-interactive-poll-0.1.css';
import {computedStyle, setStyle} from '../../../src/style';
import {dev} from '../../../src/log';
import {htmlFor} from '../../../src/static-template';
import {setStyle} from '../../../src/style';
import {toArray} from '../../../src/types';

/**
* Generates the template for the poll.
Expand Down Expand Up @@ -79,6 +81,13 @@ export class AmpStoryInteractivePoll extends AmpStoryInteractive {
return this.rootEl_;
}

/** @override */
layoutCallback() {
return this.adaptFontSize_(dev().assertElement(this.rootEl_)).then(() =>
super.layoutCallback()
);
}

/**
* Finds the prompt and options content
* and adds it to the quiz element.
Expand Down Expand Up @@ -134,4 +143,43 @@ export class AmpStoryInteractivePoll extends AmpStoryInteractive {
setStyle(currOption, '--option-percentage', percentages[index] + '%');
});
}

/**
* This method changes the font-size to best display the options, measured only once on create.
*
* If two lines appear, it will add the class 'i-amphtml-story-interactive-poll-two-lines'
* It measures the number of lines on all options and generates the best size.
* - font-size: 22px (1.375em) - All options are one line
* - font-size: 18px (1.125em) - Any option is two lines if displayed at 22px.
*
* @private
* @param {!Element} root
* @return {!Promise}
*/
adaptFontSize_(root) {
let hasTwoLines = false;
const allOptionTexts = toArray(
root.querySelectorAll('.i-amphtml-story-interactive-option-text')
);
return this.measureMutateElement(
() => {
hasTwoLines = allOptionTexts.some((e) => {
const lines = Math.round(
e./*OK*/ clientHeight /
parseFloat(
computedStyle(this.win, e)['line-height'].replace('px', '')
)
);
return lines >= 2;
});
},
() => {
this.rootEl_.classList.toggle(
'i-amphtml-story-interactive-poll-two-lines',
hasTwoLines
);
},
root
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/**
* Copyright 2019 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {AmpStoryInteractivePoll} from '../amp-story-interactive-poll';
import {AmpStoryRequestService} from '../../../amp-story/1.0/amp-story-request-service';
import {AmpStoryStoreService} from '../../../amp-story/1.0/amp-story-store-service';
import {Services} from '../../../../src/services';
import {
addConfigToInteractive,
getMockInteractiveData,
} from './test-amp-story-interactive';
import {measureMutateElementStub} from '../../../../testing/test-helper';
import {registerServiceBuilder} from '../../../../src/service';

describes.realWin(
'amp-story-interactive-poll',
{
amp: true,
},
(env) => {
let win;
let ampStoryPoll;
let storyEl;
let requestService;

beforeEach(() => {
win = env.win;

env.sandbox
.stub(Services, 'cidForDoc')
.resolves({get: () => Promise.resolve('cid')});

const ampStoryPollEl = win.document.createElement(
'amp-story-interactive-poll'
);
ampStoryPollEl.getResources = () => win.__AMP_SERVICES.resources.obj;
requestService = new AmpStoryRequestService(win);
registerServiceBuilder(win, 'story-request', function () {
return requestService;
});

const storeService = new AmpStoryStoreService(win);
registerServiceBuilder(win, 'story-store', function () {
return storeService;
});

storyEl = win.document.createElement('amp-story');
const storyPage = win.document.createElement('amp-story-page');
const gridLayer = win.document.createElement('amp-story-grid-layer');
gridLayer.appendChild(ampStoryPollEl);
storyPage.appendChild(gridLayer);
storyEl.appendChild(storyPage);

win.document.body.appendChild(storyEl);
ampStoryPoll = new AmpStoryInteractivePoll(ampStoryPollEl);
env.sandbox
.stub(ampStoryPoll, 'measureMutateElement')
.callsFake(measureMutateElementStub);
env.sandbox.stub(ampStoryPoll, 'mutateElement').callsFake((fn) => fn());
});

it('should throw an error with fewer than two options', () => {
addConfigToInteractive(ampStoryPoll, 1);
allowConsoleError(() => {
expect(() => {
ampStoryPoll.buildCallback();
}).to.throw(/Improper number of options/);
});
});

it('should not throw an error with two options', () => {
addConfigToInteractive(ampStoryPoll, 2);
expect(() => ampStoryPoll.buildCallback()).to.not.throw();
});

it('should throw an error with more than four options', () => {
addConfigToInteractive(ampStoryPoll, 5);
allowConsoleError(() => {
expect(() => {
ampStoryPoll.buildCallback();
}).to.throw(/Improper number of options/);
});
});

it('should fill the content of the options', async () => {
ampStoryPoll.element.setAttribute('option-1-text', 'Fizz');
ampStoryPoll.element.setAttribute('option-2-text', 'Buzz');
await ampStoryPoll.buildCallback();
await ampStoryPoll.layoutCallback();
expect(ampStoryPoll.getOptionElements()[0].textContent).to.contain(
'Fizz'
);
expect(ampStoryPoll.getOptionElements()[1].textContent).to.contain(
'Buzz'
);
});

it('should handle the percentage pipeline', async () => {
env.sandbox
.stub(requestService, 'executeRequest')
.resolves(getMockInteractiveData());

ampStoryPoll.element.setAttribute('endpoint', 'http://localhost:8000');

addConfigToInteractive(ampStoryPoll, 2);
await ampStoryPoll.buildCallback();
await ampStoryPoll.layoutCallback();

expect(ampStoryPoll.getOptionElements()[0].innerText).to.contain('50 %');
expect(ampStoryPoll.getOptionElements()[1].innerText).to.contain('50 %');
});

it('should have large font size if options are short', async () => {
ampStoryPoll.element.setAttribute(
'option-1-text',
'This is a short text'
);
ampStoryPoll.element.setAttribute(
'option-2-text',
'This is another text'
);
await ampStoryPoll.buildCallback();
await ampStoryPoll.layoutCallback();
expect(
ampStoryPoll
.getRootElement()
.classList.contains('i-amphtml-story-interactive-poll-two-lines')
).to.be.false;
});

it('should have small font size if options are long', async () => {
ampStoryPoll.element.setAttribute(
'option-1-text',
'This is a really really really really really long text'
);
ampStoryPoll.element.setAttribute(
'option-2-text',
'This is another text'
);
await ampStoryPoll.buildCallback();
await ampStoryPoll.layoutCallback();
expect(
ampStoryPoll
.getRootElement()
.classList.contains('i-amphtml-story-interactive-poll-two-lines')
).to.be.true;
});
}
);

0 comments on commit 475626c

Please sign in to comment.