Giter VIP home page Giter VIP logo

tribute's Introduction

Tribute

CDNJS version Build Status

A cross-browser @mention engine written in ES6, no dependencies. Tested in Firefox, Chrome, iOS Safari, Safari, IE 9+, Edge 12+, Android 4+, and Windows Phone.

Installing

There are a few ways to install Tribute; Bower, as an NPM Module, or by downloading from the dist folder in this repo.

NPM Module

You can install Tribute by running:

npm install tributejs

Or by adding Tribute to your package.json file.

Import into your ES6 code.

import Tribute from "tributejs";

Ruby Gem

To use Tribute within a Rails project, you can add the following to the app's Gemfile:

gem 'tribute'

Then, add the following to app/assets/javascripts/application.js:

*= require tribute

And in app/assets/stylesheets/application.css:

//= require tribute

Webpack

To add Tribute to your webpack build process, start by adding it to your package.json and running npm install.

After installing, you need to update your Babel module loader to not exclude Tribute from being compiled by Webpack:

{
    test: /\.js$/,
    loader: 'babel',
    exclude: /node_modules\/(?!tributejs)/
}

Download or Clone

Or you can download the repo or clone it localy with this command:

git clone [email protected]:zurb/tribute.git

You can then copy the files in the dist directory to your project.

<link rel="stylesheet" href="js/tribute.css" />
<script src="js/tribute.js"></script>

That's it! Now you are ready to initialize Tribute.

Initializing

There are two ways to initialize Tribute, by passing an array of "collections" or by passing one collection object.

var tribute = new Tribute({
  values: [
    { key: "Phil Heartman", value: "pheartman" },
    { key: "Gordon Ramsey", value: "gramsey" }
  ]
});

You can pass multiple collections on initialization by passing in an array of collection objects to collection.

var tribute = new Tribute({
  collection: []
});

Attaching to elements

Once initialized, Tribute can be attached to an input, textarea, or an element that supports contenteditable.

<div id="caaanDo">I'm Mr. Meeseeks, look at me!</div>

<div class="mentionable">Some text here.</div>
<div class="mentionable">Some more text over here.</div>

<script>
  tribute.attach(document.getElementById("caaanDo"));

  // also works with NodeList
  tribute.attach(document.querySelectorAll(".mentionable"));
</script>

A Collection

Collections are configuration objects for Tribute, you can have multiple for each instance. This is useful for scenarios where you may want to match multiple trigger keys, such as @ for users and # for projects.

Collection object shown with defaults:

{
  // symbol or string that starts the lookup
  trigger: '@',

  // element to target for @mentions
  iframe: null,

  // class added in the flyout menu for active item
  selectClass: 'highlight',

  // class added to the menu container
  containerClass: 'tribute-container',

  // class added to each list item
  itemClass: '',

  // function called on select that returns the content to insert
  selectTemplate: function (item) {
    return '@' + item.original.value;
  },

  // template for displaying item in menu
  menuItemTemplate: function (item) {
    return item.string;
  },

  // template for when no match is found (optional),
  // If no template is provided, menu is hidden.
  noMatchTemplate: null,

  // specify an alternative parent container for the menu
  // container must be a positioned element for the menu to appear correctly ie. `position: relative;`
  // default container is the body
  menuContainer: document.body,

  // column to search against in the object (accepts function or string)
  lookup: 'key',

  // column that contains the content to insert by default
  fillAttr: 'value',

  // REQUIRED: array of objects to match or a function that returns data (see 'Loading remote data' for an example)
  values: [],

  // When your values function is async, an optional loading template to show
  loadingItemTemplate: null,

  // specify whether a space is required before the trigger string
  requireLeadingSpace: true,

  // specify whether a space is allowed in the middle of mentions
  allowSpaces: false,

  // optionally specify a custom suffix for the replace text
  // (defaults to empty space if undefined)
  replaceTextSuffix: '\n',

  // specify whether the menu should be positioned.  Set to false and use in conjuction with menuContainer to create an inline menu
  // (defaults to true)
  positionMenu: true,

  // when the spacebar is hit, select the current match
  spaceSelectsMatch: false,

  // turn tribute into an autocomplete
  autocompleteMode: false,

  // Customize the elements used to wrap matched strings within the results list
  // defaults to <span></span> if undefined
  searchOpts: {
    pre: '<span>',
    post: '</span>',
    skip: false // true will skip local search, useful if doing server-side search
  },

  // Limits the number of items in the menu
  menuItemLimit: 25,

  // specify the minimum number of characters that must be typed before menu appears
  menuShowMinLength: 0
}

Dynamic lookup column

The lookup column can also be passed a function to construct a string to query against. This is useful if your payload has multiple attributes that you would like to query against but you can't modify the payload returned from the server to include a concatenated lookup column.

{
  lookup: function (person, mentionText) {
    return person.name + person.email;
  }
}

Template Item

Both the selectTemplate and the menuItemTemplate have access to the item object. This is a meta object containing the matched object from your values collection, wrapped in a search result.

{
  index: 0;
  original: {
  } // your original object from values array
  score: 5;
  string: "<span>J</span><span>o</span>rdan Hum<span>p</span>hreys";
}

Trigger tribute programmatically

Tribute can be manually triggered by calling an instances showMenuForCollection method. This is great for trigging tribute on an input by clicking an anchor or button element.

<a id="activateInput">@mention</a>

Then you can bind a mousedown event to the anchor and call showMenuForCollection.

activateLink.addEventListener("mousedown", function(e) {
  e.preventDefault();
  var input = document.getElementById("test");

  tribute.showMenuForCollection(input);
});

Note that showMenuForCollection has an optional second parameter called collectionIndex that defaults to 0. This allows you to specify which collection you want to trigger with the first index starting at 0.

For example, if you want to trigger the second collection you would use the following snippet: tribute.showMenuForCollection(input, 1);

Events

Replaced

You can bind to the tribute-replaced event to know when we have updated your targeted Tribute element.

If your element has an ID of myElement:

document
  .getElementById("myElement")
  .addEventListener("tribute-replaced", function(e) {
    console.log(
      "Original event that triggered text replacement:",
      e.detail.event
    );
    console.log("Matched item:", e.detail.item);
  });

No Match

You can bind to the tribute-no-match event to know when no match is found in your collection.

If your element has an ID of myElement:

document
  .getElementById("myElement")
  .addEventListener("tribute-no-match", function(e) {
    console.log("No match found!");
  });

Active State Detection

You can bind to the tribute-active-true or tribute-active-false events to detect when the menu is open or closed respectively.

document
  .getElementById("myElement")
  .addEventListener("tribute-active-true", function(e) {
    console.log("Menu opened!");
  });
document
  .getElementById("myElement")
  .addEventListener("tribute-active-false", function(e) {
    console.log("Menu closed!");
  });

Tips

Some useful approaches to common roadblocks when implementing @mentions.

Updating a collection with new data

You can update an instance of Tribute on the fly. If you have new data you want to insert into the current active collection you can access the collection values array directly:

tribute.appendCurrent([
  { name: "Howard Johnson", occupation: "Panda Wrangler", age: 27 },
  { name: "Fluffy Croutons", occupation: "Crouton Fluffer", age: 32 }
]);

This would update the first configuration object in the collection array with new values. You can access and update any attribute on the collection in this way.

You can also append new values to an arbitrary collection by passing an index to append.

tribute.append(2, [
  { name: "Howard Johnson", occupation: "Panda Wrangler", age: 27 },
  { name: "Fluffy Croutons", occupation: "Crouton Fluffer", age: 32 }
]);

This will append the new values to the third collection.

Programmatically detecting an active Tribute dropdown

If you need to know when Tribute is active you can access the isActive property of an instance.

if (tribute.isActive) {
  console.log("Somebody is being mentioned!");
} else {
  console.log("Who's this guy talking to?");
}

Links inside contenteditable are not clickable.

If you want to embed a link in your selectTemplate then you need to make sure that the anchor is wrapped in an element with contenteditable="false". This makes the anchor clickable and fixes issues with matches being modifiable.

var tribute = new Tribute({
  values: [
    {
      key: "Jordan Humphreys",
      value: "Jordan Humphreys",
      email: "[email protected]"
    },
    {
      key: "Sir Walter Riley",
      value: "Sir Walter Riley",
      email: "[email protected]"
    }
  ],
  selectTemplate: function(item) {
    return (
      '<span contenteditable="false"><a href="http://zurb.com" target="_blank" title="' +
      item.original.email +
      '">' +
      item.original.value +
      "</a></span>"
    );
  }
});

How do I add an image to the items in the list?

You can override the default menuItemTemplate with your own output on initialization. This allows you to replace the innerHTML of the li of each item in the list. You can use item.string to return the markup for the fuzzy match.

