Exclude ID in Twitter Bootstrap Scrollspy - javascript

I have a Twitter Bootstrap site with a main menu full of links. I have Scrollspy setup to target that menu and works great.
However, I need scrollspy to exclude the last link in the menu. Is there any easy option or attribute to do this? Each link has an ID.
To note, the last menu item is called, "Login" has an ID and clicking it opens a Twitter Modal. However since the modal is in the code even when not loaded it's affecting the scrollspy.
So just need a way to tell exclude an ID so something hypothetically like:

I suggest you extend ScrollSpy with that desired functionality, like this https://stackoverflow.com/a/13460392/1407478
ScrollSpy extension with excludeable ID's :
// save the original function object
var _superScrollSpy = $.fn.scrollspy;
// add a array of id's that need to be excluded
$.extend( _superScrollSpy.defaults, {
excluded_ids : []
});
// create a new constructor
var ScrollSpy = function(element, options) {
_superScrollSpy.Constructor.apply( this, arguments )
}
// extend prototypes and add a super function
ScrollSpy.prototype = $.extend({}, _superScrollSpy.Constructor.prototype, {
constructor: ScrollSpy
, _super: function() {
var args = $.makeArray(arguments)
// call bootstrap core
_superScrollSpy.Constructor.prototype[args.shift()].apply(this, args)
}
, activate: function (target) {
//if target is on our exclusion list, prevent the scrollspy to activate
if ($.inArray(target, this.options.excluded_ids)>-1) {
return
}
this._super('activate', target)
}
});
// override the old initialization with the new constructor
$.fn.scrollspy = $.extend(function(option) {
var args = $.makeArray(arguments),
option = args.shift()
//this runs everytime element.scrollspy() is called
return this.each(function() {
var $this = $(this)
var data = $this.data('scrollspy'),
options = $.extend({}, _superScrollSpy.defaults, $this.data(), typeof option == 'object' && option)
if (!data) {
$this.data('scrollspy', (data = new ScrollSpy(this, options)))
}
if (typeof option == 'string') {
data[option].apply( data, args )
}
});
}, $.fn.scrollspy);
For the example at http://twitter.github.com/bootstrap/javascript.html#scrollspy, and if you want the ScrollSpy to prevent showing #mdo, it should be initialized like this
$(".scrollspy-example").scrollspy({
excluded_ids : ['#mdo']
});
you could try to place the code in a separate file, scrollspy-addon.js, include it and initialize your scrollspy with
$("#your-scrollspy-id").scrollspy({
excluded_ids : ['#login']
});

I'm not aware of any "easy" fix for your situation. However you can use the "activate" event to check for the ID and act upon it:
$('#myscrollspyID li').on('activate', function(){
var id = $(this).find("a").attr("href");
if (id === "#yourlastID"){
//do something, i.e. remove all active classes from your scrollspy object, so none are shown as active
}
}
P.S: this i pretty rough code, but I modified some code I am using myself. I use the active event to check the ID of the active item, and change the background color of the navigator bar to the color corresponding to the active item :-)

Related

$ionicposition only setting correct values on a modal the first time a modal is opened

I have created a custom select directive and within this directive when you tap into the options it should use $ionicposition to locate the selected option based on the HTML element ID, and then scroll to it using $ionicscroll delegate.
This is the function which locates the option, and then scrolls to it:
private scrollToOption(selectedCode: activeh.objects.ICode): void {
this.$timeout(() => {
let item: HTMLElement = document.getElementById("code-" + selectedCode.CodeID);
if(item){
var itemPosition = this.$ionicPosition.offset(angular.element(item));
this.$ionicScrollDelegate.$getByHandle('modalContent').scrollTo(0, itemPosition.top + 40, false);
}
}, 200);
}
This is where the scrollTo function is called:
private createModal(): void {
this.$ionicModal.fromTemplateUrl('app/shared/directives/selectoption/selectoption.modal.html', {
scope: this.$scope,
hardwareBackButtonClose: false
}).then((modal) => {
this.selectModal = modal;
this.selectModal.show();
if (this.selectedVal !== undefined) {
this.scrollToOption(this.selectedVal);
}
});
}
So like mentioned in the title, this code works perfectly but only the first time that the modal is opened. After the modal has been closed and opened again the $ionicposition.offset is returning values of only 0.
I found a (probably partial) solution to this, wherein instead of using .hide() to hide the modal I use .remove() to completely remove it forcing a complete rebuild.
This mimics the behaviour where it worked the first time as now every time the modal is opened is the 'first' time.

