Skip to content
This repository was archived by the owner on Jan 22, 2021. It is now read-only.
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ You can also use a separate template for the dropdown and dropdown trigger conte

Note that `dropdownTrigger` needs the template name in the `template` argument.

### Additional arguments
### Dropdown arguments

The `dropdown` helper takes additional arguments for positioning and custom classes. The names are:

Expand All @@ -92,6 +92,22 @@ The `dropdown` helper takes additional arguments for positioning and custom clas
{{/dropdown}}
```

### Trigger arguments

The `dropdownTrigger` helper takes additional arguments for change trigger event. The names are:
- `on` - Defaults to `click`. Set to `hover` for respond to the pointing of the mouse. Set `none` for disable trigger logic. You can use `usePosition` for write your own reactions logic.
- `timeout` - Defaults is `0`. Set a number to have time to move the mouse from the `dropdownTrigger` on the `dropdown`.
-
```html
{{#dropdownTrigger name="testDropdown4" on="hover" timeout=500}}
<button>Hover with timeout</button>
{{/dropdownTrigger}}

{{#dropdown name="testDropdown4" top="-10" direction="n"}}
<p>Custom dropdown.</p>
{{/dropdown}}
```

### Markup & Classes

The `dropdownTrigger` template helper doesn't produce any extra HTML around your content. `dropdown` on the other hand produces the following HTML:
Expand All @@ -105,7 +121,7 @@ The `dropdownTrigger` template helper doesn't produce any extra HTML around your

<button class="dropdown__trigger">A trigger</button>

{{#dropdown name="testDropdown4" align="center" top="20" left="10" classes="custom-class"}}
{{#dropdown name="testDropdown5" align="center" top="20" left="10" classes="custom-class"}}
<!-- Content [..] -->
{{/dropdown}}

Expand All @@ -115,7 +131,7 @@ The `dropdownTrigger` template helper doesn't produce any extra HTML around your
class="dropdown test-dropdown4 custom-class"
id="test-dropdown4"
style="position: absolute; left: XXpx; top: XXpx;"
data-dropdown-key="testDropdown4"
data-dropdown-key="testDropdown5"
data-dropdown-align="center"
data-dropdown-left="10"
data-dropdown-top="20">
Expand All @@ -137,8 +153,8 @@ Please note that the `name` template argument will be present as `id` and `class
In order to detect active, opened dropdowns, the global `dropdownIsActive` helper can be used:

```
{{#dropdownTrigger name="testDropdown5"}}
<button class="{{#if dropdownIsActive 'testDropdown5'}}dropdown--open{{/if}}">A trigger</button>
{{#dropdownTrigger name="testDropdown6"}}
<button class="{{#if dropdownIsActive 'testDropdown6'}}dropdown--open{{/if}}">A trigger</button>
{{/dropdownTrigger}}
```

Expand All @@ -155,11 +171,11 @@ Template.testTemplate.helpers(

```html
<template name="testTemplate">
{{#dropdownTrigger name="testDropdown6"}}
{{#dropdownTrigger name="testDropdown7"}}
<button>Dropdown with data</button>
{{/dropdownTrigger}}

{{#dropdown name="testDropdown6" classes="dropdown--menu" align="left"}}
{{#dropdown name="testDropdown7" classes="dropdown--menu" align="left"}}

<ul class="dropdown__menu">
{{#each items}}
Expand Down Expand Up @@ -275,6 +291,9 @@ Dropdowns.removeAll()
# Manually set a position of a dropdown. Both x and y are optional.
Dropdowns.setPosition('name', {x: Number, y: Number})

# Automatically calculate position based on trigger template for current dropdown.
Dropdowns.usePosition('name', dropdownTriggerTemplate)

# Hide all dropdowns except for `name` (can also be an array of names).
Dropdowns.hideAllBut('name')

Expand Down
47 changes: 44 additions & 3 deletions lib/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ const factory = () => {

const removeAll = () =>
allKeys().forEach(remove);

const usePosition = (name, tmpl) =>
Tracker.afterFlush(positionDropdown(name, tmpl));

return {
all,
Expand All @@ -190,6 +193,7 @@ const factory = () => {
remove,
removeAll,
setPosition,
usePosition,
create: add,
animations: {
default: DEFAULT_ANIMATION
Expand Down Expand Up @@ -311,8 +315,13 @@ const positionDropdown = (key, reference) => {
}

const $dropdown = dropdown.element();
const $el = $(reference);


if (typeof(reference) === 'object' && reference instanceof Blaze.TemplateInstance)
var $el = $(reference.find('>'));
else
var $el = $(reference);


if ($dropdown.length === 0) {
console.error(`Dropdowns: Couldn't find a dropdown: ${key}`);
return;
Expand Down Expand Up @@ -372,15 +381,47 @@ const positionDropdown = (key, reference) => {
};
};

Dropdowns._timeout;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actually no need to define this here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Rewrite it to?

var timeout;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need to declare it – you'll attach it further down, at this line anyway, and JS/Meteor doesn't care if the parameter passed to Meteor.clearTimeout is undefined.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I try. It does not work.


Template.dropdownTrigger.events({
click(evt, tmpl) {
if (tmpl.data.on && tmpl.data.on !== 'click') return;
evt.preventDefault();
const name = tmpl.data.name;

Meteor.clearTimeout(Dropdowns._timeout);
Dropdowns.hideAllBut(name);
Dropdowns.toggle(name);
Dropdowns.usePosition(name, tmpl);
},
mouseover(evt, tmpl) {
if (tmpl.data.on != 'hover') return;
evt.preventDefault();
const name = tmpl.data.name;

Tracker.afterFlush(positionDropdown(name, tmpl.find(DROPDOWN_TRIGGER)));
Meteor.clearTimeout(Dropdowns._timeout);
Dropdowns.hideAllBut(name);
Dropdowns.show(name);
Dropdowns.usePosition(name, tmpl);
},
mouseout(evt, tmpl) {
if (tmpl.data.on != 'hover') return;
evt.preventDefault();
const name = tmpl.data.name;

Meteor.clearTimeout(Dropdowns._timeout);
Dropdowns._timeout = Meteor.setTimeout(() => {
Dropdowns.hide(name);
}, tmpl.data.timeout);

Dropdowns.get(name).element().hover(() => {
Meteor.clearTimeout(Dropdowns._timeout);
}, () => {
Meteor.clearTimeout(Dropdowns._timeout);
Dropdowns._timeout = Meteor.setTimeout(() => {
Dropdowns.hide(name);
}, tmpl.data.timeout);
})
}
});

Expand Down
70 changes: 56 additions & 14 deletions test-app/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ <h1>Dropdowns for Meteor</h1>

<ol class="toc">
<li><a href="#basics">Basics</a></li>
<li><a href="#arguments">Additional Arguments</a></li>
<li><a href="#dropdown-arguments">Dropdown Arguments</a></li>
<li><a href="#trigger-arguments">Trigger Arguments</a></li>
<li><a href="#markup-classes">Markup &amp; Classes</a></li>
<li><a href="#helpers">Helpers</a></li>
<li><a href="#data">Data Contexts</a></li>
Expand Down Expand Up @@ -107,9 +108,9 @@ <h2 id="basics">Basics</h2>

<p>Note that <code>dropdownTrigger</code> needs the template name in the <code>template</code> argument.</p>

<h2 id="arguments">Additional arguments</h2>
<h2 id="dropdown-arguments">Dropdown arguments</h2>

<p>The <code>dropdown</code> helper takes additional arguments for positioning and custom classes. The names are:</p>
<p>The <code>dropdown</code> helper takes additional arguments for positioning and custom classes.<br>The names are:</p>

<dl>
<dt><code>align</code></dt>
Expand All @@ -127,6 +128,8 @@ <h2 id="arguments">Additional arguments</h2>
<dt><code>classes</code></dt>
<dd>Additional class names for the dropdown. None as default.</dd>
</dl>

<br>

<div class="test-area dropdown-container">
{{#dropdownTrigger name="testDropdownRight" }}
Expand Down Expand Up @@ -187,7 +190,7 @@ <h2 id="arguments">Additional arguments</h2>
<p>Placed to the right of trigger with <code>direction="e"</code>.</p>
{{/dropdown}}
</div>

<div class="test-area dropdown-container">
{{#dropdownTrigger name="testDropdownDirectionW" }}
<button>West direction</button>
Expand All @@ -199,13 +202,52 @@ <h2 id="arguments">Additional arguments</h2>
</div>

<pre><code>&#123;&#123;#dropdownTrigger name="testDropdown3"&#125;&#125;
&lt;button&gt;Custom dropdown&lt;/button&gt;
&lt;button&gt;Custom dropdown on click&lt;/button&gt;
&#123;&#123;/dropdownTrigger&#125;&#125;

&#123;&#123;#dropdown name="testDropdown3" align="right" top="20" left="10" direction="n" classes="custom-class another-one"&#125;&#125;
&lt;p&gt;Custom dropdown.&lt;/p&gt;
&#123;&#123;/dropdown&#125;&#125;</code></pre>

<h2 id="trigger-arguments">Trigger arguments</h2>

<p>The <code>dropdownTrigger</code> helper takes additional arguments for change trigger event.<br>The names are:</p>

<dl>
<dt><code>on</code></dt>
<dd> Defaults to <code>click</code>. Set to <code>hover</code> for respond to the pointing of the mouse. Set <code>none</code> for disable trigger logic. You can use <code>usePosition</code> for write your own reactions logic.</dd>

<dt><code>timeout</code></dt>
<dd>Defaults is <code>0</code>. Set a number to have time to move the mouse from the <code>dropdownTrigger</code> on the <code>dropdown</code>.</dd>
</dl>

<div class="test-area dropdown-container">
{{#dropdownTrigger name="testDropdownHover" on="hover"}}
<button>Hover</button>
{{/dropdownTrigger}}

{{#dropdown name="testDropdownHover" direction="n" top="-10"}}
<p>Trigger responds to hover event <code>on="hover"</code>.</p>
{{/dropdown}}
</div>

<div class="test-area dropdown-container">
{{#dropdownTrigger name="testDropdownHoverTimeout" on="hover" timeout=500}}
<button>Hover with timeout</button>
{{/dropdownTrigger}}

{{#dropdown name="testDropdownHoverTimeout" direction="n" top="-10"}}
<p>You can move your mouse to the dropdown with <code>on="hover" timeout=500</code>.</p>
{{/dropdown}}
</div>

<pre><code>&#123;&#123;#dropdownTrigger name="testDropdown4" on="hover" timeout=500&#125;&#125;
&lt;button&gt;Hover with timeout&lt;/button&gt;
&#123;&#123;/dropdownTrigger&#125;&#125;

&#123;&#123;#dropdown name="testDropdown4" top="-10" direction="n"&#125;&#125;
&lt;p&gt;Custom dropdown.&lt;/p&gt;
&#123;&#123;/dropdown&#125;&#125;</code></pre>

<h2 id="markup-classes">Markup &amp; Classes</h2>

Expand All @@ -221,7 +263,7 @@ <h2 id="markup-classes">Markup &amp; Classes</h2>

&lt;button class=&quot;dropdown__trigger&quot;&gt;A trigger&lt;/button&gt;

&#123;&#123;#dropdown name="testDropdown4" align="center" top="20" left="10" classes="custom-class"&#125;&#125;
&#123;&#123;#dropdown name="testDropdown5" align="center" top="20" left="10" classes="custom-class"&#125;&#125;
&lt;!-- Content [..] --&gt;
&#123;&#123;/dropdown&#125;&#125;

Expand All @@ -231,7 +273,7 @@ <h2 id="markup-classes">Markup &amp; Classes</h2>
class=&quot;dropdown test-dropdown4 custom-class&quot;
id=&quot;test-dropdown4&quot;
style=&quot;position: absolute; left: XXpx; top: XXpx;&quot;
data-dropdown-key=&quot;testDropdown4&quot;
data-dropdown-key=&quot;testDropdown5&quot;
data-dropdown-align=&quot;center&quot;
data-dropdown-left=&quot;10&quot;
data-dropdown-top=&quot;20&quot;&gt;
Expand All @@ -258,17 +300,17 @@ <h2 id="helpers">Helpers</h2>
</p>

<div class="test-area dropdown-container">
{{#dropdownTrigger name="testDropdown5" }}
<button class="{{#if dropdownIsActive 'testDropdown5'}}dropdown--open{{/if}}">A trigger</button>
{{#dropdownTrigger name="testDropdown6" }}
<button class="{{#if dropdownIsActive 'testDropdown6'}}dropdown--open{{/if}}">A trigger</button>
{{/dropdownTrigger}}

{{#dropdown name="testDropdown5" top="10"}}
{{#dropdown name="testDropdown6" top="10"}}
<p>A dropdown.</p>
{{/dropdown}}
</div>

<pre><code class="html">&#123;&#123;#dropdownTrigger name="testDropdown5"&#125;&#125;
&lt;button class="&#123;&#123;#if dropdownIsActive 'testDropdown5'&#125;&#125;dropdown--open&#123;&#123;/if&#125;&#125;"&gt;A trigger&lt;/button&gt;
<pre><code class="html">&#123;&#123;#dropdownTrigger name="testDropdown6"&#125;&#125;
&lt;button class="&#123;&#123;#if dropdownIsActive 'testDropdown6'&#125;&#125;dropdown--open&#123;&#123;/if&#125;&#125;"&gt;A trigger&lt;/button&gt;
&#123;&#123;/dropdownTrigger&#125;&#125;
</code></pre>

Expand All @@ -279,10 +321,10 @@ <h2 id="data">Data Contexts</h2>
</p>

<div class="test-area dropdown-container">
{{ > testTemplate "testDropdown6" }}
{{ > testTemplate "testDropdown7" }}
</div>

<pre><code class="html">&#123;&#123; &gt; testTemplate &quot;testDropdown6&quot; &#125;&#125;</code></pre>
<pre><code class="html">&#123;&#123; &gt; testTemplate &quot;testDropdown7&quot; &#125;&#125;</code></pre>

{{#markdown}}
```coffeescript
Expand Down