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

EZP-27782: All tabs, from unrelated blocks, become unselected after clicking on any other tab #36

Closed
wants to merge 2 commits into from
Closed

EZP-27782: All tabs, from unrelated blocks, become unselected after clicking on any other tab #36

wants to merge 2 commits into from

Conversation

sunpietro
Copy link

@sunpietro sunpietro commented Aug 17, 2017

https://jira.ez.no/browse/EZP-27782

Now, the script is looking for the closest tabs container that contains selected tabs instead of searching in whole page document.

The HTML markup where an issue had been spotted:

<ez-server-side-content>
    <section class="ez-tabs ez-dashboard-tabs">
        <ul class="ez-tabs-list">
            <li class="ez-tabs-label is-tab-selected"><a href="#all_content">Content</a></li>
            <li class="ez-tabs-label"><a href="#all_media">Media</a></li>
        </ul>

        <ez-asynchronous-block class="ez-tabs-panel is-tab-selected" id="all_content" url="/all_content"></ez-asynchronous-block>
        <ez-asynchronous-block class="ez-tabs-panel" id="all_media" url="/all_media"></ez-asynchronous-block>
    </section>

    <section class="ez-tabs ez-dashboard-tabs">
        <ul class="ez-tabs-list">
            <li class="ez-tabs-label is-tab-selected"><a href="#my_content">My content</a></li>
            <li class="ez-tabs-label"><a href="#my_drafts">My drafts</a></li>
            <li class="ez-tabs-label"><a href="#my_media">My media</a></li>
        </ul>

        <ez-asynchronous-block class="ez-tabs-panel is-tab-selected" id="my_content" url="/my_content"></ez-asynchronous-block>
        <ez-asynchronous-block class="ez-tabs-panel" id="my_drafts" url="/my_drafts"></ez-asynchronous-block>
        <ez-asynchronous-block class="ez-tabs-panel" id="my_media" url="/my_media"></ez-asynchronous-block>
    </section>
</ez-server-side-content>

forEach.call(this.querySelectorAll('.' + TAB_IS_SELECTED), function (element) {
element.classList.remove(TAB_IS_SELECTED);
});
[].forEach.call(selectedTabs, (element) => element.classList.remove(TAB_IS_SELECTED));
Copy link

@andrerom andrerom Aug 17, 2017

Choose a reason for hiding this comment

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

however I don't find the line here particular easy to read, one thing is the short form for functions which I'm not used to, but even Array.prototype would have been cleaner then the empty array. But thats somewhat a style preference, and if this is more the style things are done now I can perhaps get used to it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @andrerom on [].forEach vs. Array.prototype.forEach, especially given this change is completely unrelated to the issue (and useless) so to keep the patch as short as possible, I would only change the first parameter of forEach.call.