Showing Customized Context Menu on clicking shapes(objects of fabric.js) in Canvas

I'm using fabric.js to create shapes on canvas . on right click on the shapes i want to show a context menu based on the shape selected. I'm able to capture the right click event and find which object the right click is done. but i don know how to show a context menu from a javascript (something like contextmenu.show). below is the code which im using to find the object. Any one please help.
$('.upper-canvas').bind('contextmenu', function (e) {
var objectFound = false;
var clickPoint = new fabric.Point(e.offsetX, e.offsetY);
e.preventDefault();
canvas.forEachObject(function (obj) {
if (!objectFound && obj.containsPoint(clickPoint)) {
objectFound = true;
// here need to set a customized context menu and show it
// but dont now how to do so.
}
});
});
Using jquery-ui-contextmenu you could instantiate a context menu on the canvas and modify the menu entries depending on the target.
(Note that the code is untested, but it should show the idea. Have a look at the API docs for details.)
$(document).contextmenu({
delegate: ".upper-canvas",
menu: [...], // default menu
beforeOpen: function (event, ui) {
var clickPoint = new fabric.Point(event.offsetX, event.offsetY);
// find the clicked object and re-define the menu or
// optionally return false, to prevent opening the menu:
// return false;
// En/disable single entries:
$(document).contextmenu("enableEntry", ...);
// Show/hide single entries:
$(document).contextmenu("showEntry", ...);
// Redefine the whole menu:
$(document).contextmenu("replaceMenu", ...);
},
select: function(event, ui) {
// evaluate selected entry...
}
});

How to re-run JavaScript when DOM mutates?

I'm using Template.rendered to setup a dropdown replacement like so:
Template.productEdit.rendered = function() {
if( ! this.rendered) {
$('.ui.dropdown').dropdown();
this.rendered = true;
}
};
But how do I re-run this when the DOM mutates? Helpers return new values for the select options, but I don't know where to re-execute my .dropdown()
I think you don't want this to run before the whole DOM has rendered, or else the event handler will run on EVERY element being inserted:
var rendered = false;
Template.productEdit.rendered = function() {rendered: true};
To avoid rerunning this on elements which are already dropdowns, you could give new ones a class which you remove when you make them into dropdowns
<div class="ui dropdown not-dropdownified"></div>
You could add an event listener for DOMSubtreeModified, which will do something only after the page has rendered:
Template.productEdit.events({
"DOMSubtreeModified": function() {
if (rendered) {
var newDropdowns = $('.ui.dropdown.not-dropdownified');
newDropdowns.removeClass("not-dropdownified");
newDropdowns.dropdown();
}
}
});
This should reduce the number of operations done when the event is triggered, and could stop the callstack from being exhausted
Here's my tentative answer, it works but I'm still hoping Meteor has some sort of template mutation callback instead of this more cumbersome approach:
Template.productEdit.rendered = function() {
if( ! this.rendered) {
$('.ui.dropdown').dropdown();
var mutationOptions = {
childList: true,
subtree: true
}
var mutationObserver = new MutationObserver(function(mutations, observer){
observer.disconnect(); // otherwise subsequent DOM changes will recursively trigger this callback
var selectChanged = false;
mutations.map(function(mu) {
var mutationTargetName = Object.prototype.toString.call(mu.target).match(/^\[object\s(.*)\]$/)[1];
if(mutationTargetName === 'HTMLSelectElement') {
console.log('Select Changed');
selectChanged = true;
}
});
if(selectChanged) {
console.log('Re-init Select');
$('.ui.dropdown').dropdown('restore defaults');
$('.ui.dropdown').dropdown('refresh');
$('.ui.dropdown').dropdown('setup select');
}
mutationObserver.observe(document, mutationOptions); // Start observing again
});
mutationObserver.observe(document, mutationOptions);
this.rendered = true;
}
};
This approach uses MutationObserver with some syntax help I found here
Taking ad educated guess, and assuming you are using the Semantic UI Dropdown plugin, there are four callbacks you can define:
onChange(value, text, $choice): Is called after a dropdown item is selected. receives the name and value of selection and the active menu element
onNoResults(searchValue): Is called after a dropdown is searched with no matching values
onShow: Is called after a dropdown is shown.
onHide: Is called after a dropdown is hidden.
To use them, give the dropdown() function a parameter:
$(".ui.dropdown").dropdown({
onChange: function(value, text, $choice) {alert("You chose " + text + " with the value " + value);},
onNoResults: function(searchValue) {alert("Your search for " + searchValue + " returned no results");}
onShow: function() {alert("Dropdown shown");},
onHide: function() {alert("Dropdown hidden");}
});
I suggest you read the documentation of all plugins you use.

