Add widgets to existing jQuery-UI lib - jquery-ui

I have to extend an existing project which uses version 1.10.4, and this jQuery-UI version is build without any widgets.
Now I want to use the widgets "Spinner" and "Selectmenu".
For the "Spinner"-widget: this is available for jQuery version 1.10.4.
The "Selectmenu"-widget is available from versoin 1.11.4.
Unfortunately, I can't update the current versoin of jQuery-UI, so I want to know how/if it's possible to enhance the current version with these two widgets.

Using the $.widget() you can extend or create your own custom widgets. I gathered this code from https://code.jquery.com/ui/1.11.4/jquery-ui.js and since $.ui.menu exists in 1.10.4, this mostly works. Some adjustments must be made.
I gathered the styleing from https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css
$(function() {
$.widget("custom.selectmenu", {
version: "1.11.4",
defaultElement: "<select>",
options: {
appendTo: null,
disabled: null,
icons: {
button: "ui-icon-triangle-1-s"
},
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
width: null,
// callbacks
change: null,
close: null,
focus: null,
open: null,
select: null
},
_create: function() {
var selectmenuId = this.element.uniqueId().attr("id");
this.ids = {
element: selectmenuId,
button: selectmenuId + "-button",
menu: selectmenuId + "-menu"
};
this._drawButton();
this._drawMenu();
if (this.options.disabled) {
this.disable();
}
},
_drawButton: function() {
var that = this;
// Associate existing label with the new button
this.label = $("label[for='" + this.ids.element + "']").attr("for", this.ids.button);
this._on(this.label, {
click: function(event) {
this.button.focus();
event.preventDefault();
}
});
// Hide original select element
this.element.hide();
// Create button
this.button = $("<span>", {
"class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
tabindex: this.options.disabled ? -1 : 0,
id: this.ids.button,
role: "combobox",
"aria-expanded": "false",
"aria-autocomplete": "list",
"aria-owns": this.ids.menu,
"aria-haspopup": "true"
})
.insertAfter(this.element);
$("<span>", {
"class": "ui-icon " + this.options.icons.button
})
.prependTo(this.button);
this.buttonText = $("<span>", {
"class": "ui-selectmenu-text"
})
.appendTo(this.button);
this._setText(this.buttonText, this.element.find("option:selected").text());
this._resizeButton();
this._on(this.button, this._buttonEvents);
this.button.one("focusin", function() {
// Delay rendering the menu items until the button receives focus.
// The menu may have already been rendered via a programmatic open.
if (!that.menuItems) {
that._refreshMenu();
}
});
this._hoverable(this.button);
this._focusable(this.button);
},
_drawMenu: function() {
var that = this;
// Create menu
this.menu = $("<ul>", {
"aria-hidden": "true",
"aria-labelledby": this.ids.button,
id: this.ids.menu
});
// Wrap menu
this.menuWrap = $("<div>", {
"class": "ui-selectmenu-menu ui-front"
})
.append(this.menu)
.appendTo(this._appendTo());
// Initialize menu widget
this.menuInstance = this.menu
.menu({
role: "listbox",
select: function(event, ui) {
event.preventDefault();
// support: IE8
// If the item was selected via a click, the text selection
// will be destroyed in IE
that._setSelection();
that._select(ui.item.data("ui-selectmenu-item"), event);
},
focus: function(event, ui) {
var item = ui.item.data("ui-selectmenu-item");
// Prevent inital focus from firing and check if its a newly focused item
if (that.focusIndex != null && item.index !== that.focusIndex) {
that._trigger("focus", event, {
item: item
});
if (!that.isOpen) {
that._select(item, event);
}
}
that.focusIndex = item.index;
that.button.attr("aria-activedescendant",
that.menuItems.eq(item.index).attr("id"));
}
})
.data("ui-menu");
// Adjust menu styles to dropdown
this.menu
.addClass("ui-corner-bottom")
.removeClass("ui-corner-all");
// Don't close the menu on mouseleave
this.menuInstance._off(this.menu, "mouseleave");
// Cancel the menu's collapseAll on document click
this.menuInstance._closeOnDocumentClick = function() {
return false;
};
// Selects often contain empty items, but never contain dividers
this.menuInstance._isDivider = function() {
return false;
};
},
refresh: function() {
this._refreshMenu();
this._setText(this.buttonText, this._getSelectedItem().text());
if (!this.options.width) {
this._resizeButton();
}
},
_refreshMenu: function() {
this.menu.empty();
var item,
options = this.element.find("option");
if (!options.length) {
return;
}
this._parseOptions(options);
this._renderMenu(this.menu, this.items);
this.menuInstance.refresh();
this.menuItems = this.menu.find("li").not(".ui-selectmenu-optgroup");
item = this._getSelectedItem();
// Update the menu to have the correct item focused
this.menuInstance.focus(null, item);
this._setAria(item.data("ui-selectmenu-item"));
// Set disabled state
this._setOption("disabled", this.element.prop("disabled"));
},
open: function(event) {
if (this.options.disabled) {
return;
}
// If this is the first time the menu is being opened, render the items
if (!this.menuItems) {
this._refreshMenu();
} else {
// Menu clears focus on close, reset focus to selected item
this.menu.find(".ui-state-focus").removeClass("ui-state-focus");
this.menuInstance.focus(null, this._getSelectedItem());
}
this.isOpen = true;
this._toggleAttr();
this._resizeMenu();
this._position();
this._on(this.document, this._documentClick);
this._trigger("open", event);
},
_position: function() {
this.menuWrap.position($.extend({ of: this.button
}, this.options.position));
},
close: function(event) {
if (!this.isOpen) {
return;
}
this.isOpen = false;
this._toggleAttr();
this.range = null;
this._off(this.document);
this._trigger("close", event);
},
widget: function() {
return this.button;
},
menuWidget: function() {
return this.menu;
},
_renderMenu: function(ul, items) {
var that = this,
currentOptgroup = "";
$.each(items, function(index, item) {
if (item.optgroup !== currentOptgroup) {
$("<li>", {
"class": "ui-selectmenu-optgroup ui-menu-divider" +
(item.element.parent("optgroup").prop("disabled") ?
" ui-state-disabled" :
""),
text: item.optgroup
})
.appendTo(ul);
currentOptgroup = item.optgroup;
}
that._renderItemData(ul, item);
});
},
_renderItemData: function(ul, item) {
return this._renderItem(ul, item).data("ui-selectmenu-item", item);
},
_renderItem: function(ul, item) {
var li = $("<li>");
if (item.disabled) {
li.addClass("ui-state-disabled");
}
this._setText(li, item.label);
return li.appendTo(ul);
},
_setText: function(element, value) {
if (value) {
element.text(value);
} else {
element.html(" ");
}
},
_move: function(direction, event) {
var item, next,
filter = ".ui-menu-item";
if (this.isOpen) {
item = this.menuItems.eq(this.focusIndex);
} else {
item = this.menuItems.eq(this.element[0].selectedIndex);
filter += ":not(.ui-state-disabled)";
}
if (direction === "first" || direction === "last") {
next = item[direction === "first" ? "prevAll" : "nextAll"](filter).eq(-1);
} else {
next = item[direction + "All"](filter).eq(0);
}
if (next.length) {
this.menuInstance.focus(event, next);
}
},
_getSelectedItem: function() {
return this.menuItems.eq(this.element[0].selectedIndex);
},
_toggle: function(event) {
this[this.isOpen ? "close" : "open"](event);
},
_setSelection: function() {
var selection;
if (!this.range) {
return;
}
if (window.getSelection) {
selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(this.range);
// support: IE8
} else {
this.range.select();
}
// support: IE
// Setting the text selection kills the button focus in IE, but
// restoring the focus doesn't kill the selection.
this.button.focus();
},
_documentClick: {
mousedown: function(event) {
if (!this.isOpen) {
return;
}
if (!$(event.target).closest(".ui-selectmenu-menu, #" + this.ids.button).length) {
this.close(event);
}
}
},
_buttonEvents: {
// Prevent text selection from being reset when interacting with the selectmenu (#10144)
mousedown: function() {
var selection;
if (window.getSelection) {
selection = window.getSelection();
if (selection.rangeCount) {
this.range = selection.getRangeAt(0);
}
// support: IE8
} else {
this.range = document.selection.createRange();
}
},
click: function(event) {
this._setSelection();
this._toggle(event);
},
keydown: function(event) {
var preventDefault = true;
switch (event.keyCode) {
case $.ui.keyCode.TAB:
case $.ui.keyCode.ESCAPE:
this.close(event);
preventDefault = false;
break;
case $.ui.keyCode.ENTER:
if (this.isOpen) {
this._selectFocusedItem(event);
}
break;
case $.ui.keyCode.UP:
if (event.altKey) {
this._toggle(event);
} else {
this._move("prev", event);
}
break;
case $.ui.keyCode.DOWN:
if (event.altKey) {
this._toggle(event);
} else {
this._move("next", event);
}
break;
case $.ui.keyCode.SPACE:
if (this.isOpen) {
this._selectFocusedItem(event);
} else {
this._toggle(event);
}
break;
case $.ui.keyCode.LEFT:
this._move("prev", event);
break;
case $.ui.keyCode.RIGHT:
this._move("next", event);
break;
case $.ui.keyCode.HOME:
case $.ui.keyCode.PAGE_UP:
this._move("first", event);
break;
case $.ui.keyCode.END:
case $.ui.keyCode.PAGE_DOWN:
this._move("last", event);
break;
default:
this.menu.trigger(event);
preventDefault = false;
}
if (preventDefault) {
event.preventDefault();
}
}
},
_selectFocusedItem: function(event) {
var item = this.menuItems.eq(this.focusIndex);
if (!item.hasClass("ui-state-disabled")) {
this._select(item.data("ui-selectmenu-item"), event);
}
},
_select: function(item, event) {
var oldIndex = this.element[0].selectedIndex;
// Change native select element
this.element[0].selectedIndex = item.index;
this._setText(this.buttonText, item.label);
this._setAria(item);
this._trigger("select", event, {
item: item
});
if (item.index !== oldIndex) {
this._trigger("change", event, {
item: item
});
}
this.close(event);
},
_setAria: function(item) {
var id = this.menuItems.eq(item.index).attr("id");
this.button.attr({
"aria-labelledby": id,
"aria-activedescendant": id
});
this.menu.attr("aria-activedescendant", id);
},
_setOption: function(key, value) {
if (key === "icons") {
this.button.find("span.ui-icon")
.removeClass(this.options.icons.button)
.addClass(value.button);
}
this._super(key, value);
if (key === "appendTo") {
this.menuWrap.appendTo(this._appendTo());
}
if (key === "disabled") {
this.menuInstance.option("disabled", value);
this.button
.toggleClass("ui-state-disabled", value)
.attr("aria-disabled", value);
this.element.prop("disabled", value);
if (value) {
this.button.attr("tabindex", -1);
this.close();
} else {
this.button.attr("tabindex", 0);
}
}
if (key === "width") {
this._resizeButton();
}
},
_appendTo: function() {
var element = this.options.appendTo;
if (element) {
element = element.jquery || element.nodeType ?
$(element) :
this.document.find(element).eq(0);
}
if (!element || !element[0]) {
element = this.element.closest(".ui-front");
}
if (!element.length) {
element = this.document[0].body;
}
return element;
},
_toggleAttr: function() {
this.button
.toggleClass("ui-corner-top", this.isOpen)
.toggleClass("ui-corner-all", !this.isOpen)
.attr("aria-expanded", this.isOpen);
this.menuWrap.toggleClass("ui-selectmenu-open", this.isOpen);
this.menu.attr("aria-hidden", !this.isOpen);
},
_resizeButton: function() {
var width = this.options.width;
if (!width) {
width = this.element.show().outerWidth();
this.element.hide();
}
this.button.outerWidth(width);
},
_resizeMenu: function() {
this.menu.outerWidth(Math.max(
this.button.outerWidth(),
// support: IE10
// IE10 wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping
this.menu.width("").outerWidth() + 1
));
},
_getCreateOptions: function() {
return {
disabled: this.element.prop("disabled")
};
},
_parseOptions: function(options) {
var data = [];
options.each(function(index, item) {
var option = $(item),
optgroup = option.parent("optgroup");
data.push({
element: option,
index: index,
value: option.val(),
label: option.text(),
optgroup: optgroup.attr("label") || "",
disabled: optgroup.prop("disabled") || option.prop("disabled")
});
});
this.items = data;
},
_destroy: function() {
this.menuWrap.remove();
this.button.remove();
this.element.show();
this.element.removeUniqueId();
this.label.attr("for", this.ids.element);
}
});
$("#spinner").spinner();
$("#speed").selectmenu();
});
.ui-selectmenu-menu {
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 0;
display: none;
}
.ui-selectmenu-menu .ui-menu {
overflow: auto;
/* Support: IE7 */
overflow-x: hidden;
padding-bottom: 1px;
}
.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
font-size: 1em;
font-weight: bold;
line-height: 1.5;
padding: 2px 0.4em;
margin: 0.5em 0 0 0;
height: auto;
border: 0;
}
.ui-selectmenu-open {
display: block;
}
.ui-selectmenu-button {
display: inline-block;
overflow: hidden;
position: relative;
text-decoration: none;
cursor: pointer;
}
.ui-selectmenu-button span.ui-icon {
right: 0.5em;
left: auto;
margin-top: -8px;
position: absolute;
top: 50%;
}
.ui-selectmenu-button span.ui-selectmenu-text {
text-align: left;
padding: 0.4em 2.1em 0.4em 1em;
display: block;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.js" integrity="sha256-tp8VZ4Y9dg702r7D6ynzSavKSwB9zjariSZ4Snurvmw=" crossorigin="anonymous"></script>
<p>
<label for="spinner">Select a value:</label>
<input id="spinner" name="value">
</p>
<label for="speed">Select a speed</label>
<select name="speed" id="speed">
<option>Slower</option>
<option>Slow</option>
<option selected="selected">Medium</option>
<option>Fast</option>
<option>Faster</option>
</select>
The first issue, 1.11.4 makes use of .menu('instance') which is not available to 1.10.4. In the code above, this was used on Line 145, and can be reverted to .data("ui-menu"); to compensate.
Second, when selecting an item, it triggered an error as item was undefined. This is alsos related to the above issue. Need to work on it more. Work in progress.

Related

How to make jQuery UI Tooltip stay on, on hover

Does anybody know how can I make jQuery UI tooltip to stay visible on hover. That is- I want it to stay visible when I move mouse from p element to tooltip.
Have tried on fiddle, but it seems there's a problem with :hover.
$("p").tooltip({
hide: {
effect: 'explode'
}
}).mouseleave(function () {
if ($('p').is(':hover')) {
ui.tooltip.preventDefault();
$('p').tooltip('open');
}
}).focusout(function () {
$('p').tooltip('close');
});
jsFiddle
That was a little tricky...
This script extends the standard jQuery UI 1.12.1, so that you get two extra options, allowing you to keep the tooltip open, while hover (the mouse stays on) it.
(function($) {
var uiTooltipTmp = {
options: {
hoverTimeout: 200,
tooltipHover: false // to have a regular behaviour by default. Use true to keep the tooltip while hovering it
},
// This function will check every "hoverTimeout" if the original object or it's tooltip is hovered. If not, it will continue the standard tooltip closure procedure.
timeoutHover: function (event,target,tooltipData,obj){
var TO;
var hov=false, hov2=false;
if(target !== undefined) {
if(target.is(":hover")){
hov=true;}
}
if(tooltipData !== undefined) {
if($(tooltipData.tooltip).is(":hover")){
hov=true;}
}
if(target !== undefined || tooltipData !== undefined) {hov2=true;}
if(hov) {
TO = setTimeout(obj.timeoutHover,obj.options.hoverTimeout,event,target,tooltipData,obj);
}else{
target.data('hoverFinished',1);
clearTimeout(TO);
if(hov2){
obj.closing = false;
obj.close(event,true);}
}
},
// Changed standard procedure
close: function(event) {
var tooltip,
that = this,
target = $( event ? event.currentTarget : this.element ),
tooltipData = this._find( target );
if(that.options.tooltipHover && (target.data('hoverFinished')===undefined || target.data('hoverFinished') === 0)){
target.data('hoverFinished',0);
setTimeout(that.timeoutHover, that.options.hoverTimeout,event, target, tooltipData, that);
}
else
{
if(that.options.tooltipHover){
target.data('hoverFinished',0);}
// The rest part of standard code is unchanged
if ( !tooltipData ) {
target.removeData( "ui-tooltip-open" );
return;
}
tooltip = tooltipData.tooltip;
if ( tooltipData.closing ) {
return;
}
clearInterval( this.delayedShow );
if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
target.attr( "title", target.data( "ui-tooltip-title" ) );
}
this._removeDescribedBy( target );
tooltipData.hiding = true;
tooltip.stop( true );
this._hide( tooltip, this.options.hide, function() {
that._removeTooltip( $( this ) );
} );
target.removeData( "ui-tooltip-open" );
this._off( target, "mouseleave focusout keyup" );
if ( target[ 0 ] !== this.element[ 0 ] ) {
this._off( target, "remove" );
}
this._off( this.document, "mousemove" );
if ( event && event.type === "mouseleave" ) {
$.each( this.parents, function( id, parent ) {
$( parent.element ).attr( "title", parent.title );
delete that.parents[ id ];
} );
}
tooltipData.closing = true;
this._trigger( "close", event, { tooltip: tooltip } );
if ( !tooltipData.hiding ) {
tooltipData.closing = false;
}
}
}
};
// Extending ui.tooltip. Changing "close" function and adding two new parameters.
$.widget( "ui.tooltip", $.ui.tooltip, uiTooltipTmp);
})(jQuery);
jQuery(document).ready(function($) {
$("h3").tooltip({hoverTimeout: 250, tooltipHover: true});
});
body {
background-color: #f3f3f3;
}
h3 {
display: inline-block;
margin: 1em 0 0 1em;
padding: 1em;
background-color: #FF7E6B;
color: #fff;
}
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<div>
<h3 title="I'll be here while you are hovering me or my creator.">
Hover me</h3>
</div>
$('[data-toggle="popover"]').popover({ trigger: "manual" }).on(
{
mouseenter: function () {
var $this = $(this);
$this.popover("show");
$(".popover").on("mouseleave", function () {
$this.popover('hide');
});
},
mouseleave: function () {
var $this = $(this);
setTimeout(function () {
if (!$(".popover:hover").length) {
$this.popover("hide");
}
}, 350);
}
});
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span type="button" role="button" class="glyphicon glyphicon-question-sign" data-toggle="popover" data-trigger="hover" data-placement="auto" data-html="true" data-content="For instance enter a link here <a href='https://google.com' target='_blank'>Almost know everything</a>"></span>