that said thanks to the web components polyfill, you can even use forEach method directly on NodeList returned by querySelectorAll.
(see #30 (comment))

For fat arrow vs. regular function, we tend to use fat arrow to avoid using bind but that's fine this way as well.

Copy link
Contributor

@dpobel dpobel left a comment

Choose a reason for hiding this comment

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

instead of searching in whole page document.

normally we don't search in the whole page but only within the custom element on which ez-tabs mixin is applied.

So I guess to reproduce the issue you must have 2 different series of tabs in a custom element having this mixin, right ? Could you please add in the PR description a minimal markup example to reproduce the issue ?

@@ -1,5 +1,5 @@
window.eZ = window.eZ || {};

/* jshint esversion:6 */
Copy link
Contributor

@dpobel dpobel Aug 21, 2017

Choose a reason for hiding this comment

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

that's not needed normally, see https://github.com/ezsystems/hybrid-platform-ui-core-components/blob/master/.eslintrc.json#L8

I've just notice the jshint part, we don't use jshint here, so please remove that line.

@@ -107,23 +107,25 @@ window.eZ = window.eZ || {};
*
* @param {HTMLElement} panel
* @param {HTMLElement} tabsLabel
* @param event {Event} click event
Copy link
Contributor

Choose a reason for hiding this comment

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

for consistency please put the type first

forEach.call(this.querySelectorAll('.' + TAB_IS_SELECTED), function (element) {
element.classList.remove(TAB_IS_SELECTED);
});
[].forEach.call(selectedTabs, (element) => element.classList.remove(TAB_IS_SELECTED));
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @andrerom on [].forEach vs. Array.prototype.forEach, especially given this change is completely unrelated to the issue (and useless) so to keep the patch as short as possible, I would only change the first parameter of forEach.call.

that said thanks to the web components polyfill, you can even use forEach method directly on NodeList returned by querySelectorAll.
(see #30 (comment))

For fat arrow vs. regular function, we tend to use fat arrow to avoid using bind but that's fine this way as well.

@sunpietro
Copy link
Author

@dpobel updated description and corrected minor issues pointed.

Copy link
Contributor

@dpobel dpobel left a comment

Choose a reason for hiding this comment

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

besides the inline comment, you also need to write a unit test where you reproduce the issue when there are several .ez-tabs elements.

@@ -78,7 +78,7 @@ window.eZ = window.eZ || {};

e.preventDefault();
if ( this._dispatchTabChange(label, panel) ) {
this._changeTab(panel, label);
this._changeTab(panel, label, e);
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of passing the event object until _unselectTab, I think you should compute the tab container here to have:

const tabContainer = e.target.closest('.ez-tabs');

this._changeTab(tabContainer, panel, label);

@sunpietro
Copy link
Author

@dpobel I've added updated tests. Any comments are welcome.

Copy link
Contributor

@dpobel dpobel left a comment

Choose a reason for hiding this comment

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

weird TravisCI did not run on this PR, I've changed a settings let's see if it sees the PR when you'll push changes (also rebase on master so that you get a small fix to npm run lint 5b545c3).
But in any case please run the tests locally (https://github.com/ezsystems/hybrid-platform-ui-core-components/blob/master/README.md#developers-tasks)

@@ -107,21 +109,24 @@ window.eZ = window.eZ || {};
*
* @param {HTMLElement} panel
* @param {HTMLElement} tabsLabel
* @param {HTMLElement} tabs container DOM node
Copy link
Contributor

@dpobel dpobel Aug 30, 2017

Choose a reason for hiding this comment

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

the parameter name is tabsContainer not tabs


tabsLabel.classList.add(TAB_IS_SELECTED);
panel.classList.add(TAB_IS_SELECTED);
}

/**
* Unselects currently selected tabs
*
* @param {HTMLElement} tabs container DOM node
Copy link
Contributor

Choose a reason for hiding this comment

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

same on doc parameter name

</template>
</test-fixture>

<test-fixture id="AdvancedTestFixture">
Copy link
Contributor

Choose a reason for hiding this comment

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

it's not really an advanced test but a regression test for the case where there are several tabs series, so I would call it SeveralTabsSeriesTestFixture

</div>
</div>
</ez-test-tabs>
<ez-test-tabs>
Copy link
Contributor

Choose a reason for hiding this comment

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

with this markup, you don't test the bug you are fixing which is happening is you have several tabs series in the custom element where Tabs mixin is applied. So you should have only one ez-test-tabs element with at least 2 tabs markup.

bubbles: true,
}));
}
element = fixture('BasicTestFixture');
Copy link
Contributor

Choose a reason for hiding this comment

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

this needs to be inside beforeEach so that each test starts with a fresh element/markup (see https://www.polymer-project.org/2.0/docs/tools/tests#test-fixtures)

const CLASS_TAB_SELECTED = 'is-tab-selected';
const SELECTOR_TAB_SELECTED = '.is-tab-selected';

element = fixture('AdvancedTestFixture');
Copy link
Contributor

Choose a reason for hiding this comment

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

should be in beforeEach as well

@@ -105,4 +103,38 @@ describe('ez-tabs', function () {
});
});
});

describe('switch tab in a correct container', function () {
Copy link
Contributor

Choose a reason for hiding this comment

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

describe('several tabs series', function () {

panel = element.querySelector(link.getAttribute('href'));
});

it('should change tab in a correct tabs container', function () {
Copy link
Contributor

Choose a reason for hiding this comment

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

actually here we want to test 2 things so I think you should write 2 tests:

  • should change tab which should be the same as 'switch tab' / 'should change tab' (so you should extract the code of it in a function for instance called testChangeTab and call it in both cases)
  • should leave others tabs intact which will also call testChangeTab but in addition check that the other tabs have not changed (for that the easiest is probably to compare .innerHTML of the other tab container before and after the tab change)

<div class="ez-tabs-panel" id="tab2">
Some other content
</div>
<ez-asynchronous-block id="async-tab"></ez-asynchronous-block>
Copy link
Contributor

Choose a reason for hiding this comment

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

since mixins/js/ez-tabs.js is also included in this file, you need to add the SeveralTabsSeriesTestFixture here as well (but make sure to use ez-content-view not ez-test-tabs)

<div class="ez-tabs-panel" id="tab2">
Some other content
</div>
<ez-asynchronous-block id="async-tab"></ez-asynchronous-block>
Copy link
Contributor

Choose a reason for hiding this comment

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

and same here, mixins/js/ez-tabs.js is included in this file as well so a SeveralTabsSeriesTestFixture is needed

@sunpietro sunpietro closed this Sep 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants