Wicket Autocomplete in wicket 6.2.0 - wicket

I've been trying to use an example that appears in the following link:
http://www.mysticcoders.com/blog/autocomplete-with-an-object/
the trouble is nothing happens...
when start typing something in the text field nothing happens.
i debugged and it seems that the builder & renderer are not fired.
can someone please tell me why nothing happens?
I'm using Wicket 6.2.0 version.

Wicket since version 6.0 bundles its own version of jQuery (jQuery v1.8.3 as of Wicket 6.5.0).
Make sure you don't load your own jQuery.
Previously I had loaded our own jQuery (using RequireJS) while using Wicket 1.5.9. And suddenly after upgrading to Wicket 6.5.0 (actually, Pax Wicket 2.1.0) AutoComplete (among other things) stopped working.
My solution was to use the bundled jQuery and avoid loading our own jQuery.
If you use RequireJS to load jQuery, as we do, you will want to "replace" the jQuery module with a dummy module as follows:
define([], function() {
return jQuery;
});
So other modules that use RequireJS to load jQuery will continue to work.

You should investigate Igor Vaynberg's Wicket-Select2 project which offers very nice features for auto-completion, multi-selection etc. Especially as you mentioned something like adding recipients to new mails in Gmail, you should consider using something based on this example.

Can you provide your code?
Did you use an AutoCompleteTextField? In this case you must add some css-classes in your stylesheet that define the autocomplete list.
For testing this class i would choose DefaultCssAutoCompleteTextField. This works out-of-the-box. You only have to implement the getChoices Method

As #Rudi Wijava said it could be jQuery version problem.
In my project I have same problem but I can't use bundle version of jQuery couse skin required higher than Wicket provides. But it's simple solution for that. In your Application settings you can set jQuery reference to your own like this:
jQueryLibrarySettings.setJQueryReference(new UrlResourceReference(Url.parse(contextPath
+ "/static/js/libs/jquery-2.0.2.min.js")));
You can do this in class that extends WebApplication class
http://ci.apache.org/projects/wicket/apidocs/6.0.x/org/apache/wicket/protocol/http/WebApplication.html

You can use following link to do Autocomplete textbox which is easy to use :
http://www.7thweb.net/wicket-jquery-ui/autocomplete/DefaultAutoCompletePage;jsessionid=ACC1524F61A303942AEE7C28D096DF7D?0
For Example:
package com.googlecode.wicket.jquery.ui.samples.pages.autocomplete;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.Model;
import com.googlecode.wicket.jquery.ui.form.autocomplete.AutoCompleteTextField;
import com.googlecode.wicket.jquery.ui.panel.JQueryFeedbackPanel;
public class DefaultAutoCompletePage extends AbstractAutoCompletePage
{
private static final long serialVersionUID = 1L;
private static final List<String> CHOICES = Arrays.asList("Acid rock", "Alternative metal", "Alternative rock", "Anarcho punk", "Art punk", "Art rock", "Beat music", "Black metal", "Blues-rock", "Britpop", "Canterbury scene",
"Chinese rock", "Christian metal", "Crossover Thrash Metal", "Crust punk", "Crustgrind", "Dark cabaret", "Death metal", "Deathcore", "Deathrock", "Desert rock", "Djent", "Doom metal", "Dream pop", "Drone metal",
"Dunedin Sound", "Electronic rock", "Emo", "Experimental rock", "Folk metal", "Folk rock", "Freakbeat", "Funk metal", "Garage punk", "Garage rock", "Glam metal", "Glam rock", "Goregrind", "Gothic metal", "Gothic rock",
"Grindcore", "Groove metal", "Grunge", "Hard rock", "Hardcore punk", "Heavy metal", "Indie pop", "Indie rock", "Industrial metal", "Industrial rock", "J-Rock", "Jazz-Rock", "Krautrock", "Math rock", "Mathcore",
"Melodic Death Metal", "Melodic metalcore", "Metalcore", "Neo-psychedelia", "New Prog", "New Wave", "No Wave", "Noise pop", "Noise rock", "Noisegrind", "Nu metal", "Paisley Underground", "Pop punk", "Pop rock", "Pornogrind",
"Post-Britpop", "Post-grunge", "Post-hardcore", "Post-metal", "Post-punk", "Post-punk revival", "Post-rock", "Power metal", "Power pop", "Progressive metal", "Progressive rock", "Psychedelic rock", "Psychobilly", "Punk rock",
"Raga rock", "Rap metal", "Rap rock", "Rapcore", "Riot grrrl", "Rock and roll", "Rock en EspaƱol", "Rock in Opposition", "Sadcore", "Screamo", "Shoegazer", "Slowcore", "Sludge metal", "Soft rock", "Southern rock", "Space Rock",
"Speed metal", "Stoner rock", "Sufi rock", "Surf rock", "Symphonic metal", "Technical Death Metal", "Thrash metal", "Thrashcore", "Twee Pop", "Unblack metal", "World Fusion");
public DefaultAutoCompletePage()
{
// Form //
final Form<Void> form = new Form<Void>("form");
this.add(form);
// FeedbackPanel //
final FeedbackPanel feedback = new JQueryFeedbackPanel("feedback");
form.add(feedback.setOutputMarkupId(true));
// Auto-complete //
form.add(new AutoCompleteTextField<String>("autocomplete", new Model<String>()) {
private static final long serialVersionUID = 1L;
#Override
protected List<String> getChoices(String input)
{
List<String> choices = new ArrayList<String>();
String inputLowerCase = input.toLowerCase();
int count = 0;
for (String choice : CHOICES)
{
if (choice.toLowerCase().startsWith(inputLowerCase))
{
choices.add(choice);
// limits the number of results
if (++count == 20)
{
break;
}
}
}
return choices;
//
// Equivalent to:
// return ListUtils.startsWith(input, CHOICES);
//
}
#Override
protected void onSelected(AjaxRequestTarget target)
{
info("Your favorite rock genre is: " + this.getModelObject());
target.add(feedback);
}
});
}
}
HTML:
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
<wicket:head>
<title>Wicket - jQuery UI: auto-complete</title>
<style type="text/css">
.ui-autocomplete {
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
padding-right: 20px;
}
</style>
</wicket:head>
</head>
<body>
<wicket:extend>
<div id="wrapper-panel-frame" class="ui-corner-all">
<form wicket:id="form">
<div>Choose your favorite rock genre: (that starts with your criteria)</div>
<br/>
<input wicket:id="autocomplete" type="text" size="30" title="enter your criteria here"></input><br/>
<br/>
<div wicket:id="feedback" style="width: 360px;"></div>
</form>
</div>
</wicket:extend>
</body>
</html>

