Extending sap.ui.core.Icon with hover event or mouseover - hover

I extended sap.ui.core.Icon with hover event handling:
sap.ui.define(function () {
"use strict";
return sap.ui.core.Icon.extend("abc.reuseController.HoverIcon", {
metadata: {
events: {
"hover" : {}
}
},
// the hover event handler, it is called when the Button is hovered - no event registration required
onmouseover : function(evt) {
this.fireHover();
},
// add nothing, just inherit the ButtonRenderer as is
renderer: {}
});
});
The event onmouseover is never fired. I also used this extension for sap.m.Button and it works. But I need this for sap.ui.core.Icon.
I also tried this jquery example but it did not work at all.
$("testIcon").hover(function(oEvent){alert("Button" + oEvent.getSource().getId());});
Please, do you have any idea why event handler onmouseover is not called for sap.ui.core.Icon? Or can you propose some other solution?
Bellow is how I added icon to my sap.suite.ui.commons.ChartContainer:
var oFilterIcon = new HoverIcon({
tooltip : "{i18n>filter}",
src : "sap-icon://filter",
hover : function(oEvent){alert("Button" + oEvent.getSource().getId());},
});
this.byId("idChartContainer").addCustomIcon(oFilterIcon);

This is my analysis:
Your new custom Control Icon for hover is correct. If you will use it independently it will work correctly .
However, your custom control will not work as your icons are converted to sap.m.OverflowToolbarButton when you use ChartContainer.
I looked into the source code of Chart Container and below is the code:
sap.suite.ui.commons.ChartContainer.prototype._addButtonToCustomIcons = function(i) {
var I = i;
var s = I.getTooltip();
var b = new sap.m.OverflowToolbarButton({
icon: I.getSrc(),
text: s,
tooltip: s,
type: sap.m.ButtonType.Transparent,
width: "3rem",
press: [{
icon: I
}, this._onOverflowToolbarButtonPress.bind(this)]
});
this._aCustomIcons.push(b);
}
So, you Icon is not used but its properties are used. As this is standard code, your hover code of Custom icon is not passed along.
One solution will be to add the onmouseover to sap.m.OverflowToolbarButton :
sap.m.OverflowToolbarButton.prototype.onmouseover=function() {
alert('hey')
};
However, this is dangerous as all OverflowToolbarButton button start using this code and I will not recommend it.
Next solution would be to overwrite the private method:_addButtonToCustomIcons ( again not recommendred :( )
sap.suite.ui.commons.ChartContainer.prototype._addButtonToCustomIcons = function(icon) {
var oIcon = icon;
var sIconTooltip = oIcon.getTooltip();
var oButton = new sap.m.OverflowToolbarButton({
icon : oIcon.getSrc(),
text : sIconTooltip,
tooltip : sIconTooltip,
type : sap.m.ButtonType.Transparent,
width : "3rem",
press: [{icon: oIcon}, this._onOverflowToolbarButtonPress.bind(this)]
});
this._aCustomIcons.push(oButton);
//oButton.onmouseover.
oButton.onmouseover = function() {
this.fireHover();
}.bind(oIcon);
};
Let me know if this helps u. :)

Related

TAU: How do we use the PageIndicator for Wearable Devices

I am trying the Page Indicator in Tizen Wearable Application for Gear S3 Frontier. When I use the code pasted there, It works fine for text only. E.g. when I try to add controls on each section (being shown as page on the screen) It doesn't work. Even if I set a background image the whole design gets scattered. I've tried some approaches, including the answer given on this question
My Output:
HTML Code:
Page1 of 2
Page2 of 2
CSS:
.ui-content section {
overflow: hidden;
overflow-y: auto;
text-align: center;
}
JavaScript:
/*global tau */
(function() {
var page = document.getElementById("taskListPage"),
changer = document.getElementById("hsectionchanger"),
sections = document.querySelectorAll("section"),
sectionChanger,
elPageIndicator = document.getElementById("pageIndicator"),
pageIndicator,
pageIndicatorHandler;
/**
* pagebeforeshow event handler
* Do preparatory works and adds event listeners
*/
page.addEventListener( "pagebeforeshow", function() {
// make PageIndicator
pageIndicator = tau.widget.PageIndicator(elPageIndicator, { numberOfPages: sections.length });
pageIndicator.setActive(0);
// make SectionChanger object
sectionChanger = new tau.widget.SectionChanger(changer, {
circular: true,
orientation: "horizontal",
useBouncingEffect: true
});
});
/**
* pagehide event handler
* Destroys and removes event listeners
*/
page.addEventListener( "pagehide", function() {
// release object
sectionChanger.destroy();
pageIndicator.destroy();
});
/**
* sectionchange event handler
*/
pageIndicatorHandler = function (e) {
pageIndicator.setActive(e.detail.active);
};
changer.addEventListener("sectionchange", pageIndicatorHandler, false);
}());
I am facing an error as well:
file:///lib/tau/wearable/js/tau.min.js (20) :[tau][10/24/2019, 1:28:31
The HTML code is not attached. Basing on the screens I assume that your application has two sections. The SectionChanger widget with "circular" option can be build only with apps that contain at least 3 sections, hence the error in console.
Please change the circular option for section changer to false:
page.addEventListener( "pagebeforeshow", function() {
// make PageIndicator
pageIndicator = tau.widget.PageIndicator(elPageIndicator, { numberOfPages: sections.length });
pageIndicator.setActive(0);
// make SectionChanger object
sectionChanger = new tau.widget.SectionChanger(changer, {
circular: true,
orientation: "horizontal",
useBouncingEffect: true
});
});
into:
page.addEventListener( "pagebeforeshow", function() {
// make PageIndicator
pageIndicator = tau.widget.PageIndicator(elPageIndicator, { numberOfPages: sections.length });
pageIndicator.setActive(0);
// make SectionChanger object
sectionChanger = new tau.widget.SectionChanger(changer, {
circular: false,
orientation: "horizontal",
useBouncingEffect: true
});
});
This option is responsible for switching between sections mode. If it's set to true user can move from first section to the last one and vice versa.

