Background
Creating a WYSIWYG editor that uses Dave Hauenstein's edit-in-place and jQuery's autocomplete plug-in.
Source Code
The code has the following parts: HTML, edit-in-place, and autocomplete.
HTML
The HTML element that becomes an edit-in-place text field:
<span class="edit" id="edit">Edit item</span>
Edit In Place
The JavaScript code that uses the edit-in-place plugin:
$('#edit').editInPlace({
url : window.location.pathname,
hover_class : 'inplace_hover',
params : 'command=update-edit',
element_id : 'edit-ac',
on_edit : function() {
return '';
}
});
The on_edit is custom code to call a function when the user clicks on the associated span element. The value returned is used to seed the text input field. In theory, the plugin should replace the span element in the DOM with an input element similar to:
<input type="text" id="edit-ac" />
Autocomplete
The autcomplete code:
$('#edit-ac').autocomplete({
source : URL_BASE + 'search.php',
minLength : 2,
delay : 25
});
Problem
It seems that the timing for the autocomplete code is incorrect with respect to the timing for the edit-in-place code.
I think that the edit-in-place plugin needs to call the autocomplete code snippet after the input field has been added to the DOM.
Question
How would you integrate the two plugins so that when a user clicks on the edit-in-place field that the autocomplete code provides autocomplete functionality on the DOM element added by edit-in-place?
Thank you!
Solution
Modify the jQuery in-place-editor source code by instructing the code to append an identifier onto the input field.
jQuery in-place-editor Updates
This section details the updates required.
Type Definition
Provide new attributes in the default settings:
editor_id: "inplace_id", // default ID for the editor input field
on_create: null, // function: called after the editor is created
inputNameAndClass
Change the inputNameAndClass function to use the editor_id setting:
/**
* Returns the input name, class, and ID for the editor.
*/
inputNameAndClass: function() {
var result = ' name="inplace_value" class="inplace_field" ';
// DJ: Append the ID to the editor input element.
if( this.settings.editor_id ) {
result += 'id="' + this.settings.editor_id + '" ';
}
return result;
},
replaceContentWithEditor
Change the replaceContentWithEditor function to call the create function:
replaceContentWithEditor: function() {
var buttons_html = (this.settings.show_buttons) ? this.settings.save_button + ' ' + this.settings.cancel_button : '';
var editorElement = this.createEditorElement(); // needs to happen before anything is replaced
/* insert the new in place form after the element they click, then empty out the original element */
this.dom.html('<form class="inplace_form" style="display: inline; margin: 0; padding: 0;"></form>')
.find('form')
.append(editorElement)
.append(buttons_html);
// DJ: The input editor is part of the DOM and can now be manipulated.
if( this.settings.on_create ) {
this.settings.on_create( editorElement );
}
},
Autocomplete Coupling
The autocomplete functionality can now be activated the edit-in-place is revealed.
Combined Call
The HTML snippet remains the same as before. The new call to editInPlace resembles:
$('#edit').editInPlace({
url : window.location.pathname,
hover_class : 'inplace_hover',
params : 'command=update-edit',
editor_id : 'edit-ac',
on_create : function( editor ) {
$('#edit-ac').autocomplete({
source : URL_BASE + 'search.php',
minLength : 2,
delay : 25
});
},
on_edit : function() {
return '';
}
});
This attaches the autocomplete function to the in-place-editor whenever the in-place-editor is activated.
Related
I am using Algolia and instantsearch.js for one of my projects.
I managed to get the custom searchbox to work. Inside JS I create an input field and style it to look nice:
// searchbox design
var searchField = '<div class="input-search">';
searchField += '<i class="input-search-icon wb-search" aria-hidden="true"></i>';
searchField += '<input type="text" class="form-control" id="customerSearch" name="search" placeholder="Search for customer..">';
searchField += '<span id="custom-clear-all-container"></span>';
searchField += '</div>';
// custom `renderFn` to render the custom SearchBox widget
function renderFnSB(SearchBoxRenderingOptions, isFirstRendering) {
if (isFirstRendering) {
SearchBoxRenderingOptions.widgetParams.containerNode.html(searchField);
SearchBoxRenderingOptions.widgetParams.containerNode
.find('input')
.on('keyup', function() {
SearchBoxRenderingOptions.refine($(this).val());
});
SearchBoxRenderingOptions.widgetParams.containerNode
.find('input')
.val(SearchBoxRenderingOptions.query);
}
}
// connect `renderFn` to SearchBox logic
var customSearchBox = instantsearch.connectors.connectSearchBox(renderFnSB);
// mount widget on the page
search.addWidget(
customSearchBox({
containerNode: $('#custom-searchbox')
})
);
The code above is almost identical to the code example in Algolia's documentation. I just added a "div" in DOM with id="custom-searchbox". This works just fine.
Then I try to create a custom clear all button and append it to:
<span id="custom-clear-all-container"></span>
inside searchbox. Again I use an almost identical code as Algolia's documentation:
function renderFnCA(ClearAllRenderingOptions, isFirstRendering) {
var containerNode = ClearAllRenderingOptions.widgetParams.containerNode;
if (isFirstRendering) {
var markup = $('<button id="custom-clear-all" type="button" class="input-search-close icon wb-close" aria-label="Close"></button>');
containerNode.append(markup);
markup.on('click', function(event) {
event.preventDefault();
ClearAllRenderingOptions.refine();
})
}
var clearAllCTA = containerNode.find('#custom-clear-all');
clearAllCTA.attr('disabled', !ClearAllRenderingOptions.hasRefinements)
};
// connect `renderFn` to ClearAll logic
var customClearAllWidget = instantsearch.connectors.connectClearAll(renderFnCA);
// mount widget on the page
search.addWidget(
customClearAllWidget({
containerNode: $('#custom-clear-all-container'),
clearsQuery: true
})
);
When I run the code, everything is working but I don't see the clearAll button (in my case is an X icon).
If I insert the:
<span id="custom-clear-all-container"></span>
directly into HTML and remove it from JS, then it works perfectly.
I don't know what is going wrong. By the way, the code to add clearAll is after the code for adding the searchbox. So, the searchbox DOM element is already placed in DOM when we are trying to append clearAll button.
Any ideas why this is happening?
Thanks in advance!
You're probably going to want to leave the button in the dom and instead of completely removing it $('#custom-clear-all').hide() it instead.
The algolia search widget is probably looking for the button all the time and when its not found in dom it doesn't run
I'm editing a plugin under CKEditor, link.js under link plugin. I added a text input field and trying to assign a css class to input but can't do it. This is my code I added.
{
type : 'text',
class: 'myClassName',
label : 'myInputLabel'
}
I also tried className, inputClass, inputStyle instead of class but none of them worked.
I need to have something like this
<input class="cke_dialog_ui_input_text myClassName" type="text" aria-labelledby="cke_102_label">
Workaround using jQuery
Seems CKEditor doesn't let you assign className directly to input element but it assigns it to input element's third level parent div
<div class='cke_dialog_ui_text myClassName'>
<div>
<div>
<input class='cke_dialog_ui_input_text'>
</div>
</div>
</div>
What I did to make it work
{
type : 'text',
className : 'myClassName',
label : 'myInputLabel',
onLoad : function () {
var myid = this.getElement().getId();
var that = this;
var thatobj = $("#" + myid);
var obj = $(".cke_dialog_ui_input_text", thatobj);
//Have fun with your "obj" text input
//variable "that" is good to have because you may need it inside of jQuery plugins like that.getDialog().setValueOf('info', 'url', 'blahblah');
}
}
className should work for you according to the documentation. Double-check your code. Otherwise try to mess with your field on dialogDefinition event. See my previous answer.
{
type: 'text',
label: 'My text input',
onLoad : function () {
this.getInputElement().$.classList.add('class-for-my-input');
}
}
How can I locate the tag which calls a JQuery script, when
the tag is dynamically loaded, so won't be the last
tag on the page?
I'm using the MagicSuggest autosuggest library. I want to give certain suggested items a different background color depending on their contents, which I'm currently doing by adding JQuery inside a tag, which I'm adding on to the String which is returned to be rendered inside the selection div. Then, to get the div the item is suggested in, I need to essentially get the parent() of the tag, and change it's css() properties. How can I get this current script tag however?
I'm currently assigned each new tag an id generated from incrementing a JS variable - which works, but isn't very 'nice'! Is there anyway I can directly target the tag with JQuery?
If it perhaps makes it clearer, here is my current selectionRenderer function.
selectionRenderer: function(a){
var toRet = a.english;
var blueBgScript = "<script id=ft" + freeTextFieldID + ">$('#ft" + freeTextFieldID + "').parent().css('background', 'blue');</script>"
if(a.id==a.english){
toRet += blueBgScript;
freeTextFieldID++;
}
return toRet;
},
Why don't you add some code at afterrender event instead? Add some tag to flag the options that need a different background, then detect the parents and add a class (or edit the bg property) or whatever you like:
var newMS = $('#idStr').magicSuggest({
data: 'states.php',
displayField: 'english',
valueField: 'id',
selectionRenderer: function(a){
var toRet = a.english;
if(a.id==a.english) toRet = "<span class='freetext'>" + toRet + "</span>";
return toRet;
},
});
$(newMS).on('selectionchange', function(event,combo,selection){
var selDivs = $(event.target._valueContainer[0].parentNode).children('div'); //Get all the divs in the selction
$.each(selDivs,function(index,value){ //For each selected item
var span = $(value).children('.freetext'); //It if contains a span of class freetext
if(span.length == 1) $(value).css('background','blue'); //Turn the background blue
});
I'm using jqGrid to build a custom inline entry widget on a page. The relevant part of the jqjGrid setup is:
colModel:[ {
// Other columns removed.
{name:'ship',index:'ship', width:90, editable: true, sortable: false,
edittype: "custom",
editoptions:{ custom_element: customElement,
custom_value: customValue} }
],
And my callback function is:
function customElement(value, options) {
var a = $("<input>").attr({
type: 'text',
size: 2,
value: value,
style: 'float: left'
}).add(
$("<span>").attr({
style: 'float: left; margin-top: 2px;',
'class': 'ui-icon ui-icon-search'
}).click(function() {
// My custom function here.
})
).appendTo($("<div>"));
return a;
}
This all works properly.
However, I'm building a library to manage several jqgrid tables on a page. I'd like to use the same function to build the custom elements on several of those tables. The problem is that this particular click() function needs to know which jquery table it's dealing with.
I can get the table ID through a hacky way at the beginning of customElement and pass it in the closure to the function:
var fieldID = options.id;
var rowID = fieldID.replace(/_.*/, "");
var containingTable = $("#" + rowID + "_id").closest("table");
But this assumes that the column "id" exists in the current jqGrid, and it's an earlier (leftward) column. I can't use the "ship" column because it hasn't been created yet. I can't assume there are other rows in the table that would have a "ship" column either.
How can I, in a custom_element handler, reliably get a handle to the "calling" table?
I agree that it's a problem in the current code of jqGrid. There are no simple and elegant way to get the id of the grid for which the control are created.
One workaround you already suggested. I can suggest you one more version to get the id of "the calling table".
Custom element can be used for every editing mode: inline editing, form editing and cell editing. The click handle receive Event object e
.click(function(e) {
// My custom function here.
})
which you can to detect the id of the "the calling grid". In case of inline editing or cell editing the detection is the most easy. It will be
.click(function(e) {
var $grid = $(e.target).closest('table.ui-jqgrid-btable');
...
})
Inside of click event handler of the form editing you can use
.click(function(e) {
// you can do the following
var $t = $(e.target).closest('table.EditTable'),
tid = $t.attr('id'); // id=TblGrid_list
if (typeof tid === "string" && tid.substr(0, 8) === 'TblGrid_') {
var gridId = tid.substr(8);
}
var grid = $('#' + $.jgrid.jqID(gridId));
// or the following
var $f = $(e.target).closest('form.FormGrid'),
fid = $f.attr('id'); // id=FrmGrid_list
if (typeof fid === "string" && fid.substr(0, 8) === 'FrmGrid_') {
var grid_id = tid.substr(8);
}
var mygrid = $('#' + $.jgrid.jqID(grid_id));
...
})
The code above use the fact that the editing form contains two elements which ids will be constructed based on the id of the grid: the <table> element inside of the editing form has the id="TblGrid_list" if the grid id="list" and the <form> element has the id="FrmGrid_list".
The usage of $('#' + $.jgrid.jqID(gridId)) is more safe as $('#' + gridId) because it gives correct results in case when the grid id contain meta characters. The jqID function is very easy (see here). It makes just escaping of the meta characters used in the jQuery selector.
i want to understand this piece of code as i m a beginner.Mostly these red color fonts. they are taking which page value?
$(function() {
$("#title").blur(function() { QuestionSuggestions(); });
});
function QuestionSuggestions() {
var s = $("#title").val();
if (s.length > 2 && !($("#title").hasClass('edit-field-overlayed'))) {
document.title = s + " - Stack Overflow";
$("#question-suggestions").load("/search/titles?like=" + escape(s));
}
}
function QuestionSuggestions() {
var s = $("#title").val(); // Here we take the value of element with ID "title"
// If the length of the title is bigger than 2 or
// the element doesn't have 'edit-field-overlayed' class
if (s.length > 2 && !($("#title").hasClass('edit-field-overlayed'))) {
// we set the title of the document as <title>[our old title] - Stack Overflow</title>
document.title = s + " - Stack Overflow";
// Load data from the server and place the returned HTML into the matched element.
$("#question-suggestions").load("/search/titles?like=" + escape(s));
}
}
If you element with id title has longer title than 2, lets say "My title" and there is no class "edit-field-overlayed" we change the page title to "My title - Stack Overflow" and load html/text in element "#question-suggestions" by querying the URL http://yoursite.tld/search/titles?like=My%20title
This looks like jQuery code. The expression $("#title") is a call to the jQuery $ function. It looks for the HTML tag with id="title" and wraps a utility object around it. .blur is a method of that utility object, which supplies a function to be called when the mouse moves off the corresponding element.
The best thing would be to get stuck into a jQuery tutorial like this one.
The peice of code posted, condensed to a sentence is
"When the field with id 'title' blurs, execute an ajax query passing the content of that field as a parameter"