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

ToolBarDropdownMenu #297

Open
aminya opened this issue Apr 15, 2020 · 8 comments
Open

ToolBarDropdownMenu #297

aminya opened this issue Apr 15, 2020 · 8 comments
Projects

Comments

@aminya
Copy link
Member

aminya commented Apr 15, 2020

Adding a dropdown menu that each option is a ToolBarButton.

It should be built on top of ToolBarItem.

We should use atom-select-list if possible.

References:
https://www.w3schools.com/howto/howto_js_dropdown.asp
Electron References if applicable:
https://github.com/electron/electron/blob/v5.0.13/docs/api/menu-item.md
https://github.com/electron/electron/blob/v5.0.13/docs/api/menu.md
https://livebook.manning.com/book/electron-in-action/chapter-7/1

@aminya

This comment has been minimized.

@aminya
Copy link
Member Author

aminya commented Apr 16, 2020

I got it working using atom-select-list:

dropdown

It isn't the most beautiful dropdown yet. Unfortunately, it changes the width of the toolbar itself.

The code

items/tool-bar-dropdown.js

const {ToolBarButtonView} = require("./tool-bar-button-view");
const SelectListView = require('atom-select-list');

class ToolBarDropdown {
  constructor (buttonOptions, listItems, group) {
    this.element = document.createElement('div');

    buttonOptions.callback = () => {
      if (mydropdown.list.selectList.element.hidden == true) {
        mydropdown.list.show();
      } else {
        mydropdown.list.selectList.element.hidden = true;
      }
    }
    this.button = new ToolBarButtonView(buttonOptions, group);
    this.element.appendChild(this.button.element);
    this.list= new DropdownSelector(listItems);
    this.element.appendChild(this.list.selectList.element);
  }
}


class DropdownSelector {
  // Make a selector object (should be called once)
  constructor(SelectorItems) {
    // Defining a SelectListView with methods - https://github.com/atom/atom-select-list
    this.selectList = new SelectListView({
      // an array containing the objects you want to show in the select list
      items: SelectorItems,

      // // called whenever an item needs to be displayed.
      elementForItem: (item) => {
        const element = document.createElement("li");
        element.textContent = item.text;
        return element;
      },

      // // called to retrieve a string property on each item and that will be used to filter them.
      filterKeyForItem: (item) => {
        return item.text;
      },

      // // called when the user clicks or presses Enter on an item. // use `=>` for `this`
      didConfirmSelection: (item) => {
        item.callback();
        this.selectList.element.hidden = true;
      },

      // // called when the user presses Esc or the list loses focus. // use `=>` for `this`
      didCancelSelection: () => {
        this.selectList.element.hidden = true;
      },
    });

    this.selectList.element.style.position = "relative";
    this.selectList.element.style.left = "20px";
	// initially hidden
    this.list.selectList.element.hidden = true;
  }

  // Show a selector object
  show() {
    // Show selector
    this.selectList.element.hidden = false;
    this.selectList.reset();
    this.selectList.focus();
  }

  // Dispose selector
  dispose() {
    this.selectList.element.hidden = true;
    this.selectList.destroy();
  }
}

module.exports.ToolBarDropdown = ToolBarDropdown;

tool-bar.js activate function:

const { ToolBarDropdown } = require('./items/tool-bar-dropdown');

exports.activate = function () {
  toolBarView = new ToolBarView();
  touchBarManager = new TouchBarManager();


  // test dropdown
  let mygroup = "Amin";
  let toolBarManager = new ToolBarManager(mygroup, toolBarView, touchBarManager);

  let items = [
    {text: "option1", callback: () => console.log("option1") },
    {text: "option1", callback: () => console.log("option2") }
  ];

  let mydropdown = new ToolBarDropdown({ icon: "star"}, items, mygroup);


  toolBarManager.addItem({element: mydropdown.element, priority: -1});
};

@aminya
Copy link
Member Author

aminya commented Apr 16, 2020

It is more beautiful now using the actual button type of the Toolbar itself (without atom-select-list).

Still has the toolbar width changing issue:

dropdown2

The code

items/tool-bar-dropdown.js

const {ToolBarButtonView} = require("./tool-bar-button-view");

class ToolBarDropdown {

  /**
   *
   * @param {ButtonOptions} titleOptions
   * @param {ButtonOptions[]} listOptions
   * @param {string} group
   */
  constructor (titleOptions, listOptions, group) {
    this.element = document.createElement('div');
    this.createList(listOptions, group);
    this.createTitle(titleOptions, group);
    this.element.appendChild(this.title.element);
    this.element.appendChild(this.listElement);
  }

  /**
   *
   * @param {ButtonOptions} titleOptions
   * @param {string} group
   */
  createTitle (titleOptions, group) {
    // callback for titleButton
    titleOptions.callback = () => {
      if (this.isListHidden()) {
        this.showList();
      } else {
        // to close the list when clicked again
        this.hideList();
      }
    };

    // create the title button
    this.title = new ToolBarButtonView(titleOptions, group);
  }

  /**
   *
   * @param {ButtonOptions[]} listOptions
   * @param {string} group
   */
  createList(listOptions, group) {
    // list container
    this.listElement = document.createElement('div');

    // creating each list button and appending it to the list container
    for (let i =0, l = listOptions.length; i < l; i++) {
      this.listElement.appendChild((new ToolBarButtonView(listOptions[i], group)).element);
    }

    this.listElement.style.position = "relative";
    this.listElement.style.left = "20px";
    // this.listElement.style.cssFloat = "right";

    // initially hidden
    this.hideList();
  }

  isListHidden() {
    return this.listElement.hidden;
  }

  hideList() {
    this.listElement.hidden = true;
  }

  showList() {
    this.listElement.hidden = false;
  }
}

module.exports.ToolBarDropdown = ToolBarDropdown;

tool-bar.js inside activate:

const { ToolBarDropdown } = require('./items/tool-bar-dropdown');

exports.activate = function () {
  toolBarView = new ToolBarView();
  touchBarManager = new TouchBarManager();


  // test dropdown
  let mygroup = "Amin";
  let toolBarManager = new ToolBarManager(mygroup, toolBarView, touchBarManager);

  let listOptions = [
    {text: "option1", callback: () => console.log("option1") },
    {text: "option2", callback: () => console.log("option2") }
  ];
  let titleOption = {
    icon: "star"
  };
  let mydropdown = new ToolBarDropdown(titleOption,listOptions, mygroup);
  toolBarManager.addItem({element: mydropdown.element, priority: -1});
};

@aminya
Copy link
Member Author

aminya commented Apr 16, 2020

@suda @ericcornelissen any solution for the tool-bar width changing issue?
I cannot make the dropdown be a float thing separate from the tool-bar width.

@ericcornelissen
Copy link
Contributor

Don't really have the time to look into this right now, but the w3c solutions seems pretty nice to me.

Why doesn't the dropdown overlay whatever is below it? In fact, what is below it might not even be a toolbar, depending on the end-user setup.

@aminya
Copy link
Member Author

aminya commented Apr 17, 2020

I think we need to add a floating dropdown and position it under the actual button and not appendChild it to the tool-bar.

@ericcornelissen
Copy link
Contributor

Not sure what you're trying to say @aminya 🤔

I agree that it should be "floating" (though I don't think using CSS float is the solution) and position under1 the actual button. However, your current solution looks (didn't test it) like it won't work if there is no toolbar below the button (e.g. when toolbar position is top) without expanding the toolbar.

Regarding appendChild. This would depend on your implementation. Where do you plan to append it to? In the w3c solution it is inside a <div> after the <button>.


  1. However, if the toolbar is position at the bottom this doesn't work. Similarly, when it is position left or right, this might not work for buttons near the bottom.

@aminya
Copy link
Member Author

aminya commented Apr 23, 2020

I found this video. It is maybe related.
https://www.youtube.com/watch?v=IF6k0uZuypA&t=619s

There are other ones too: https://www.youtube.com/results?search_query=dropdown+menu

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

No branches or pull requests

2 participants