asp.net mvc 4 bootstrap jquery combobox autocomplete

I'm having problems with the rendering of combobox in my project.
The autocomplete functionality works correctly. But you can not click to select the items in the combobox. Also the items are badly formed, and a descriptive label appears at the bottom.
Print:
http://tinypic.com/r/2jebtau/8
View:
<div class="col-lg-10">
#Html.DropDownList("IdProcedimento", (IEnumerable<SelectListItem>)ViewBag.PriorityID, new { #class = "form-control", id = "combobox" })
</div>
Script:
(function ($) {
$.widget("custom.combobox", {
_create: function () {
this.wrapper = $("<span>")
.addClass("custom-combobox")
.insertAfter(this.element);
this.element.hide();
this._createAutocomplete();
this._createShowAllButton();
},
_createAutocomplete: function () {
var selected = this.element.children(":selected"),
value = selected.val() ? selected.text() : "";
this.input = $("<input>")
.appendTo(this.wrapper)
.val(value)
.attr("title", "")
.addClass("custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left")
.autocomplete({
delay: 0,
minLength: 0,
source: $.proxy(this, "_source")
})
.tooltip({
tooltipClass: "ui-state-highlight"
});
this._on(this.input, {
autocompleteselect: function (event, ui) {
ui.item.option.selected = true;
this._trigger("select", event, {
item: ui.item.option
});
},
autocompletechange: "_removeIfInvalid"
});
},
_createShowAllButton: function () {
var input = this.input,
wasOpen = false;
$("<a>")
.attr("tabIndex", -1)
.tooltip()
.appendTo(this.wrapper)
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass("ui-corner-all")
.addClass("custom-combobox-toggle ui-corner-right")
.mousedown(function () {
wasOpen = input.autocomplete("widget").is(":visible");
})
.click(function () {
input.focus();
// Close if already visible
if (wasOpen) {
return;
}
// Pass empty string as value to search for, displaying all results
input.autocomplete("search", "");
});
},
_source: function (request, response) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
response(this.element.children("option").map(function () {
var text = $(this).text();
if (this.value && (!request.term || matcher.test(text)))
return {
label: text,
value: text,
option: this
};
}));
},
_removeIfInvalid: function (event, ui) {
// Selected an item, nothing to do
if (ui.item) {
return;
}
// Search for a match (case-insensitive)
var value = this.input.val(),
valueLowerCase = value.toLowerCase(),
valid = false;
this.element.children("option").each(function () {
if ($(this).text().toLowerCase() === valueLowerCase) {
this.selected = valid = true;
return false;
}
});
// Found a match, nothing to do
if (valid) {
return;
}
// Remove invalid value
this.input
.val("")
this.element.val("");
this._delay(function () {
this.input.tooltip("close").attr("title", "");
}, 2500);
this.input.data("ui-autocomplete").term = "";
},
_destroy: function () {
this.wrapper.remove();
this.element.show();
}
});
})(jQuery);
$(function () {
$("#combobox").combobox();
});
Try to add these files:
jquery-ui.css // this is for styling
jquery-1.10.2.js
jquery-ui.js"
And the following css classes are also required:
.custom-combobox {
position: relative;
display: inline-block;
}
.custom-combobox-toggle {
position: absolute;
top: 0;
bottom: 0;
margin-left: -1px;
padding: 0;
/* support: IE7 */
*height: 1.7em;
*top: 0.1em;
}
.custom-combobox-input {
margin: 0;
padding: 0.3em;
}
And check if "form-control" class is having efects.
You have downloaded this from here
Have you changed the paths of images(icons) which are being used by the plugins in CSS.

Prevent default jquery-ui tab behaviour when using keyboard navigation

I'm using jquery-ui tabs and jeditable to inline edit the tab title. But navigating with the cursors in the editable text leads jquery-ui to navigate to the tab next to it.
How can i prevent the jquery default behaviour (disable keyboad navigation in tabs).
Cheers,
Broncko
Solved it by:
$.widget( "ui.tabs", $.ui.tabs, {
options: {
keyboard: true
},
_tabKeydown: function(e) {
if(this.options.keyboard) {
this._super( '_tabKeydown' );
} else {
return false;
}
}
});
A better solution from here http://www.daveoncode.com/2013/09/18/how-to-disable-keyboard-navigation-in-jquery-ui-tabs/ :
jQuery('.foo').tabs({
activate: function(e, ui) {
e.currentTarget.blur();
}
});
It's possible to unbind keydown events when tabs are initialized:
$('#tabs').tabs({
create : function() {
var data = $(this).data('tabs');
data.tabs.add(data.panels).off('keydown');
}
});
Just had to do this myself. This is what worked for me:
$.widget("ui.tabs", $.ui.tabs, {
_tabKeydown: function (event) {
if (event.keyCode !== 38 && event.keyCode !== 40) {
this._super(event);
}
}
});
You can substitute any combination of keys using event.keyCode and even make it customizable with something like:
$.widget("ui.tabs", $.ui.tabs, {
options: {
overrideKeyCodes: [],
},
_tabKeydown: function (event) {
var isOverride = false;
if (Object.prototype.toString.call(this.options.overrideKeyCodes) === '[object Array]') {
for (i = 0; i < this.options.overrideKeyCodes.length; i++) {
if (event.keyCode === this.options.overrideKeyCodes[i]) {
isOverride = true;
break;
}
}
}
if (!isOverride) {
this._super(event);
}
}
});
$('#MyTabs').tabs({ overrideKeyCodes: [ 38, 40 ] });
Or even better you can add your own custom behaviors:
$.widget("ui.tabs", $.ui.tabs, {
options: {
overrideKeyCodes: {},
},
tabKeydown: function (event) {
if (this.options.overrideKeyCodes.hasOwnProperty(event.keyCode)) {
if (typeof this.options.overrideKeyCodes[event.keyCode] === 'function') {
this.options.overrideKeyCodes[event.keyCode](event, this._super(event));
}
}
else {
this._super(event);
}
}
});
$('#MyTabs').tabs({
overrideKeyCodes: {
40: function (event, callback) {
console.log(event.keyCode);
},
38: function (event, callback) {
console.log(event.keyCode);
if (callback) {
callback();
}
},
32: null //just let the space happen
}
});