Hide and Unhide text using popper.js

I have the following popper.js script and I want that when I click a button a text appears and when I click the button again the text disappears. The script shown only unhide the text.
var ref = $('#button-a');
var popup = $('#popup');
popup.hide();
ref.click(function(){
popup.show();
var popper = new Popper(ref,popup,{
placement: 'bottom',
onCreate: function(data){
console.log(data);
},
modifiers: {
flip: {
behavior: ['bottom']
},
offset: {
enabled: true,
offset: '0,10'
}
}
});
});
Your event handler is never calling .hide() (I assume these are the JQuery show and hide functions?). You either need to use .toggle() instead of .show() or set up a conditional that handles the case where the popup is already visible and calls .hide().

Point click callback of Dygraph not working in Polymer Shadow DOM

I am creating a Ploymer custom component and using Dygraph to creat a chart. I have added a pointClickCallback for the same.
But, when the chart is inside the shadow dom pointClickcallback is not working at all. Although, when I put the chart outside the custom component i.e. in the index.html, the pointClickCallback is working fine.
EDIT : highlightCallback is working properly inside shadow dom, not the pointClickCallback
Can any one tell me what might be the problem.
UPDATE
I am not sure whether this is right way of doing it but, please suggest. I am doing like below and it works for me
var self = this; // 'this' is not the window object
self.pts = null;
var g = new Dygraph(
this.$.div_g,
NoisyData, {
rollPeriod: 7,
showRoller: true,
errorBars: true,
highlightCallback: function(e, x, pts, row) {
console.log("highlightCallback --> self.pts", self.pts);
console.log("highlightCallback", pts);
self.pts = pts;
console.log("highlightCallback --> self.pts", self.pts);
},
interactionModel : {
'click' : function(e) {
console.log("click", e, self.pts);
}
},
}
);
The pointClickCallback does not go into the interactionModel but is bascially on the same level as the highlightCallback.
So your code should look like this:
var g = new Dygraph(
this.$.div_g,
NoisyData, {
rollPeriod: 7,
showRoller: true,
errorBars: true,
highlightCallback: function(e, x, pts, row) {
console.log("highlightCallback --> self.pts", self.pts);
console.log("highlightCallback", pts);
self.pts = pts;
console.log("highlightCallback --> self.pts", self.pts);
},
pointClickCallback: function(e,pt) {
console.log('Point clicked');
},
interactionModel : {
'click' : function(e) {
console.log("click", e, self.pts);
}
},
}
);

draggable rows in a p:dataTable by handle