{
  //..other config options
  menuItemTemplate: function (item) {
    return '<img src="'+item.original.avatar_url + '">' + item.string;
  }
}

Embedding Tribute in a scrollable container.

Sometimes you may need to have the Tribute menu attach to a scrollable parent element so that if the user scrolls the container the menu will scroll with it. To do this, you can set menuContainer to the node that is the scrollable parent.

{
  //..other config options
  menuContainer: document.getElementById("wrapper");
}

Loading remote data

If your data set is large or would like to pre filter your data you can load dynamically by setting the values to a function.

{
  //..other config options
  // function retrieving an array of objects
  values: function (text, cb) {
    remoteSearch(text, users => cb(users));
  },
  lookup: 'name',
  fillAttr: 'name'
}

You would then define a function, in this case remoteSearch, that returns your data from the backend.

function remoteSearch(text, cb) {
  var URL = "YOUR DATA ENDPOINT";
  xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        var data = JSON.parse(xhr.responseText);
        cb(data);
      } else if (xhr.status === 403) {
        cb([]);
      }
    }
  };
  xhr.open("GET", URL + "?q=" + text, true);
  xhr.send();
}

Hide menu when no match is returned

If you want the menu to not show when no match is found, you can set your noMatchTemplate config to the following:

noMatchTemplate: function () {
  return '<span style:"visibility: hidden;"></span>';
}

Detaching Tribute instances

When you want to remove Tribute from an element you can call detach.

tribute.detach(document.getElementById("caaanDo"));

This will remove all event listeners from the DOM that are associated with that element.

Trigger on multiple character strings

It is also possible to configure Tribute to trigger on a string consisting of multiple characters.

This example shows the usage of Tribute for autocompletion of variables:

var tribute = new Tribute({
  trigger: "{{",
  values: [
    { key: "red", value: "#FF0000" },
    { key: "green", value: "#00FF00" }
  ],
  selectTemplate: function(item) {
    return "{{" + item.original.key + "}}";
  },
  menuItemTemplate: function(item) {
    return item.original.key + " = " + item.original.value;
  }
});

Framework Support

Vue.js — vue-tribute by @syropian

AngularJS 1.5+ — angular-tribute by ZURB

Angular 2+ - ngx-tribute by Ladder.io

Ruby — tribute-rb by ZURB

Ember – ember-tribute by MalayaliRobz

WYSIWYG Editor Support

Brought to you by

ZURB, the creators of Helio

Design successful products by rapidly revealing key user behaviors. Helio makes it easy to get reactions on your designs quickly so your team can focus on solving the right problems, right now.

tribute's People

Contributors

agarbund avatar alexisbernard avatar alexthewilde avatar andreynering avatar bitnot avatar borntraegermarc avatar cgross avatar danielruf avatar dependabot-preview[bot] avatar dependabot[bot] avatar fynnfeldpausch avatar imontiel avatar iskandiar avatar jmlavoier avatar mrrobz avatar mrsweaters avatar nickrivadeneira avatar onhate avatar peschuster avatar postlagerkarte avatar rafibomb avatar rcavezza avatar rene-leanix avatar robwouters avatar rsbondi avatar samlbest avatar sassy avatar stefanneculai avatar thomhurks avatar yeexel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tribute's Issues

could not attach tribute in a frame/body with contenteditable true created by CKEditor

