What to use instead of `toggle(...)` in jQuery > 1.8? - toggle

Now that toggle(...) was deprecated in jQuery 1.8 and then removed in jQuery 1.9
What could be used in general (aside from using the jQuery migrate script) instead of toggle(fn, fn2); thats has the same type of functionality?
Related question (asked about a specific case): What to use instead toggle?
I know that toggle() functionality was not removed, just the ability to add custom toggle functions (aside from the show/hide default functionality).

Here is a simple implementation:
$.fn.toggleClick = function() {
var methods = arguments; // Store the passed arguments for future reference
var count = methods.length; // Cache the number of methods
// Use return this to maintain jQuery chainability
// For each element you bind to
return this.each(function(i, item){
// Create a local counter for that element
var index = 0;
// Bind a click handler to that element
$(item).on('click', function() {
// That when called will apply the 'index'th method to that element
// the index % count means that we constrain our iterator between 0
// and (count-1)
return methods[index++ % count].apply(this, arguments);
});
});
};
and use it as
$('selector').toggleClick( function1, function2, ... );

Related

Find out if a leaflet control has already been added to the map

I wrote a custom Leaflet control. It's some kind of legend that may be added for each layer. The control itself has a close button to remove it from the map (like a popup).
The control can be added by clicking a button.
My problem is that the user may add the same control to the map several times. So what I need is to test if this specific control has already been added to the map and, if so, don't add it again.
I create a control for each layer, passing some options
var control = L.control.customControl(mylayer);
and add it to my map on button click
control.addTo(map);
Now imagine the control has a close button and may be closed. Now if the user clicks the button again, I only want to add the control if it's not already on the map - something like this (hasControl is pseudocode, there is afaik no such function)
if(!(map.hasControl(control))) {
control.addTo(map);
}
For simplicity I made an example where I create a zoom control and add it twice here.
Easiest way is to check for the existence of the _map property on your control instance:
var customControl = new L.Control.Custom();
console.log(customControl._map); // undefined
map.addControl(customControl);
console.log(customControl._map); // returns map instance
But please keep in mind, when using the _map property, that the _ prefix of the property implies that it's a private property, which you are normally not supposed to use. It could be changed or removed in future versions of Leaflet. You're not going to encounter that if you use the follow approach:
Attaching a reference of your custom control to your L.Map instance:
L.Control.Custom = L.Control.extend({
options: {
position: 'bottomleft'
},
onAdd: function (map) {
// Add reference to map
map.customControl = this;
return L.DomUtil.create('div', 'my-custom-control');
},
onRemove: function (map) {
// Remove reference from map
delete map.customControl;
}
});
Now you can check for the reference on your map instance like so:
if (map.customControl) { ... }
Or create a method and include it in L.Map:
L.Map.include({
hasCustomControl: function () {
return (this.customControl) ? true : false;
}
});
That would work like this:
var customControl = new L.Control.Custom();
map.addControl(customControl);
map.hasCustomControl(); // returns true
map.removeControl(customControl);
map.hasCustomControl(); // returns false
Here's a demo of the concept on Plunker: http://plnkr.co/edit/nH8pZzkB1TzuTk1rnrF0?p=preview

Add CSS dynamically to a control in UI5