jQuery UI Sortable: no changing order of items while sorting

By default, while sorting, items are replaced (for example, if I take the third element and move it to the first, than the first and the second elements will move down)
I do not need this behaviour. I'd like elements not to change order while I finish sorting (release mouse).
I need this because I want to ask user if he want to change element or to re-order?
P.S. option tolerance have only 2 options, and they don't help in this situation.
I meant something like this (sortable list with option of replacing elements):
$(function() {
var
/**
* Sortable List, that can insert or replace elements
*/
SortableList = (function() {
var
// Configuration of Sortable list
// css classes of separator and sortable elements
// jQuery UI droppable and sortable init configuration
CONFIG = {
'confirm-message': 'Insert? Element will be removed',
'separator-class': 'sortable-separator',
'sortable-class': 'sortable-elem',
// Initialization of jQuery UI Droppable
'separators-droppable-init': {
drop: function(e, ui) {
// Insertation
var drag = ui.draggable,
drop = $(this),
a = drop.prev(),
b = drop.next();
Separators.clean();
Elements.insert(a, b, drag);
Separators.init();
},
over: function(e, ui) {
$(this).css({
'background-color': 'lightgreen'
});
},
out: function(e, ui) {
$(this).css({
'background-color': 'white'
});
}
},
'sortable-droppable-init': {
drop: function(e, ui) {
// Replace
var drag = ui.draggable,
drop = $(this);
if (Elements.replace(drop, drag)) {
Separators.init();
}
}
},
'sortable-draggable-init': {
revert: true,
start: function(e, ui) {
$(this).css({
'z-index': '999',
'cursor': 'move'
});
},
stop: function(e, ui) {
$(this).css({
'z-index': '1',
'cursor': 'default'
});
}
}
},
getSeparators = function() {
return $('.' + CONFIG['separator-class']);
},
getSortables = function() {
return $('.' + CONFIG['sortable-class']);
},
/**
* Separators Handler
*/
Separators = (function() {
var
// create separator html element
_create = function() {
return $('<div />').addClass(CONFIG['separator-class']);
},
// create all separators and insert them
createAll = function() {
getSortables().each(function() {
$(this).before(_create());
}).last().after(_create());
return Separators;
},
// remove all separators
clean = function() {
var s = getSeparators();
if (s.length) {
s.remove();
}
return Separators;
},
// init jQuery UI Droppable interface
initDroppable = function() {
getSeparators().droppable(CONFIG['separators-droppable-init']);
return Separators;
},
// Initialization of separators
init = function() {
if (getSeparators().length) {
Separators.clean();
}
return Separators.createAll().initDroppable();
};
// Return result
Separators = {
clean: clean,
createAll: createAll,
init: init,
initDroppable: initDroppable
};
return Separators;
}()),
Elements = (function() {
var
init = function() {
getSortables().droppable(CONFIG['sortable-droppable-init']).draggable(CONFIG['sortable-draggable-init']);
return Elements;
},
// replaces element A with element B
replace = function(A, B) {
if (!confirm(CONFIG['confirm-message'])) {
return false;
}
B.draggable("option", "revert", false).css({
top: 0,
left: 0
});
A.replaceWith(B);
return Elements;
},
// insert element C between elements A and B
insert = function(A, B, C) {
C.draggable("option", "revert", false).css({
top: 0,
left: 0
});
if (!A.length) {
B.before(C);
} else {
A.after(C);
}
return Elements;
},
// result to return
Elements = {
init: init,
replace: replace,
insert: insert
};
return Elements;
}()),
init = function() {
Separators.init();
Elements.init();
};
return {
init: init
};
}());
SortableList.init();
});
.sortable-elem {
width: 32px;
height: 32px;
background-color: darkred;
border: 1px solid brown;
color: white;
}
.sortable-separator {
width: 100px;
height: 16px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<link href="//code.jquery.com/ui/1.8.16/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="//code.jquery.com/ui/1.8.16/jquery-ui.min.js"></script>
<div class="sortable-elem" data-order="1">1</div>
<div class="sortable-elem" data-order="2">2</div>
<div class="sortable-elem" data-order="3">3</div>
<div class="sortable-elem" data-order="4">4</div>
<div class="sortable-elem" data-order="5">5</div>
<div class="sortable-elem" data-order="6">6</div>
<div class="sortable-elem" data-order="7">7</div>
<div class="sortable-elem" data-order="8">8</div>
<div class="sortable-elem" data-order="9">9</div>
<div class="sortable-elem" data-order="10">10</div>
View on JSFiddle

jQuery cookie not clearing upon UI close

As you can see, I'm using cookies to pop up modal confirmation boxes and alerts. While these have worked for a long time until very recently, I must have added something to this chunk of code and it all went haywire. The "close" function on the modal is supposed to clear the cookies so the pop up won't pop up anymore, now it is not clearing the cookies unless there is a CKEditor on the page, which puzzles me since the call for editor is AFTER the modals...
I forgot in what order I added each element - stupid, I know - and am having a hard time what could've caused the problem. I also recently wrote a bunch of mod_rewrite rules, though I'm not sure if that would change anything.
PLEASE HELP! I need this project done this week...
Here's my entire jQuery chunk:
<script type="text/javascript">
$(document).ready(function(){
$("body").prepend('<div id="topbar" class=""><\/div><div id="subnavbar" class="subnavbar-<?php echo $nav_id; ?>"><\/div>');
$("#group-left a").prepend('- ');
$("input").hint();
$("#mypassword").focus(function(){
this.type='password';
$(this).val('');
});
$("#mypassword").blur(function(){
if($(this).val() == "Password") {
this.type='text';
}
});
$("label.required").append('<span style="color: #F00; float: none;">*<\/span>');
$("#coupon_start").datepicker({dateFormat: 'yy-mm-dd'});
$("#coupon_end").datepicker({dateFormat: 'yy-mm-dd'});
$("div.blog-entry img").each(function() {
var blogImgFloat = $(this).css("float");
if(blogImgFloat == "left") {
$(this).css("margin-right", "15px");
} else if(blogImgFloat == "right") {
$(this).css("margin-left", "15px");
}
});
$.fn.tipper = function() {
if($(this).attr('alt')) {
if($(this).hasClass('height')) {
$(this).qtip({
content: $(this).attr('alt'),
position: {
corner: {
target: 'topMiddle',
tooltip: 'bottomMiddle'
}
},
style: {
name: 'cream', // Inherit from preset style
padding: 10,
tip: 'bottomMiddle',
border: {
width: 5,
radius: 5
}
},
show: 'focus',
hide: 'blur'
});
}
else {
$(this).qtip({
content: $(this).attr('alt'),
position: {
corner: {
target: 'rightMiddle',
tooltip: 'leftMiddle'
}
},
style: {
name: 'cream', // Inherit from preset style
padding: 10,
tip: 'leftMiddle',
border: {
width: 5,
radius: 5
}
},
show: 'focus',
hide: 'blur'
});
}
} else { return false; }
};
$("#content input").each( function(){ $(this).tipper(); } );
$("#content textarea").each( function(){ $(this).tipper(); } );
// calendar
$("#ajax-datepicker").datepicker({
onSelect: function(date,instance){
$(".eventdateheader").html(date);
$.ajax
({
type: "GET",
url: "/grab_events.php",
data: "date=" + $.datepicker.formatDate("yy-mm-dd", $(this).datepicker('getDate')),
success: function(result)
{
$("#eventslist").html(result);
}
});
},
minDate: '-2W',
dateFormat: 'M d, yy'
});
$("#event-datepicker").datepicker({
onSelect: function(date,instance){
window.location = "/events.php?date=" + $.datepicker.formatDate("yy-mm-dd", $(this).datepicker('getDate'));
},
minDate: '-2W',
gotoCurrent: true,
dateFormat: 'M d, yy'
});
$("#event-datepicker").datepicker('setDate', '<?php echo $selected_date; ?>');
$(".date").datepicker({
dateFormat: 'yy-mm-dd',
showOn: 'button',
buttonImage: '/images/calendar.gif',
buttonImageOnly: true
});
// regular dialog box
$("#dialog").dialog({autoOpen: false, modal: true});
$("#dialog_link").click(function(){
$("#dialog").dialog("open");
return false; });
// user context menu
$("a.user").contextMenu(
{ menu: 'HKPopUpMenu' },
function(action, el, pos) {
var username = $(el).attr('id');
if(action == "viewprofile") { window.location = "/profile.php?req="+username; }
else if(action == "viewblog") { window.location = "/profile_blog.php?req="+username; }
else if(action == "sendmsg") {
$("#sendmsg_to").val(username);
$("#sendmsg_div").dialog("open");
return false;
}
else if(action == "sendwink") {
$.cookie("modal_confirm", "<?php echo $alert_13_send_wink_frag; ?>"+username+"?");
$.cookie("confirmGo", "/sendwink_process.php?req="+username+"&nexturl=<?php echo curPageURL(); ?>");
window.location.reload();
}
else {
alert(
'Action: ' + action + '\n\n' +
'Element text: ' + thisid + '\n\n' +
'X: ' + pos.x + ' Y: ' + pos.y + ' (relative to element)\n\n' +
'X: ' + pos.docX + ' Y: ' + pos.docY+ ' (relative to document)'
);
}
}
);
// send message form
$("#sendmsg_div").dialog({
autoOpen: false,
height: 300,
width: 500,
modal: true,
buttons: {
'<?php echo $popmenu_sendmsg; ?>': function() {
//validate
var m_to = $('input[name=sendmsg_to]');
var m_subject = $('input[name=sendmsg_subject]');
var m_body = $('textarea[name=sendmsg_body]');
if (m_to.val()=='') {
m_to.addClass('highlight');
return false;
} else { m_to.removeClass('highlight'); }
if (m_subject.val()=='') {
m_subject.addClass('highlight');
return false;
} else { m_subject.removeClass('highlight'); }
if (m_body.val()=='') {
m_body.addClass('highlight');
return false;
} else { m_body.removeClass('highlight'); }
$("#sendmsg_form").submit();
$(this).dialog('close');
},
Cancel: function() {
$(this).dialog('close');
}
},
close: function() {
}
});
$("a.leftmenu_compose_message").click(function(){
$("#sendmsg_div").dialog("open");
return false; });
$("a.mail").click(function(){
$("#sendmsg_to").val($(this).attr('id'));
$("#sendmsg_div").dialog("open");
return false; });
// save search form
$("#savequery_div").dialog({
autoOpen: false,
height: 220,
width: 300,
modal: true,
buttons: {
'<?php echo $popmenu_savequery; ?>': function() {
$("#savequery_form").submit();
$(this).dialog('close');
},
Cancel: function() {
$(this).dialog('close');
}
},
close: function() {
}
});
$("a.savequery").click(function(){
$("#savequery_div").dialog("open");
return false; });
// confirm box
if($.cookie("modal_confirm")!==null) {
$("body").prepend('<div id="confirm" title="System Message">'+$.cookie("modal_confirm")+'<\/div>');
var g = $("#confirm");
g.html( g.html().replace(/\+/g," ") );
$("#confirm").dialog({
modal: true,
stack: true,
buttons: {
'OK': function() {
window.location = "\/" + $.cookie("confirmGo");
$(this).dialog('close');
},
Cancel: function() {
$(this).dialog('close');
}
},
close: function(){
$.cookie("modal_confirm",null);
$.cookie("confirmGo",null);
$(this).remove;
}
});
}
// alert box
if($.cookie("alert")!==null) {
$("body").prepend('<div id="alert" title="System Message">'+$.cookie("alert")+'<\/div>');
var f = $("#alert");
f.html( f.html().replace(/\+/g," ") );
$("#alert").dialog({
modal: true,
stack: true,
buttons: {
'OK': function() {
$(this).dialog('close');
}
},
close: function(){
$.cookie("alert",null); $(this).remove;
}
});
}
<?php if($include_editor) { ?>
// editors
$("textarea.editor").ckeditor( {
skin: 'kama',
toolbar: 'HKEditor',
filebrowserImageUploadUrl: '/php/upload.php',
language: <?php if($_SESSION["user_lng"] == "kor") { echo "'ko'"; } else { echo "'en'"; } ?>
});
<?php } ?>
}); // END DOC.READY
I figured it out.
It wasn't working because javascript can't deal with server-relative URLs.
I fixed it by specifying the paths for cookie:
$.cookie("modal_confirm", null, { path: '/' });
etc.

Resources