Open specific accordion tab using external link and hash

hi to all I'm new in js sorry for what I ask here now I know its a basic one, I'm working now with accordion plugin that collects all the article that users want to put in accordion and view it in accordion my question is how to open specific tab when is have dynamic id per article inside a item of accordion.. im trying to hook the item using link, http//:example.com#id to open specific tab in accordion here s the plugin code.
hook inside the code and trigger the click event to open the specific the in the accordion plugin
!(function($){
$.fn.spAccordion = function(options){
var settings = $.extend({
hidefirst: 0
}, options);
return this.each(function(){
var $items = $(this).find('>div');
var $handlers = $items.find('.toggler');
var $panels = $items.find('.sp-accordion-container');
if( settings.hidefirst === 1 )
{
$panels.hide().first();
}
else
{
$handlers.first().addClass('active');
$panels.hide().first().slideDown();
}
$handlers.on('click', function(){
if( $(this).hasClass('active') )
{
$(this).removeClass('active');
$panels.slideUp();
}
else
{
$handlers.removeClass('active');
$panels.slideUp();
$(this).addClass('active').parent().find('.sp-accordion-container').slideDown();
}
event.preventDefault();
});
});
};
})(jQuery);
A little thing is, you can use .children('div') instead of .find('>div').
But if you want to get what the hash is set to you can use window.location.hash. By default this is used to identify element IDs. So ideally you could get the element you want to show by doing
if (window.location.hash) {
var $selected = $('#'+window.location.hash);
if ($selected.length) {
// Do what you need to show this element
}
}

Redefining a jQuery dialog button

In our application we use a general function to create jQuery dialogs which contain module-specific content. The custom dialog consists of 3 buttons (Cancel, Save, Apply). Apply does the same as Save but also closes the dialog.
Many modules are still using a custom post instead of an ajax-post. For this reason I'm looking to overwrite/redefine the buttons which are on a specific dialog.
So far I've got the buttons, but I'm unable to do something with them. Is it possible to get the buttons from a dialog (yes, I know) but apply a different function to them?
My code so far:
function OverrideDialogButtonCallbacks(sDialogInstance) {
oButtons = $( '#dialog' ).dialog( 'option', 'buttons' );
console.log(oButtons); // logs the buttons correctly
if(sDialogInstance == 'TestInstance') {
oButtons.Save = function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
}
}
}
$('#dialog').dialog({
'buttons' : {
'Save' : {
id:"btn-save", // provide the id, if you want to apply a callback based on id selector
click: function() {
//
},
},
}
});
Did you try this? to override button's callback based on the need.
No need to re-assign at all. Try this.
function OverrideDialogButtonCallbacks(dialogSelector) {
var button = $(dialogSelector + " ~ .ui-dialog-buttonpane")
.find("button:contains('Save')");
button.unbind("click").on("click", function() {
alert("save overriden!");
});
}
Call it like OverrideDialogButtonCallbacks("#dialog");
Working fiddle: http://jsfiddle.net/codovations/yzfVT/
You can get the buttons using $(..).dialog('option', 'buttons'). This returns an array of objects that you can then rewire by searching through them and adjusting the click event:
// Rewire the callback for the first button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons[0].click = function() { alert('Click rewired!'); };
See this fiddle for an example: http://jsfiddle.net/z4TTH/2/
If necessary, you can check the text of the button using button[i].text.
UPDATE:
The buttons option can be one of two forms, one is an array as described above, the other is an object where each property is the name of the button. To rewire the click event in this instance it's necessary to update the buttons option in the dialog:
// Rewire the callback for the OK button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons.Ok = function() { alert('Click rewired!'); };
$('#dialog').dialog('option', 'buttons', buttons);
See this fiddle: http://jsfiddle.net/z4TTH/3/
Can you try binding your new function code with Click event of Save?
if(sDialogInstance == 'TestInstance') {
$('#'+savebtn_id).click(function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
});
}

Categories