I'm trying to add a CSS property dynamically to a control.
I have a group of RadioButton. On selection of any one of the buttons, I want to make one layout visible.
Below are some of the snippets I tried, none of them seem to work!
Snippet-1
showhide: function(){
var fcid = sap.ui.getCore().byId("FC7");
fcid.visibility = "hidden";
}
Snippet-2
showhide: function(){
var fcid = sap.ui.getCore().byId("FC7");
jquery('#fcid').css("visibility","hidden");
}`
Snippet-3
showhide: function(){
var fcid = sap.ui.getCore().byId("FC7");
jquery('#fcid').hide();
}
You cannot use fcid.visibility = "hidden"; and expect it to behave like a DOM object; it's not, it's a Javascript class with getters, setters, events, aggregations, etc.
Therefore, you should use the control's properties instead: fcid.setVisible(true);
See the API docs for the correct signature of the control/layout properties
You can:
var fcid = ...byId("FC7");
fcid.setVisible(false);
Or
fcid.$().hide(); // or every other jquery method
Or
fcid.addStyleClass("hiddenObject");
Last one with Css-Class:
.hiddenObject { display:none; }

Add ondblClick and click event to Codemirror

I would like to add onDblClick event to codemirror 2. I found that onCursorActivity does not deliverer the event so there is no way for me from this method to filter the events.
How can I implement onDbClick event on Codemirror ?
Thanks in advance.
You can call on method on object returned by CodeMirror:
var cm = CodeMirror.fromTextArea(document.querySelector('textarea'));
cm.on('dblclick', function() {
alert('You double click the editor');
});
You can find the list of all available events in documentation.
Register a handler on the element returned by the getWrapperElement() method. Unless you want to not just detect double-clicks, but also prevent the default (select word under mouse cursor) from occurring... in that case I guess some modification of the core code is needed.
http://jsfiddle.net/yusafkhaliq/NZF53/1/
Since codemirror renders inside the element specified you can add an ondblclick event to the element, like below the highlighter renders without line numbers once double clicked that specific elements will display line numbers
var codeelems = document.getElementsByClassName("code");
for (i = 0; i < codeelems.length; i++) {
(function ($this) {
var value = $this.innerHTML;
$this.innerHTML = "";
var editor = CodeMirror($this, {
value: value,
mode: "text/javascript",
lineNumbers: false
});
$this.ondblclick = function () {
editor.setOption("lineNumbers", true);
}
})(codeelems[i]);
}

What is the proper way in OpenLayers (OSM) to trigger a popup for a feature?

I have the feature ID, I can grab the marker layer on GeoRSS loadend, but I'm still not sure how to cause the popup to appear programmatically.
I'll create the popup on demand if that's necessary, but it seems as though I should be able to get the id of the marker as drawn on the map and call some event on that. I've tried using jQuery and calling the $(marker-id).click() event on the map elements, but that doesn't seem to be working. What am I missing?
Since I was asked for code, and since I presumed it to be boilerplate, here's where I am so far:
map = new OpenLayers.Map('myMap');
map.addLayer(new OpenLayers.Layer.OSM());
map.addLayer(new OpenLayers.Layer.GeoRSS(name,url));
//I've done some stuff as well in re: projections and centering and
//setting extents, but those really don't pertain to this question.
Elsewhere I've done a bit of jQuery templating and built me a nice list of all the points that are being shown on the map. I know how to do a callback from the layer loadend and get the layer object, I know how to retrieve my layer out of the map manually, I know how to iter over the layers collection and find my layer. So I can grab any of those details about the popup, but I still don't know how to go about using the built-in methods of the DOM or of this API to make it as easy as element.click() which is what I would prefer to do.
You don't have to click the feature to open a popup.
First you need a reference to the feature from the feature id. I would do that in the loadend event of the GeoRSS layer, using the markers property on the layer.
Assuming you have a reference to your feature, I would write a method which handles the automatic popup:
var popups = {}; // to be able to handle them later
function addPopup(feature) {
var text = getHtmlContent(feature); // handle the content in a separate function.
var popupId = evt.xy.x + "," + evt.xy.y;
var popup = popups[popupId];
if (!popup || !popup.map) {
popup = new OpenLayers.Popup.Anchored(
popupId,
feature.lonlat,
null,
" ",
null,
true,
function(evt) {
delete popups[this.id];
this.hide();
OpenLayers.Event.stop(evt);
}
);
popup.autoSize = true;
popup.useInlineStyles = false;
popups[popupId] = popup;
feature.layer.map.addPopup(popup, true);
}
popup.setContentHTML(popup.contentHTML + text);
popup.show();
}
fwiw I finally came back to this and did something entirely different, but his answer was a good one.
//I have a list of boxes that contain the information on the map (think google maps)
$('.paginatedItem').live('mouseenter', onFeatureSelected).live('mouseleave',onFeatureUnselected);
function onFeatureSelected(event) {
// I stuff the lookup attribute (I'm lazy) into a global
// a global, because there can be only one
hoveredItem = $(this).attr('lookup');
/* Do something here to indicate the onhover */
// find the layer pagination id
var feature = findFeatureById(hoveredItem);
if (feature) {
// use the pagination id to find the event, and then trigger the click for that event to show the popup
// also, pass a null event, since we don't necessarily have one.
feature.marker.events.listeners.click[0].func.call(feature, event)
}
}
function onFeatureUnselected(event) {
/* Do something here to indicate the onhover */
// find the layer pagination id
var feature = findFeatureById(hoveredItem);
if (feature) {
// use the pagination id to find the event, and then trigger the click for that event to show the popup
// also, pass a null event, since we don't necessarily have one.
feature.marker.events.listeners.click[0].func.call(feature, event)
}
/* Do something here to stop the indication of the onhover */
hoveredItem = null;
}
function findFeatureById(featureId) {
for (var key in map.layers) {
var layer = map.layers[key];
if (layer.hasOwnProperty('features')) {
for (var key1 in layer.features) {
var feature = layer.features[key1];
if (feature.hasOwnProperty('id') && feature.id == featureId) {
return feature;
}
}
}
}
return null;
}
also note that I keep map as a global so I don't have to reacquire it everytime I want to use it

How to handle calling a function without oEvent

I have a CheckBox with a handler attached to the select event. In this function is the code to dynamically populate/ display few fields. If I come on the screen and the data brings in a value which makes the checkbox selected already, then those fields are not displayed (because they become visible only when I select the checkbox).
I want to ensure that if the CheckBox is auto selected, still I should be able to process the logic in the function, which has oEvent as an input parameter. But the issue is that if I call this function from another method, that function does not work as it has many statements like oEvent().getSource() which I do not pass.
Controller.js
onCheckBoxSelect: function(oEvent) {
var cells = sap.ui.getCore().byId("cell");
controlCell.destroyContent();
vc.abc();
var material= sap.ui.getCore().byId("abc");
var isSelected = oEvent.getParameters("selected").selected;
if (isSelected) {
// ...
}
},
someFunction : function(){
if(true){
// want to call onCheckBoxSelect here
}
// ...
},
If you assign an ID to your checkbox, you can get the checkbox in any function you want as long as it is known in the view. By doing that you won't need the oEvent which is only available when an event on the checkbox is executed.
Example:
var cb = this.byId('checkboxId');
if(cb.getProperty('selected')) {
// execute code
} else {
// do something else
}
Decouple the handler body into a separate function so that other functions can call the decoupled function with the right arguments. For example:
Controller
onCheckBoxSelect: function(oEvent) {
const bSelected = oEvent.getParameter("selected");
this.doIt(bSelected); // Instead of "doing it" all here
},
someFunction: function(){
if (/*Something truthy*/) {
const checkBox = this.byId("myCheckBox");
const bSelected = checkBox.getSelected();
doIt(bSelected); // passing the same argument as in onCheckBoxSelect
}
// ...
},
doIt: function(bSelected) { // decoupled from onCheckBoxSelect
// ...
if (bSelected) {
// ...
}
},
View
<CheckBox id="myCheckBox"
select=".onCheckBoxSelect"
/>
Or since 1.56:
<CheckBox id="myCheckBox"
select=".doIt(${$parameters>/selected})"
/>
Docu: Handling Events in XML Views
By that, you can have a pure, decoupled function that can be called from anywhere.
I would suggest a different approach. Use the same property that you have used in your checkbox binding, to determine the visibility of the other fields, i.e. bind the visible property of each relevant field to that property in your model.
If there is additional post-processing required in populating the fields, you can either use expression binding or custom formatter for field-specific processing, or model binding events if you need to do a bit more "staging" work (in which case you would probably store the resultant data in a client model and bind to that for populating your fields).