I have a DataTable in which I added drag and drop support for the rows (draggableRows="true"). The problem is that wherever I click inside a row, I can drag it.
What I want is the possibility to drag the row only by a handle, the handle could be a column field with an icon at the left of the row for example (have a look at the screenshot), so if the user clicks on a row outside of the handle, there's no drag support; but if he clicks on the handle, he'll have the possibility to drag the entire row.
How could I implement this?
The source is always with you. In there you can see the makeRowsDraggable function on line 2727 in datatable.js
makeRowsDraggable: function() {
var $this = this;
this.tbody.sortable({
placeholder: 'ui-datatable-rowordering ui-state-active',
cursor: 'move',
handle: 'td,span:not(.ui-c)',
appendTo: document.body,
start: function(event, ui) {
ui.helper.css('z-index', ++PrimeFaces.zindex);
},
...
}
with a reference to the handle ('td, span:not(.ui-c)').
By overriding this function and having the handle point to a selector that explicitly refers to your handle, you can 'fix' it.
You can even make this generic by not assigning an explict string to the handle, but but looking it up on e.g. a custom pass-through attribute you define on the datatable where you put the 'string' in.
Did I mention already that the source is always with you? Good thing to remember when having further questions
Since Primefaces 6.2 p:datatable has a property rowDragSelector specifically for this purpose. See the example below:
<p:dataTable value="#{myBean.entities}" id="myTablePreferredId" rowDragSelector=".draggableHandle" draggableRows="true">
<p:ajax event="rowReorder" listener="#{myBean.onRowReorder}"/>
<p:column>
<h:outputText styleClass="fa fa-arrows-v draggableHandle" />
</p:column>
...
</p:dataTable>
For more details refer to the primefaces documentation.
My solution is the same as the solution of #Kuketje.
Here is the source code (compatible with Primefaces 6.1)
if (PrimeFaces.widget.DataTable){
PrimeFaces.widget.DataTable = PrimeFaces.widget.DataTable.extend({
makeRowsDraggable: function () {
var $this = this,
draggableHandle = '.dnd-handle'; //change to what ever selector as you like
this.tbody.sortable({
placeholder: 'ui-datatable-rowordering ui-state-active',
cursor: 'move',
handle: draggableHandle,
appendTo: document.body,
start: function (event, ui) {
ui.helper.css('z-index', ++PrimeFaces.zindex);
},
helper: function (event, ui) {
var cells = ui.children(),
helper = $('<div class="ui-datatable ui-widget"><table><tbody></tbody></table></div>'),
helperRow = ui.clone(),
helperCells = helperRow.children();
for (var i = 0; i < helperCells.length; i++) {
helperCells.eq(i).width(cells.eq(i).width());
}
helperRow.appendTo(helper.find('tbody'));
return helper;
},
update: function (event, ui) {
var fromIndex = ui.item.data('ri'),
toIndex = $this.paginator ? $this.paginator.getFirst() + ui.item.index() : ui.item.index();
$this.syncRowParity();
var options = {
source: $this.id,
process: $this.id,
params: [
{name: $this.id + '_rowreorder', value: true},
{name: $this.id + '_fromIndex', value: fromIndex},
{name: $this.id + '_toIndex', value: toIndex},
{name: this.id + '_skipChildren', value: true}
]
}
if ($this.hasBehavior('rowReorder')) {
$this.cfg.behaviors['rowReorder'].call($this, options);
}
else {
PrimeFaces.ajax.Request.handle(options);
}
},
change: function (event, ui) {
if ($this.cfg.scrollable) {
PrimeFaces.scrollInView($this.scrollBody, ui.placeholder);
}
}
});
}
});
}
The solution from Vít Suchánek is not really working. It detects the drag&drop handle only when the page is ready. After the first drag&drop interaction, it is not going to work anymore.
Another possibility is to override Primefaces's setting of handler after initialization of UI sortable:
<script type="text/javascript">
$(document).ready(function() {
var sortableRows = $(".tableWithDraggableRows > tbody");
if (sortableRows) {
sortableRows.sortable("option", "handle", ".ui-icon-arrow-4");
}
});
</script>
See http://api.jqueryui.com/sortable/#option-handle

pass dom element from background script to chrome.tabs.executeScript

I'm trying to pass the active dom element when the contextmenu is clicked from my background script to a script that is being called through chrome.tabs.executeScript. I can pass booleans and strings just fine, but i always get an error when i pass dom elements. I'm starting to think it's not possible.
//doScripts function called from browser action
chrome.browserAction.onClicked.addListener(function(tab) {
doScripts(true, null);
});
//doScripts function called from context menu click
function getClickHandler(info, tab) {
var currTarg = document.activeElement;
console.log("currTarg = " + currTarg);
doScripts(false, currTarg);
}
//i reference doingBrowserAction and contextTarg in myscript.js
function doScripts(context, targ){
chrome.tabs.executeScript(null, {code: "var doingBrowserAction = "+context+"; var contextTarg = "+targ+";"}, function(){
chrome.tabs.executeScript(null, {file: "js/myscript.js"}, function(){
//all injected
});
});
}
//setup context menu
chrome.contextMenus.create({
"title" : "DESTROY!",
"type" : "normal",
"contexts" : ["page","selection","link","editable","image","video","audio"],
"onclick" : getClickHandler
});
i reference doingBrowserAction and contextTarg in myscript.js. I know what i'm trying to do is possible because the adblock extension does it, but having a hard time figuring out how. thanks in advance.
You cannot get a direct reference to a content script's DOM element from the background page, because the background page runs in the extension's process, and the content script runs in the tab's process. See also https://code.google.com/p/chromium/issues/detail?id=39507.
The document.activeElement property in the background page refers to the active element in the background page's document. As you can imagine, this value is quite useless.
If you query the state of the currently right-clicked element, bind an event in the content script. In the next example, I've chosen the contextmenu event, because context menus can also be opened through the keyboard.
This example adds a context menu option that removes the last active element from the document.
// content script
var lastElementContext;
document.addEventListener('contextmenu', function(event) {
lastElementContext = event.target;
}, true);
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (lastElementContext && lastElementContext.parentNode) {
lastElementContext.parentNode.removeChild(lastElementContext);
lastElementContext = null;
}
});
Background script:
chrome.contextMenus.create({
title: 'DESTROY!',
contexts: ['page', 'link', 'editable', 'image', 'video', 'audio'],
onclick: function(info, tab) {
chrome.tabs.sendMessage(tab.id, 'doDestroy');
}
});