How can we reproduce this bug?

  1. Create textarea input
  2. Set CKEditor in textarea -> its create a iframe with a body tag(contenteditable true)
  3. try to attach: tribute.attach(document.getElementById('bodyid')

What did you expect to happen?
Attach tribute in body.

What happened instead?
Nothing

Link (jsfiddle/plunkr) or Screenshot:
image

    `<script>
    CKEDITOR.replace( 'editor1' );
    //Criacao do Tribute AutoComplete
    var tribute = new Tribute({
        collection: [
            {
                // The function that gets call on select that retuns the content to insert
                selectTemplate: function (item) {
                    return '@[' + item.original.value + ']';
                },
                // template for displaying item in menu
                menuItemTemplate: function (item) {
                    return '<img style="max-width: 20px;" src="'+ item.original.url + '">' + '&nbsp;&nbsp;&nbsp;&nbsp;' + item.original.value;
                },
                
                // the array of objects
                values: users,
                
                // specify whether a space is allowed in the middle of mentions
                allowSpaces: false
            },
            {
                // The symbol that starts the lookup
                trigger: '#',
                
                // The function that gets call on select that retuns the content to insert
                selectTemplate: function (item) {
                    return '#' + item.original.value;
                },
                
                // template for displaying item in menu
                menuItemTemplate: function (item) {
                    return item.original.value;
                },
                
                // the array of objects
                values: hashtags
            }
        ]
    })
    
    tribute.attach(document.querySelectorAll('.cke_editable'));
    //tribute.attach(document.getElementById('testarea'));
    //tribute.attach(document.querySelectorAll('#autocompletetext'));
    //tribute.attach(document.getElementsByTagName("p"));
    //
    
    //tribute.attach(document.getElementById("autocompletetext"));
    //tribute.attach(document.getElementsByTagName("body"));
    </script>`

Autocomplete issue when insert template has markup

As you will be able to see from the last image, i'm using div with contenteditable="true".

First you need to setup selectTemplate to look something like this:

{
   selectTemplate: function (item) {
      return '<span class="handle">' + item.original.username + '</span>';
   },

   values: [
      { name: 'Allen Iverson', username: 'alleniverson' },
      { name: 'Basketball HOF', username: 'Hoophall' }
   ]
}
.editor { color: #000; } 
.handle { color: #1b95e0; }

How can we reproduce this bug?

  1. Start mentioning "Basketball HOF"
  2. Mention someone
  3. "Backspace" delete handle to look like this: @hooph
  4. You see autocomplete list again, hit enter to mention @Hoophall again
  5. Continue typing

What did you expect to happen?
I expected to have text with black colour again. (see image)
screen shot 2016-09-23 at 09 35 12

What happened instead?
I got all text blue. (see result image and markup)
screen shot 2016-09-23 at 09 34 08

screen shot 2016-09-23 at 09 33 33

TributeEvents can not be prevented from propagation

How can we reproduce this bug?

When enter event (to select item from dropdown) is fired, the events of element, which tribute is attached to, are still triggered.

What did you expect to happen?
Is it possible to have an option to stop propagation (event bubbling) of enter event?

What happened instead?
These is no way currently to get enter event, subscribe to it. The only emitted is custom 'tribute-replaced' event, which unfortunately know nothing about its parent event.
As possible solution 'tribute-replaced' can provide its parent event, so we can call stopPropagation manually.

Leading space

First of all I must say that I really like this project!

I have an issue with the leading space option.
The issue is that when requireLeadingSpace is set to true and a user types @bob@mail the values function is no longer being called after typing @ (assuming that the trigger key is @).
i.e it will be called for b, bo, bob, but will not be called for bob@, bob@m, etc.

How can we reproduce this bug?

  1. configure tribute as follows:
var tribute = new Tribute({
      requireLeadingSpace: true,
      values: function(prefix, cb) {
          console.log(prefix);
          cb([]);
      }
});
tribute.attach(document.getElementById('test'));
  1. enter @bob@mail in the 'test' element

What did you expect to happen?
console output: bob@mail

What happened instead?
console output:

Trigger suggestions popup (menu show) ?

Hello friends,

Is there a way to trigger suggestions popup programmatically?

I've tried

tribute.showMenuFor($('.editor').get(0), true);

but it doesn't work.

Currently I'm trying to show menu with dispatching keydown + keyup events, not sure if this will work.

li elements not scrolling in tribute-container on arrow up/down

We have more li elements in our list than will fit in the viewport of the fixed-height tribute-container. Scrolling with a mouse or trackpad works as expected, but arrow up/down does not move the list in the container.

  1. Create a list of users larger than will fit in fixed height tribute-container
  2. Trigger dropdown and arrow down to the bottom of the list (the list will not move with the arrow down behavior)
  3. Try again with mouse or trackpad scroll and the list scrolls

We expected arrow up/down to move the list visually through viewport of the fixed height div.

We could hack this with javascript/jQuery but had expected arrow up/down to scroll out of the box.

JS Error: "Tribute was already bound to TEXTAREA"

I'm having issues triggering @mentions with an app using Rails 5, Ruby 2.3.1 inside a Backbone model in a Marionette view.

In my view, I have a form in a modal with a textarea: <textarea name="message" rows="3" placeholder="Write your comment..." class="form-input"></textarea>.

On keyup with '@' in console I am getting the above error: "Tribute was already bound to TEXTAREA".

The code in my Marionette view is pretty simple, the following is my function (in CoffeeScript):

mentionedUsers: ->
      allBrandUsers = (app.BrandChannel.request 'current:brand:users')
      tribute = new Tribute(values: allBrandUsers.models)
      tribute.attach(@ui.message)

...where @ui.message is the name of the <textarea>

I'm attaching the function with an event (last line below):

events:
      'submit @ui.form': 'onBeforeSubmit'
      'keypress @ui.message': 'onMessageKeypress'
      'keyup @ui.message': 'mentionedUsers'

With debugger stepping through, allBrandUsers evaluates properly:
UsersCollection {length: 2, models: Array[2], _byId: Object, parent: BrandModel}

also tribute evaluates properly:
Tribute {menuSelected: 0, current: Object, inputEvent: false, isActive: false, menuContainer: null…}

attaching seems to evaluate properly (although I am curious about the array here):
[<textarea name="message" rows="3" placeholder="Write your comment..." class="form-input" data-tribute="true"></textarea>]

I do not get the dropdown to trigger at all, and additionally, there's the error in console I mentioned already.

screen shot 2016-08-31 at 9 03 50 am

lookup should accept a function

The lookup config should accept a function that allows you to construct a lookup value by concatenating attributes on the item as well as the the current approach, a string representing the attribute to query against.

ex.

{
  lookup: function(person) {
    return person.name + person.email;
  }
}

or

{
  // this will query against person.name
  lookup: 'name'
}

Default will still lookup against a key attribute.

No way to stop AJAX call

when using ajax request callback to populate values, The AJAX request is sent by adding a new character even after no match. There's no reason to send another request when the previous request with less characters itself returns nothing.

Also I would like to use the previously populated values instead of making new request again on pressing backspace.

Tribute menu wrong position when body is scrolled on contenteditable elements

When the window is scrolled it's correctly taken into account by getTextAreaOrInputUnderlinePosition. However its contenteditable sibling getContentEditableCaretPosition does not consider window scroll

A quick fix I used was to add this block of at the bottom of getContentEditableCaretPosition

var doc = document.documentElement
var windowLeft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0)
var windowTop = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0)

coordinates.top += windowTop
coordinates.left += windowLeft

A better fix would take into account the scroll of every parent having a scroll, not only the window. (For instance if there is an overflow: auto on an ancestor element)

Problems with shadow DOM

The call this.getDocument().activeElement in for example

let textComponent = this.getDocument().activeElement
is causing problems when an app implements shadow DOM. Because the active element in shadow DOM is not the native input element but it's parent.

That is why all this.getDocument().activeElement should get replaced with this.tribute.current.element

@mrsweaters you know the architecture way better than me. Could you shortly explain why this.getDocument().activeElement was introduced instead of this.tribute.current.element and what implications it would had to replace it?

Mention menu wrongly positioned in version 3.1.0

In version 3.1.0 there's a change regarding positioning. In my case, this broke the positioning of the mentions window. I have a comment box on the right of the screen (I'm just using Bootstrap columns, nothing special) and the mentions box now appears on the left side of the screen. The tribute-container div is a child of the <body> and it has the style top: 413px; left: 449px; position: absolute; display: block; which wouldn't even be the correct positioning if it was relative to the comment box. The vertical position does seem to be correct though, it's only the horizontal positioning that is broken.