Related

User snippets not working in VScode

Hi guys I'm using VScode and trying to get some user snippets to work.
I've tried adding them to both the javascriptreact.json file and the javascript.json file... and even the html.json file but with no success.
I know VSCode uses Emmet, and am confused as to whether user snippets work with emmet rather than intellisense, and if so am I putting this in the wrong file?
Cheers in advance for any help!
I am trying to overwrite the default div. span. img. etc. by adding the following snippets:
"Expand ReactQL Div": {
"prefix: "div.",
"body": [
"<div className={css.:1}>:2</div>;"
],
"description": "expand div"
},
"Expand ReactQL img": {
"prefix: "img.",
"body": [
"<img src={:1} alt=":2" className={css.:3} />;"
],
"description": "expand img"
},
"Expand ReactQL span": {
"prefix: "span.",
"body": [
"<span className={css.1:}>:2</span>;"
],
"description": "expand span"
}
I'd imagine you have solved this one, but for anyone else,
There a few issues with your snippets:
Missing " within your prefix definition, the : is also enclosed in quotes.
{css.:1} syntax works like so ${1:css}
An example:
"Expand ReactQL Div": {
"prefix": "div.",
"body": [
"<div className=${1:css}>${2}</div>"
],
"description": "expand div"
},
Demo of snippet in action

Flexible content modules in Silverstripe

