Upgrading to select2 v4: make matcher compatible - jquery-select2-4

I have a matcher from an older version of select2, and I need to get it to work in select2 v4. select2 v4 has changed the matcher function, and offers a compatibility module with which you can wrap your old matcher. The module is included in the "full" version of select2, and is listed under "select2/compat/matcher". I just don't know how to read it well enough to utilize it and wrap my old matcher, which looks like this:
matcher: function (term, text) {
term = term.toUpperCase().replace('SAINT', 'ST. C').replace(' ', '').replace('.', '');
text = text.toUpperCase().replace('SAINT', 'ST. C').replace(' ', '').replace('.', '');
return text.toUpperCase().indexOf(term.toUpperCase()) >= 0;
}
I have done some reading about AMD and modules, but it's still a bit too advanced for me to understand.

I found some example code on the select2 site:
$.fn.select2.amd.require(['select2/compat/matcher'], function (oldMatcher) {
$(".county_id").select2({
placeholder: "Enter a county name or select from list",
allowClear: true,
matcher: oldMatcher(matchStart)
})
where matchStart refers to the old match function.

Related

"select2" Add constant option

I am currently using Select2 in a project and would like to add a option to my select list that shows up regardless of what the user types or searches. The idea is to have a "Add new" option always present in the list.
I do not think my code is necessary here (but if needed I may provide) as the only thing i'm lacking knowledge in this specific topic is on how to keed the option always showing.
I thought of using the matcher attribute, but i'm not sure how.
I've managed to do it setting a new matcher, the problem was I was not sure on how to create a new matcher and still use the select2 default one.
Something else I was missing was the full version of select2.
function newMatcher(term, text){
//The "ADD NEW" String is the text in the option I want to always show up.
//The code after OR looks for the actual results for the user's search
if ((text.toUpperCase().indexOf("ADD NEW") > -1)
|| (text.toUpperCase().indexOf(term.toUpperCase()) > -1)) {
return true;
}
}
$(document).ready(function() {
$.fn.select2.amd.require(['select2/compat/matcher'], function (oldMatcher) {
$('select').select2({
matcher: oldMatcher(newMatcher)
})
})
});

typeahead.js to select multiple values in same text element

Is there a way to get the solution referenced here:
Twitter bootstrap typeahead multiple values?
To work with typeahead.js where updater, matcher etc functions are not available?
At https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md#custom-events you can read:
typeahead:selected – Triggered when a suggestion from the dropdown
menu is selected. The event handler will be invoked with 3 arguments:
the jQuery event object, the suggestion object, and the name of the
dataset the suggestion belongs to.
demo: http://jsfiddle.net/3hL70h1L/
$('.typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'states',
displayKey: 'value',
source: substringMatcher(states)
})
.on('typeahead:selected',
function(event,suggestions) {
$myTextarea.append(suggestions.value, ' ');
$('.typeahead').val('');
}
);
Notice that you also can use The Typeahead plugin from Twitter's Bootstrap 2 ready to use with Bootstrap 3 (can also be integrated with Bloodhound)
Both typeahead plugins also work together with Bootstrap tags support, see https://github.com/bassjobsen/Bootstrap-3-Typeahead#bootstrap-tags-input which seems to offer a similar functionality.

Why can't my Capybara/Poltergeist test select from a jQuery autocomplete field?

UPDATE: I have fixed this problem after lots of painstaking work on my own. I am happy to be a resource to anybody needing a hand with this. Here is a gist of my working setup.
I have tried every solution I could find Google and SO. Here are some different things I have tried:
page.execute_script %Q{$('#{selector}').val('#{value}').trigger('keydown')}
and
fill_in field, with: options[:with]
page.execute_script %Q{ $('##{field}').trigger('focus') }
page.execute_script %Q{ $('##{field}').trigger('keydown') }
This is what fails:
page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')
But it's definitely there when I look at it in Firebug and test it in the browser.
Here are all of the details, including a restatement of those above. Remember, the autocomplete field works fine in the browser.
listing_integration_spec.rb
require "spec_helper"
describe "Listing Integration" do
let!(:user) { login_user }
it "lets a user add information listing", js: true do
listing = create(:listing, user: user)
click_link('Additional Information')
click_link('Create')
fill_autocomplete('listings_search', with: listing.item_id)
end
end
spec/support/feature_helper.rb
def fill_autocomplete(field, options = {})
fill_in field, with: options[:with]
page.execute_script %Q{ $('##{field}').trigger('focus') }
page.execute_script %Q{ $('##{field}').trigger('keydown') }
selector = %Q{ul.ui-autocomplete li.ui-menu-item a:contains('#{options[:with]}')}
page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')
page.execute_script %Q{ $("##{selector}").trigger('mouseenter').click() }
end
ERB from view template
<%= simple_fields_for :listings do |f| %>
<%= f.input :search, label: "Search by Listing", required: true %>
<% end %>
and the Coffeescript:
$("#listings_search").autocomplete
source: (request, response) ->
options =
term: request.term
$.get "/search_listings", options, (data) ->
if data.length == 0
alert "No listings found."
response data
minLength: 2
select: (event, ui) ->
add_listing_hash =
type: "GET"
url: "/add_listing"
data: { id: ui.item.id }
success: () ->
$.ajax(add_listing_hash)
JS drivers are generally meh, they're slow and not single one of them covers 100% of function, and they're often quirky and hard to debug, but I'm sure you've got that figured out by now.
I've got similar piece of code working on rails 3.2, minitest and poltergeist 1.3.0 (an ajaxed dropdown) but it kind of breaks periodically for no good reason (one might say it has a poltergeist? I have already resorted switching that test between selenium and poltergeist a couple times so far), not sure why autocompleter wouldn't work for you but it feels like a bug,
submit issue to https://github.com/jonleighton/poltergeist (you already have? https://github.com/jonleighton/poltergeist/issues/439), try changing to selenium or webkit, see if it works, you can use a different driver in this one test if it gets you out of the woods (it beats losing days of work over a widget that works).
I've found several solutions online, none of which work with current versions of Poltergeist, Capybara, and Autocomplete. But I learned enough from them to make a working helper method, with no sleep calls.
def fill_autocomplete(css_id, page, options = {})
find("#{css_id}").native.send_keys options[:with]
page.execute_script %{ $('#{css_id}').trigger('focus') }
page.execute_script %{ $('#{css_id}').trigger('keydown') }
selector = %{ul.ui-autocomplete li.ui-menu-item:contains("#{options[:select]}")}
expect(page).to have_selector('ul.ui-autocomplete li.ui-menu-item')
page.execute_script %{ $('#{selector}').trigger('mouseenter').click() }
end
Example usage:
fill_autocomplete(
'#contact_filter_company',
listing_page,
with: 'acm',
select: 'Acme'
)
I have a page argument because I'm using SitePrism - if you're not, you can strip it out.
I'm using this with:
jQuery UI Autocomplete 1.11.2
poltergeist 1.5.1
capybara 2.4.4
rspec 3.1.0
I was able to test my autocompleting text field with Poltergeist without much trouble. The main thing to know about is Poltergeist's .native.send_keys method.
Hacking together a summary out of the Cucumber steps where these lines of code actually live in my project:
find('#username').native.send_keys "the" # this field autocompletes usernames
wait_until { all('a', text: "the_username").any? }
find('a', text: "the_username").click
Then I submit the form and assert the expected results on the following page in the usual way.
wait_until (a reimplementation of a method which was removed from Capybara 2) takes a block which returns true when we should stop waiting. It's faster than waiting for 5 seconds or whatever every time.
def wait_until(delay = 1)
seconds_waited = 0
while ! yield && seconds_waited < Capybara.default_wait_time
sleep delay
seconds_waited += 1
end
raise "Waited for #{Capybara.default_wait_time} seconds but condition did not become true" unless yield
end
I think perhaps you need a mixture of triggering KEYDOWN, but also setting the keycode to DOWN.
e.g.
var keyEvent = $.Event("keydown");
keyEvent.keyCode = $.ui.keyCode.DOWN;
$("#autocomplete").val("j");
$("#autocomplete").trigger(keyEvent);
Here is a working jsfiddle example showing an item selected by the autocomplete: http://jsfiddle.net/alexkey/74BST/ I'm not sure why you need to trigger keydown twice, but that's a problem to solve separately (if a problem at all).
However I'm not familiar with the unit testing framework you are using, but I hope the above helps.
Credit goes to JQuery AutoComplete, manually select first searched item and bind click
I'm using the example code form: http://api.jqueryui.com/autocomplete/#entry-examples
The autocomplete unit tests that the jquery-ui team uses may come in useful for inspiration: https://github.com/jquery/jquery-ui/tree/master/tests/unit/autocomplete
Also a reference to the keycode: http://api.jqueryui.com/jQuery.ui.keyCode/
I had this problem and no proposed solution could solve it. My tests always failed when trying to find the ul.ui-autocomplete element. I finally noticed, that jQuery autocomplete appends the ul to the end of the html page and NOT to the input field in question. In my spec, I follow the practice of targeting my forms explicitly by within my_form do and doing all the fill_instuff inside this block:
within my_form do
fill_autocomplete …
end
Of course this could never find the ul attached OUTSIDE this form element. My solution was simple: Use jQuery autocomplete's attribute appendTo: '#id_of_input_field' when initializing autocomplete. Now it can find my uland everything works fine.

autocomplete of words in the middle (jQuery UI)

Anyone know good sample code using jQuery UI's autocomplete widget that can autocomplete words in the middle of a text box, not just autocomplete of the word at the end only?
I'm using the jquery UI autocomplete widget for a component that supports entry of multiple tags. It's like like stack overflow's tag editor, but simpler: no fancy formatting in the autocomplete dropdown, no "tag" background images in the edit box. I started with the jQuery UI Autocomplete Multiple sample and modified it.
It's working OK, except autocomplete doesn't work for tags in the middle of a multi-tag string. For example, if I type C Fortran and then put the caret right after C and type +, I'd expect to see C++ in the autocomplete list but instead I see Fortran again.
Here's the code so far: http://jsfiddle.net/WCfyB/4/
This is the same problem described by autocomplete in middle of text (like Google Plus), but the problem in that question was simpler because he could rely on an empty # in the text to signal when to show the autocomplete. In my case, I can't just rely on the text-- I actually need to find out where the caret is and autocomplete for the word where the caret is.
I could build this myself using caret or another plugin, but was wondering if there was already a jQuery-UI-based sample online that I could use without re-inventing another wheel, especially if there are browser-specific corner cases to worry about. Ideally, it'd behave like this: whenever the user places the caret inside or at the end of a tag (where tags are always separated by 1+ spaces), autocomplete is shown for that tag. Know a good sample?
I don't know of any examples like this, but here's something that you could start with:
var availableTags = [ ... ];
function split(val) {
return val.split(/ \s*/);
}
function extractLast(term) {
return split(term).pop();
}
$("#tags")
.bind("keydown", function(event) {
// don't navigate away from the field on tab when selecting an item
if (event.keyCode === $.ui.keyCode.TAB
&& $(this).data("autocomplete").menu.active) {
event.preventDefault();
}
})
.autocomplete({
minLength: 0,
source: function(request, response) {
var results = [],
selectionStart = this.element[0].selectionStart
term = extractLast(request.term.substring(0, selectionStart));
if (term.length > 0) {
results = $.ui.autocomplete.filter(availableTags, term);
}
response(results);
},
focus: function() {
return false; // prevent value inserted on focus
},
select: function(event, ui) {
var terms = split(this.value.substring(0, this.selectionStart));
terms.pop(); // remove the current input
terms.push(ui.item.value); // add the selected item
this.value =
$.trim(terms.join(" ") + this.value.substring(this.selectionStart)) + " ";
return false;
}
});
Example: http://jsfiddle.net/WCfyB/7/
The major caveat here is that the selectionStart method does not work in IE. You can replace those function calls with one of those plugins you mentioned in your question.

How can I stop CKEditor replacing paragraphs with double <br> when pasting from Word

When I use the Paste from Word or Paste as plain text options in CKEditor double line returns get converted into double instances of <br>.
Whilst this is technically exactly what exists in the source file it would be fantastic if there were a way to have all double line returns be converted into paragraph tags when pasting from an external document. TinyMCE doesn’t seem to struggle with this.
Is this possible with CKEditor?
I'm using Pixel & Tonic's Wygwam version of CKEditor and the inference of this support thread is that it can't be done as exists :(
Since I spent hours searching for the same thing and found lots of posts asking but none answering I decided to work it out on my own.
Here is the solution, hope it saves you the time I wasted:
In config.js add:
CKEDITOR.on('instanceReady', function (ev) {
ev.editor.on('paste', function (ev) {
ev.data.html = ev.data.html.replace(/<br>\s*<br>/g, '</p><p>');
});
});
What really really fixed this issue for me was:
Put this line in config.js:
"config.enterMode = CKEDITOR.ENTER_BR;"
This will create a "br" instead of a "p" when you hit ENTER in the ckeditor.
Then put this script where you replace the
CKEDITOR.replace( 'descripcion', { enterMode : CKEDITOR.ENTER_BR, shiftEnterMode : CKEDITOR.ENTER_BR } );
CKEDITOR.on( 'instanceReady', function( ev )
{
ev.editor.dataProcessor.writer.setRules( 'br',
{
indent : false,
breakBeforeOpen : false,
breakAfterOpen : false,
breakBeforeClose : false,
breakAfterClose : false
});
});
</script>
That script prevented the double "br"
Hope it helps.
Here is my work-around for this in CKEditor 4 (where ck is an editor instance):
ck.on('afterPaste', function() {
var data = ck.getData();
data = data.replace(/<br \/>\s*<br \/>/g, '</p><p>');
ck.setData(data);
});

Resources