If you need more info, I'll be glad to help.

Page jumps up when top of textarea is scrolled out of view

How can we reproduce this bug?

  1. Go to the example https://zurb.github.io/tribute/example/
  2. In the contenteditable input, enter lots of new lines and scroll the page down so that the top of the contenteditable is scrolled out of view
  3. Start typing a mention

What did you expect to happen?

The page does not jump.

What happened instead?

The page jumps up so that the top of the contenteditable is scrolled back into view

This is caused by the following line https://github.com/zurb/tribute/blob/master/src/TributeRange.js#L43
Commenting out that line seems to fix the issue, but that may have unintended consequences in other situations.

Search is not fired after Backspace, when previous result is empty

How can we reproduce this bug?

  1. Step one
    Create a simple <div class="mentionable">Some text.</div>
    and initialize a tribute var tribute = new Tribute({ values: [ {key: 'Phil Heartman', value: 'pheartman'}, {key: 'Gordon Ramsey', value: 'gramsey'} ]});
    Apply tribute to the element tribute.attach(document.querySelectorAll('.mentionable'));

  2. Step two
    Start typing @P - 'Phil Heartman' option is shown
    image
    Type anything (not to match the option) @Py - no option is shown
    image

  3. Step three
    Press Backspace - @P text is left

What did you expect to happen?
'Phil Heartman' option is shown