We are looking at using Silverstripe CMS and want to be able to have modules which can be reordered.
We have come from a Wordpress setup and mostly use the flexible content ACF field. Modules (e.g. text, masthead or video) need to be able to be re-ordered.
We use our CMS's as an API so these modules are output as a section to the page or post:
[
{
"id": 10,
"title": "Post title",
"slug": "post_slug",
"path": "/post_slug",
"template": "campaign",
"published": "2017-05-25 06:09:36",
"image": null,
"seo": {
"title": "",
"description": "",
"image": {
},
},
"sections": [
{
"type": "masthead",
"Title": "",
"video": false,
"image": [
],
"showCta": false,
"cta": [
]
},
{
"type": "video_text",
"video_text": [
{
"type": "video",
"video_url": "https://www.youtube.com/watch?v=asdfa",
"video_length": "07:38",
"video_preview": false
},
{
"type": "text",
"title": "Video Title",
"content": "Video text content",
"call_to_action": false,
"cta": [
]
}
]
},
{
"type": "text",
"title": "Text Title",
"content": "",
"alignment": "centre",
"call_to_action": false,
"cta": {
"text": "CTA button",
"link_type": "internal_link",
"internal_link": "about",
"external_link": "",
"section_id": [
]
}
},
]
}
]
Does Silverstripe have it's own way of handling modules / do I need to ditch this flexible content modules method? How do others handle flexible content modules in Silverstripe?
Both silverstripe-blocks and silverstripe-elemental works very well in their own regard but I don't think they will achieve what you want. These modules don't really give you the power to use pre-defined templates. You can hook the templates in but the code will be massive. I not sure if there is an open source module for that yet.
From your JSON code, in order to have those Sections to render something like this below;
<section id="Sections">
<div id="video_text" class="section">
<iframe width="560" height="315" src="https://www.youtube.com/watch?v=asdfa" frameborder="0" allowfullscreen></iframe>
</section>
<div id="text" class="section">
<h2>Text Title</h2>
<a class='text-center btn btn-default' href="/about/">CTA button</a>
</section>
</sections>
You might want to do this.
Use DataObjects (DO) for you Sections, easy for re-ordering.
Create an abstract DO, BlockSection, with fields like Title(Varchar), Content(HTMLText), Sort(Int) and most importantly has_one to Page.
For the video use can name the DO VideoBlockSection and it extends BlockSection,
TextBlockSection for the other one. Don't forget the $singular_name for each DO (useful for nice class naming in the Grid)
On Page getCMSFields add the Grid to manage the Sections. You need to add GridFieldSortableRows and GridFieldAddNewMultiClass and now you can add you Section on each Page.
Add has_many from Page to BlockSection and a method that will render the Blocks and outputs the html.
Page.php
private static $has_many = array(
"Sections" => "BlockSection",
);
function SectionContent()
$aContent = ArrayList::create();
$oSections = $this->Sections();
if (count($oSections )) {
foreach ( $oSections as $oSection ) {
$aContent->push(ArrayData::create([
"Section" => $oSection,
"Content" => $oSection->renderWith([$oSection->ClassName, get_parent_class($oSection)]),
]));
}
}
return $aContent;
For the VideoBlockSection the template array list will be VideoBlockSection and BlockSection
VideoBlockSection.ss
<div id="video_text_{$ID}" class="section">
<iframe width="560" height="315" src="{$URL}" frameborder="0" allowfullscreen></iframe>
</section>
In you specific case, because you are using an API you need to use a wrapper to render the Template.
It needs to match [section][type] to a Template (renderWith) video_text to VideoBlockSection
Lastly in Page.ss
<% loop $SectionContent %>
{$Content}
<% end_loop %>
This was a proof of concept but its working for me so refactoring, speed and memory usage was not considered (but its working).
This way I had to ditch the unnecessary so called "page types" which I find not to be reusable in most cases.
This works 100% for me and I use it together with Bootstrap 3. I use it to create CTAs, parallax scroll, Google Map Section (multiple maps on one page), Thumbnails. Specify image resize method (Cropped, ByWidth, ByHeight).
DO NOT ditch that flexible content modules method.
I am working on an open source module which works with SS4 and Bootstrap 4 (with possibilities of using any other html framework)

TinyMCE bug with block elements

I have a problem with TinyMCE:
I need to get this code:
<blockquote>
<h2>REVOLUTIONARY QUOTE RELATING MANIFESTO TO PROJECT GOES HERE</h2>
<hr/>
<p>Erik Heinsholt</p>
</blockquote>
TinyMCE settings:
valid_elements: "a[href|target|title],ul,ol,li,br,strong/b,em/i,span[style<text-decoration: underline;|class],u,p,blockquote,hr,h2",
force_br_newlines: false,
force_p_newlines: true,
theme_advanced_buttons1: "undo,redo,|,bold,italic,underline,|,hr,code,preview, styleselect",
schema: "html5",
style_formats : [
{title : "First Word", inline : "span", classes : "first_word"},
{title : "Blockquote", block : "blockquote"},
{title : "Quote Header", inline : "h2"}
]
What I have: I write in admin textarea "REVOLUTIONARY QUOTE RELATING MANIFESTO TO PROJECT GOES HERE <hr /> Erik Heisholt", then select "REVOLUTIONARY QUOTE RELATING MANIFESTO TO PROJECT GOES HERE", set a style "Quote Header" for it, then select all and set a style "Blockquote" for it. As a result I get this:
<blockquote><h2>REVOLUTIONARY QUOTE RELATING MANIFESTO TO PROJECT GOES HERE</h2></blockquote>
<blockquote><hr /></blockquote>
<blockquote><p>Erik Heinsholt</p></blockquote>
What should I do to put all elements in one blockquote tag, not each element??
p.s.: the video describing this problem: http://www.sendspace.com/file/nkz97d
Have a look at the tinymce configuration parameters valid_elements and valid_children.
You can define that h2- and hr-tags may be childs to other htmlnodes.

jquery ui autocomplete js error on keydown

i've included the jquery ui automcomplete plugin into the following structure:
<li class="search">
<input type="text" class="searchfield" name="searchfield" value="Search for Products" />
</li>
my javascript for this input field looks like:
<script type="text/javascript">
function addSearchFieldFunctionality() {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
$('.searchfield').each(function () {
$(this).autocomplete({
source: availableTags,
minLength: 1
}).data("autocomplete")._renderItem = function(ul, item) {
//console.log(item);
var a = $('<a>', {
href: item.value,
text: item.label,
"class" : "mySearchClass"
});
var b = $('<a>', {
href: item.value,
text: "Add", style: "float:right"});
var $li = $('<li></li>', {style:"width:100%"});
return $li.add(a).appendTo(ul);
};
});
}
</script>
I'm loading that function on document ready. for some reason, if a start typing e.g. the first three letters of a item, i get a resultlist. as soon as i push the keydown push button on the keyword, i get the following error in the chrome (latest version) console:
Uncaught TypeError: Cannot read property 'top' of null
a.widget.activate jquery-ui.min.js:12
a.widget.move jquery-ui.min.js:12
a.widget.next jquery-ui.min.js:12
a.widget._move jquery-ui.min.js:12
a.widget._create.element.addClass.attr.attr.bind.bind.d jquery-ui.min.js:12
f.event.dispatch jquery-1.7.1.min.js:3
f.event.add.h.handle.i
i'm using version 1.7.1 of jQuery and Version 1.8.12 of jquery UI
On the demo page of jquery ui autocomplete the keydown works well.
Any ideas what's going wrong with my constellation?
It doesn't make a difference to use remote or local data.
Best regards,
Ramo
I really can make your code working. So I tried to rewrote it in a more simplier way. The problem is render functions only accept strings, not html element. So I add a listener to render the list after its generation (fired on keydown() event).
My thought is you are doing it the wrong way.
why adding another class on those items ? they have already one, so they can be styled.
why transforming them into a nodes ? just add a click() event on them
Could you explain your functional goal ?
// Your list of links
var redirectLinks = {'Ruby': '1234.com', 'Asp': '1235.com'};
function redirect(url) {
// TODO implement window.location=url or whatever you like
if(redirectLinks[url] != undefined) {
alert('redirecting to '+url+' => '+redirectLinks[url]);
}
}
$('.searchfield').each(function () {
$(this).autocomplete(availableTags, {
minLength: 1,
change: function(event, ui) {
console.log('this change event doesnt seem to be fired');
},
select: function(event, ui) {
console.log('this select event doesnt seem to be fired');
}
});
// After the list construction
$(this).keyup(function(e){
if (e.which == 13) { // typing enter validates the input => autocompletechange
console.log('validating input '+$(this).val());
redirect($(this).val());
}
var $list = $('.ac_results:first ul').find('li');
$list.click(function() { // adding an event on suggestion => autocompleteselect
console.log('clicking on suggestion '+$(this).text());
redirect($(this).text());
});
});
});

How to send an email when a user responds to a comment

What I want is to announce the original comment poster, when someone has responded on his comment
It's a bit blurry on how to do this with triggers.
Has anybody done that, or is there another way to do this?
I'm not sure exactly how to do it with the core Triggers module, but this can definitely be done with the Rules Module (assuming Drupal 6... not sure of any issues with Drupal 7 version of Rules).
Download and install Rules
Navigate to admin/rules/trigger/add to create a new rule, name it whatever you like and under the Event dropdown, choose "After saving a new comment" and click Save
Click on the "Add a condition" link choose "Execute custom PHP code". In the PHP code area, add the following then click save:
if ($comment->pid != 0) {
return TRUE;
}
else {
return FALSE;
}
Click "Add an action" and choose "Load comment by id". In the Comment id field add: <?php echo $comment->pid; ?> and click Save
Click "Add an action" again and choose "Load a user account". In the User id field add: <?php echo $comment_loaded->uid; ?> and click Save
Click "Add an action" again and choose "Send a mail to an arbitrary mail address". In the Recipient field add: <?php echo $user_loaded->mail; ?> and fill in the other fields however you like to customize the email.
Now whenever a comment is replied to, an email will be sent to the "replied-to" comment author.
For Drupal 7 website
Here is the code you can import under rules and update your subject and body as per your requirement:
{ "rules_send_reply_notice_for_comments" : {
"LABEL" : "Send reply notice for comments",
"PLUGIN" : "reaction rule",
"OWNER" : "rules",
"TAGS" : [ "comments" ],
"REQUIRES" : [ "rules", "comment" ],
"ON" : { "comment_insert" : [] },
"IF" : [ { "NOT data_is_empty" : { "data" : [ "comment:parent" ] } } ],
"DO" : [
{ "mail" : {
"to" : [ "comment:parent:mail" ],
"subject" : "SUBJECT",
"message" : "Here is the message you want to send [comment:body] regards Gaurav",
"from" : "YOUR EMAIL ADDRESS",
"language" : [ "" ]
}
}
] } }