What happened instead?
No option is shown. Need to type something again for search to be called.

Link (jsfiddle/plunkr) or Screenshot:
image

How to use values from json

first of all mey english isnot very good sorry for this. Iwant to use values form json but
I try a lot of way but i couldnt do it. itry dataType json. jsonp not working list is empty. when i try html i can see values pattern on console just like yours. But icant get it. Console error arr.reduce is not a function

....
return arr.reduce(function (prev, element, idx, arr) {
....

please help me my code is

$.ajax({
type: 'GET',
url: 'bla bla bla',
dataType: 'html',
success: function (data) {
console.log(data)

    var tribute = new Tribute({
        values: JSON.stringify(data),

        selectTemplate: function (item) {
            if (this.range.isContentEditable(this.current.element)) {
                return '<span contenteditable="false" class="mentionsPerson"><a href="http://ismailhakkieren.com" target="_blank" title="' + item.KEY + '" class="mentionsPerson">@' + item.KEY + '</a></span>';
            }
            return '@' + item.KEY;
        }
    });

    tribute.attach($('#mainEditor'));
    tribute.attach($('#inputExperience'));


}

});

Define HTML file for templates

It would be cool if one could define a string to the location to the HTML templates like selectTemplate.

That way the template would be more maintainable.

Error on CKeditor integration

Hello

Just want to say love the package. I want to help out getting this working CKEditor. Currently getting this error when I try to attach it to the CK editor ID on my text area

Error: [Tribute] Must pass in a DOM node or NodeList.

Just wondering if we could start the discussion on getting this integrated. If you can point me in the right direction, I can dive into the code and help out.

Let me know.

Error in console when clicking on 'No Match' or clicking enter when there are no results

When typing something that doesn't exist on the values list and clicking on the 'No Match' in the list, an error appears in the console saying: 'Cannot read property 'original' of undefined'.

Does it should be clickable at all? there is no reason that someone could click the 'No Match' label that is shown when the typing did not match anything.

Also, the 'No Match' disappears after some chars where typed, and so the error is shown also when there isn't a 'No Match' label but the enter button is clicked.

Tribute in appendGrid?

Has anyone conquered getting Tribute working as a custom control in an appendGrid row?

In appendGrid you define a customBuilder: function that creates the dynamic control in a very jQuery stylee. The problem is, with Tribute, you need an existing text input that's hooked via

triLocation.attach(document.getElementById('txtFoo'));

or am I missing something? Can you dynamically create individual Tributes?

Memory Leak in TributeMenuEvents.js

In the bind function of TributeMenuEvents there's a call to document.addEventListener('click' and window.addEventListener('resize' . These event listeners are never cleaned up (that I can see), even if the underlying text element is removed.

Tribute.attach breaks if passed a jquery object

I know Tribute doesn't require jquery, but it seems like it should play nicely with it. If I call attach with a jquery object I get the following error:

tribute.js?body=1:135 Uncaught TypeError: el.hasAttribute is not a function
_attach @ tribute.js?body=1:135
attach @ tribute.js?body=1:129

I think the reason is Tribute is explicitly checking for NodeList instead of just accepting any array-like set of elements

'Utils' Script Missing from /dist

How can we reproduce this bug?

  1. npm i --save tributejs
  2. require('tributejs')

What did you expect to happen?

Would import tributejs

What happened instead?

dist/tribute.js is requiring ./utils on the 10th line, and that is not in the dist folder.

Link (jsfiddle/plunkr) or Screenshot:

image

image

Quilljs + Tributejs - Pressing enter key doesn't select

How can we reproduce this bug?

I have created a JSFiddle for this issue here.
https://jsfiddle.net/chphr0ab/3/

The issue is when you press "enter", it actually goes to the new line in the editor.
Instead of creating a newline, it should actually select an item from the tribute.

You can still select the item using "tab" or a "mouse". It's just the "enter" key which doesn't work.

how to trigger tribute after @ + any letter

Hi, i am using tribute and it is all perfect! But now there is too much data and it is hard to start tribute after @/#.. Therefore i need to trigger mention or hashtag not just after @or #, but after an additional letter typing like @A or #b?
Another issue is i want to use a dynamic mention list?
How can i do that?

Bundling and use of "use strict"

This is more of an enhancement, but we bundle and minify/compress this code, and it would be great if the 'use strict'; line was contained so that we didn't have to worry about it affecting our other code that's out of scope.

For now, we've had luck wrapping the whole tribute.js library in an IIFE, but there might be a better solution that we haven't thought of.

The `dist` directory was deleted

Hi @mrsweaters, thanks to accept my pull-request!

But, there is anything wrong and URGENT to fix with the dist directory, I don't know if the problem was happened because i included the dist directory to .gitignore.

I went update my TributeJS to new version on my project by npm and the dist directory disappeared.

Help

i wrote special ediitor and i use your library for mentions.
my div id is mainEditor.

tribute.attach($('#mainEditor'));

it works perfect but i have a special situation. this div (mainEditor) has a h3 (h3 id is hContent )and i dont want to mentions only this element. Please help me.

How to trigger AJAX and append results

I think I've missed the docs on how to do this and I've trawled these issues but I still can't work out how to trigger an AJAX load.

I understand the expected format and how to append correctly, but I can't find how to hook Tribute to my AJAX load.

Great component! Any pointers much appreciated.

Mentions menu goes out of vertical view

When opening the mentions menu in the bottom of the page, the menu goes out of the view and a scroll is added to the page.

I believe that the wanted behavior in case the menu is too long (when the "top" coordinates + the menu height is bigger than the page height), is that it should be opened upwards.

image

image

Dropdown hover vs arrow highlighting

When triggering the @mention dropdown, highlight is working as expected but the switching to and from mouse/trackpad navigation vs. arrow/keydown navigation the highlighted item doesn't switch properly.

  1. Trigger dropdown
  2. Arrow/keydown through the list
  3. Scroll list with mouse/trackpad

We expect mouse navigation to behave the same as key navigation via arrows - the item hovered should clear the previously-highlighted item from being in it's highlighted state.

Instead 2 items can seemingly be highlighted at once and also when using the mouse/trackpad, again, as already mentioned, highlighted state will not clear. Hover is fine.

hover
hover2

Allow mentions to contain spaces

I would consider this more an enhancement than a bug, but it would be nice to allow users to type spaces when mentioning someone, especially if we use first names and last names for mentioning.

For example, in the Katniss example, you can't type out @peeta m and still be able to mention him.

I think keeping this functionality is important, so maybe a new option allowSpaces: true can be used to signify this?

Add ability to detach/remove a Tribute instance

Hey there!

First of all, thank you so much for creating this plugin. I love it!

I was wondering if you'd consider an enhancement that allows me to completely remove an attached Tribute instance (so that I can then create a new instance with new data).

In my use case, I have 2 Tribute instances attached to 2 textareas on a page (so one instance per textarea). When the user makes a selection above the first textarea, I want to replace the collection for the associated Tribute instance with completely new data without interfering with the other Tribute instance attached to the second textarea.

Perhaps there could be "remove" method -- i.e., tribute.remove(...) to remove a Tribute instance from an element. That way, I could re-initialize & re-attach a new Tribute instance with new data to the target element.

What do you think?

Thank you for your time!

Jen

Anchor suggestions below input field

This is more of a feature suggestion, if that's OK: it would be great if you could pass an option to have the suggestions menu render below the field instead of at the trigger character location (and have the width of the list automatically set to match the field above, etc). I could see folks wanting the option depending on their app's style.

Add a "nothingFound" event

It would be great if an event was fired when a user tried to search something and there were no matches in the collection. When trying to be judicious about sending large collections to the client, having this event could let us update the list on the fly with another large page of data without loading it all up front.

(bug) text between mentions inside textarea getting deleted

There's a critical bug occurring within a textarea upon deleting a mention and then hitting enter. You can reproduce this behaviour in the Tribute Demo:

  1. Enter a mention followed by text followed by another mention:
to @Jordan Humphreys 
lorem ipsum
from @Sir Walter Riley 
  1. Remove second mention using backspace key
to @Jordan Humphreys 
lorem ipsum
  1. Hit enter: complete lorem ipsum text after first mention gets removed
to @Jordan Humphreys 

Behaves unexpectedly with contentEditable on Enter click after mentioning

How can we reproduce this bug?

  1. Create a simple application with <div class="mentionable">Some text.</div>

  2. Initialize Tribute as new Tribute({ values: [ {key: 'Phil Heartman', value: 'pheartman'}, {key: 'Gordon Ramsey', value: 'gramsey'} ]
    and attach to the contentEditable tribute.attach(document.querySelectorAll('.mentionable'));

  3. Type @ to see the possible options to mention
    image
    and select any
    image

  4. Continue typing on the same line
    image
    then press 'Enter' key
    image

What did you expect to happen?
Cursor moves to the next line.

What happened instead?
Cursor moves back to the place after mention and some part of a mention appears after it.
Trying to press 'Enter' again together with printing some text continue to insert some part of mentioning and moving cursor.

Link (jsfiddle/plunkr) or Screenshot:
image

Request for Callback

We're using knockout, and It would be great to have a callback after text is replaced. This isn't playing nicely with the textInput binding in knockoutjs, and it would help to be able to track the changes applied by tributejs.

Bug with contentedible, starting typing with @ and enter to select.

How can we reproduce this bug?
Using latest master version 2.3.6

  1. Step one
    Create a contentedible element:
    <div id="mention" contenteditable="true" placeholder="type here"></div>
  2. Step two
    attach a tributejs with basic defaults (issue remains with custom selectTemplate):
let tribute = new Tribute({
        collection: [ {
          trigger: '@',
          allowSpaces: false,
          values: [{key: 'Phil Heartman', value: 'pheartman'}, {key: 'Gordon Ramsey', value: 'gramsey'}]
        }]
      });
tribute.attach(document.getElementById('mention'));
  1. Step three
    Start typing @ for the mention list to appear, select any, press enter (keyboard not click), and press space, or continue writing. Then press enter again.

What did you expect to happen?
Default action: in this case line change

What happened instead?
No default action, all text reverted to just mention. This also happened some time with text before the mention, and this text also disappeared (cannot reproduce though atm)

Link (jsfiddle/plunkr) or Screenshot:
https://jsfiddle.net/kj2tzbe4/3/

remove mention action

When i add mention i add input value item.original.key but when i remove mention i want to remove this parametre how ican do it please help me

i need just like this...
document.getElementById('mainEditor').addEventListener('tribute-removed', function (e) {
console.log('Text replaced by Tribute!');
});

Brunch Error

Hi. I ran into this error when I tried to use 2.0.1 with brunch 2.8.2.

error: Resolving deps of node_modules/tributejs/dist/tribute.js failed. Could not load module './TributeEvents' from './node_modules/tributejs/dist'. Make sure the file actually exists.

Is this a brunch issue?

Menu can get placed outside viewport

The menu is created with this call:

this.tribute = new Tribute({
            values: [],
            menuContainer: document.body,
            selectTemplate: (item) => {
                return '@' + item.original.value.username;
            },
            menuItemTemplate: (item) => {
                return 'someBoringHTML'
            },
            lookup: (original) => {
                return original.value.username + original.value.displayName;
            }
        });

We use this lib to display a user menu if somebody writes '@' in the message create input. As you can see from this screenshot (the menu to the very right bottom corner):
untitled

The tribute menu gets loaded nearly off screen. In this screenshot:
untitled1

It is even completely off screen. I think there should be an implementation, where the menu can never go outside the viewport. I can't think of an use case (not even iFrame?) where the menu should be outside the viewport...

Need access to original item key/value pairs after text is replaced

I see that I can access the 'tribute-replaced' event to get to the HTML inside event.detail, but what I really need access to are the original key/value pairs in my values collection.

For example, if I have:

values: [
     { name: "The Empire Strikes Back", id: "the-empire-strikes-back", entity: "movie" },
],

when my text is replaced, I need access to those original variables: name, id, and entity after my text has been replaced, because I'm going to need to store those variables in my object along with the replaced text.

(This allows me to display the "replaced" text when it's pulled from the database later and displayed in my app.)

So really, I just would like to see lines 101-103 in TributeRange.js:

        let replaceEvent = new CustomEvent('tribute-replaced', {
            detail: text
        })

changed to something along these lines:

        let replaceEvent = new CustomEvent('tribute-replaced', {
            detail: {
                 "text": text,
                 "name": name,
                 "id": id,
                 "entity": entity
            }
        })

The challenge is, I don't seem to have access to the item object at that point, and the code at that point would have no idea what the key/value pair names are, so you'd have to just iterate over them and deliver them directly - given that each item value could have any number of individual key/value pairs.

If you have a thought of how to accomplish this easily that I'm unaware of, let me know.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.