android webview javascript bridge, why passed in string got resolved to the div element - android-webview

In webview code it calls into the loaded javascript, passing in the string for the html div element id `"module_1", <div id="module_1" class="module"></div>:
my_web_view.evaluateJavascript(
"javascript:sendHtmlMarkerLocation("module_1");", null)
and the javascript is to accepting a string for the div element id, and then lookup the div element and get its location:
function sendHtmlMarkerLocation( moduleElementId ) {
console.log('+++ enter sendHtmlMarkerLocation()'+moduleElementId+',
window.androidObj:'+window.androidObj);
var elm = null
var moduleId = moduleElementId
if (moduleElementId instanceof String) {
elm = document.getElementById(moduleElementId)
} else if (moduleElementId instanceof Element) { // how it changes to the div element ???
elm = moduleElementId
moduleId = elm.id
}
var _x = 0;
var _y = 0;
while( elm && !isNaN( elm.offsetLeft ) && !isNaN( elm.offsetTop ) ) {
_x += elm.offsetLeft - elm.scrollLeft;
_y += elm.offsetTop - elm.scrollTop;
elm = elm.offsetParent;
}
var width = getWindowWidth()
var height = getWindowHeight()
window.androidObj.sendLocationToAndroid(moduleId, _x, _y, width, height);
}
but it crashes since the passed in moduleElementId is not the string div id "module_1" anymore, instead it is resolved to the <div id="module_1" class="module"></div>.
the coresponding console.log is:
+++ enter sendHtmlMarkerLocation()[object HTMLDivElement], window.androidObj:function AndroidClass(){} # 48
How it is changed from string id to the <div> element?

Related

How to filter with multiple condition text input in Ag-Grid?

Using ag-grid-enterprise v5.4.0
create multiple textFilter input ex: [CONTAINS] filterText AND [NOT CONTAIN] filterText2 just like Excel data analysis
but both filterType2 and filterText are undefined after click [APPLY FILTER]
https://embed.plnkr.co/4nAjGKmChqJiRcqz6E2n/
I believe what you are trying to do would be best achieved with the Filter Component. This allows you full control of the filter pain, whether you are in enterprise or not. Here are the required methods for each custom filter:
function CustomFilter() {}
CustomFilter.prototype.init = function (params) {
//Put any initial functions you need here (such as setting values to null)
};
CustomFilter.prototype.getGui = function () {
//return a string of HTML or a DOM element/node
};
CustomFilter.prototype.doesFilterPass = function (params) {
//Logic for your custom Filter
//return True if the row should display, false otherwise
};
CustomFilter.prototype.isFilterActive = function () {
//logic for displaying the filter icon in the header
};
CustomFilter.prototype.getModel = function() {
//store the filter state
};
CustomFilter.prototype.setModel = function(model) {
//restore the filter state here
};
Here is an example of how to implement an "Includes x but Excludes y" filter:
function DoubleFilter() {
}
DoubleFilter.prototype.init = function (params) {
this.valueGetter = params.valueGetter;
this.filterText = null;
this.setupGui(params);
};
// not called by ag-Grid, just for us to help setup
DoubleFilter.prototype.setupGui = function (params) {
this.gui = document.createElement('div');
this.gui.innerHTML =
'<div style="padding: 4px; width: 200px;">' +
'<div style="font-weight: bold;">Custom Athlete Filter</div>' +
'Include: <div><input style="margin: 4px 0px 4px 0px;" type="text" id="includesText" placeholder="Includes..."/></div>' +
'Exclude: <div><input style="margin: 4px 0px 4px 0px;" type="text" id="excludesText" placeholder="Excludes..."/></div>' +
'</div>';
// add listeners to both text fields
this.eIncludesText = this.gui.querySelector('#includesText');
this.eIncludesText.addEventListener("changed", listener);
this.eIncludesText.addEventListener("paste", listener);
this.eIncludesText.addEventListener("input", listener);
// IE doesn't fire changed for special keys (eg delete, backspace), so need to
// listen for this further ones
this.eIncludesText.addEventListener("keydown", listener);
this.eIncludesText.addEventListener("keyup", listener);
this.eExcludesText = this.gui.querySelector('#excludesText');
this.eExcludesText.addEventListener("changed", listener2);
this.eExcludesText.addEventListener("paste", listener2);
this.eExcludesText.addEventListener("input", listener2);
// IE doesn't fire changed for special keys (eg delete, backspace), so need to
// listen for this further ones
this.eExcludesText.addEventListener("keydown", listener2);
this.eExcludesText.addEventListener("keyup", listener2);
var that = this;
function listener(event) {
that.includesText = event.target.value;
params.filterChangedCallback();
}
function listener2(event) {
that.excludesText = event.target.value;
params.filterChangedCallback();
}
};
DoubleFilter.prototype.getGui = function () {
return this.gui;
};
DoubleFilter.prototype.doesFilterPass = function (params) {
var passed = true;
var valueGetter = this.valueGetter;
var include = this.includesText;
var exclude = this.excludesText;
var value = valueGetter(params).toString().toLowerCase();
return value.indexOf(include) >= 0 && (value.indexOf(exclude) < 0 || exclude == '') ;
};
DoubleFilter.prototype.isFilterActive = function () {
return (this.includesText !== null && this.includesText !== undefined && this.includesText !== '')
|| (this.excludesText !== null && this.excludesText !== undefined && this.excludesText !== '');
};
DoubleFilter.prototype.getModel = function() {
var model = {
includes: this.includesText.value,
excludes: this.excludesText.value
};
return model;
};
DoubleFilter.prototype.setModel = function(model) {
this.eIncludesText.value = model.includes;
this.eExcludesText.value = model.excludes;
};
Here is a modified plunker. I placed the filter just on the Athlete column, but the DoubleFilter can be applied to any column once it is created.
EDIT:
I realized you were asking for a rather generic double filter in your question with "Includes and Excludes" as an example. Here is a plunker that has a more generic double filter.
ag-Grid now supports this behavior, by default, in version 18.0.0.
https://www.ag-grid.com/ag-grid-changelog/?fixVersion=18.0.0

Chart.js click on labels, using bar chart

i need help with my Chart.js interactivity. When I click on the label, I need to return the column(index) number at which I clicked.
I tried to use getElementsAtEvent but it only work if I click directly at chart.
This http://jsfiddle.net/yxz2sjam/ is pretty much what I am looking for but getPointsAtEvent is no longer available in the new versions.
canvas.onclick = function (evt) {
var points = chart.getPointsAtEvent(evt);
alert(chart.datasets[0].points.indexOf(points[0]));
};
I also found this http://jsfiddle.net/1Lngmtz7/ but it isn't working with bar chart.
var ctx = document.getElementById("myChart").getContext("2d");
var myRadarChart = new Chart(ctx, {
type: 'radar',
data: data
})
$('#myChart').click(function (e) {
var helpers = Chart.helpers;
var eventPosition = helpers.getRelativePosition(e, myRadarChart.chart);
var mouseX = eventPosition.x;
var mouseY = eventPosition.y;
var activePoints = [];
helpers.each(myRadarChart.scale.ticks, function (label, index) {
for (var i = this.getValueCount() - 1; i >= 0; i--) {
var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5);
var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize);
var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle);
var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily);
var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
ctx.font = pointLabeFont;
var labelsCount = this.pointLabels.length,
halfLabelsCount = this.pointLabels.length / 2,
quarterLabelsCount = halfLabelsCount / 2,
upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
var width = ctx.measureText(this.pointLabels[i]).width;
var height = pointLabelFontSize;
var x, y;
if (i === 0 || i === halfLabelsCount)
x = pointLabelPosition.x - width / 2;
else if (i < halfLabelsCount)
x = pointLabelPosition.x;
else
x = pointLabelPosition.x - width;
if (exactQuarter)
y = pointLabelPosition.y - height / 2;
else if (upperHalf)
y = pointLabelPosition.y - height;
else
y = pointLabelPosition.y
if ((mouseY >= y && mouseY <= y + height) && (mouseX >= x && mouseX <= x + width))
activePoints.push({ index: i, label: this.pointLabels[i] });
}
}, myRadarChart.scale);
var firstPoint = activePoints[0];
if (firstPoint !== undefined) {
alert(firstPoint.index + ': ' + firstPoint.label);
}
});
Thank for response.
I solve the problem with
document.getElementById("chart").onclick = function(e)
{
var activeElement = weatherMainChart.lastTooltipActive;
console.log(activeElement[0]._index);
};
this solution register clicks on chart and label, then I restricted it with e.layerY to register only clicks on label section.
document.getElementById("chart").onclick = function(e)
{
var activeElement = weatherMainChart.lastTooltipActive;
if(e.layerY > 843 && e.layerY < 866 && activeElement[0] !== undefined)
console.log(activeElement[0]._index);
};
If you add a click handler through the onClick option you can use the following code using the getElementsAtEventForMode() call:
function handleClick(evt) {
var col;
switch(chartType) {
case "horizontalBar":
this.getElementsAtEventForMode(evt, "y", 1).forEach(function(item) { col = item._index });
break;
case "bar":
this.getElementsAtEventForMode(evt, "x", 1).forEach(function(item) { col = item._index });
break;
}
if (!col) {
return;
}
alert("Column " + col + " was selected");
};
You'll probably need to add extra switch checks for other chart types but I'm sure you get the idea.
Using version 2.4.0, i created an onClick Event, and inside it
var activeIndex = localChart.tooltip._lastActive[0]._index;
var clickCoordinates = Chart.helpers.getRelativePosition(e, localChart.chart);
if (clickCoordinates.y >= 530) { //custom value, depends on chart style,size, etc
alert("clicked on " + localChart.data.labels[activeIndex]);
}
I Solved this problem with single or multiple label click you will be find using true/false
First you need to set your chartJs Id click
below code SessionChart = Your ChartJs ID e.g. ("myChart") I was replace it for my Id
document.getElementById("SessionChart").onclick = function (evt) {
var meta = SubscriberSessionChart.getDatasetMeta(0);
if (meta.$filler.chart.legend.legendItems[0].text.toLowerCase() "sessions")
{
if (meta.$filler.chart.legend.legendItems[0].hidden) {
sessionHidden = true;
}
}
}
here "sessions" = first label text
meta.$filler.chart.legend.legendItems[0].text.toLowerCase() = is your first label
from Array so you can get multiple label's click here true / false
if (meta.$filler.chart.legend.legendItems[0].hidden) = your label is not active then
you will get hidden true otherwise you will get false if not tick on label
by default label tick hidden is false in chart js

pressing tab select the text of a certain element in tinymce

HOW DO I ACHIEVE THE FOLLOWING?
[1st image] On Initiate: highlight title
[2nd image] Press Tab: highlight description
[3rd image] Press Tab: highlight content
Press Tab Again Goes back to highlight the title and goes on
below is the tinymce content:
<hr>
<div id='title'>
TITLE
</div>
<hr>
<div id='description'>
DESCRIPTION
</div>
<hr>
<div id='content'>
CONTENT
</div>
below is the current function i have of selecting the text.
// the problem is that it doesn't select the text but put the carret in the first part of the text
// looks like this (|*carret) --> |TITLE or |DESCRIPTION or |CONTENT
// id = #title, #description, #content
tinyMceSelectText = function (id) {
if ($('#id_of_tinymce_iframe').contents().find(id).length > 0) {
var $itemNode = $('#content_editor_ifr').contents().find(id);
var text = '';
var items = $itemNode.contents();
// clean up the span and other elements automatically inserted by tinymce
$.each(items, function (i, val) {
if ($(val).length == 0) {
return;
}
if ($(val).prop('nodeName') == 'BR') {
text += '<br/>';
} else {
var t = $(val).text();
text += t;
}
})
$itemNode.html(text);
var len = $itemNode.contents().length - 1;
var textNode = $itemNode.contents()[len];
start = (start === undefined) ? 0 : start;
end = (end === undefined) ? textNode.length : end;
var ed = tinyMCE.activeEditor;
var range = ed.selection.getRng(true);
start = (start === undefined)? 0 : start;
end = (start === undefined)? 0 : end;
try {
range.setStart(textNode, start);
range.setEnd(textNode, end);
range.collapse(true);
ed.selection.setRng(range);
//ed.selection.collapse(false); // added to put carret to the last part of the text
var items = $itemNode.contents();
} catch (err) {}
}
}

execCommand without a selection? (set font, size etc)

I can get my custom WYSIWYG editor to apply styling to selected text no problem:
pnlDocumentEditor_IFrame.document.execCommand(cmd, ui, opt)
.. but what I need to be able to do is allow the user to set a font, or font size, or bold etc so that text typed AFTER this command is issued will have that style applied.
Is this possible? All execCommands I've tried seem to only work on selected text.
Appling execCommand on certain element, WITHOUT selecting it with mouse, can be done with this function:
jsFiddle example
function execCommandOnElement(el, commandName, value) {
if (typeof value == "undefined") {
value = null;
}
if (typeof window.getSelection != "undefined") {
// Non-IE case
var sel = window.getSelection();
// Save the current selection
var savedRanges = [];
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
savedRanges[i] = sel.getRangeAt(i).cloneRange();
}
// Temporarily enable designMode so that
// document.execCommand() will work
document.designMode = "on";
// Select the element's content
sel = window.getSelection();
var range = document.createRange();
range.selectNodeContents(el);
sel.removeAllRanges();
sel.addRange(range);
// Execute the command
document.execCommand(commandName, false, value);
// Disable designMode
document.designMode = "off";
// Restore the previous selection
sel = window.getSelection();
sel.removeAllRanges();
for (var i = 0, len = savedRanges.length; i < len; ++i) {
sel.addRange(savedRanges[i]);
}
} else if (typeof document.body.createTextRange != "undefined") {
// IE case
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.execCommand(commandName, false, value);
}
}
And example usage:
var testDiv = document.getElementById("test");
execCommandOnElement(testDiv, "Bold");
execCommandOnElement(testDiv, "ForeColor", "red");
Source: set execcommand just for a div

Getting cursor position in a Textarea

I am trying to implement Autocomplete in a text area (similar to http://www.pengoworks.com/workshop/jquery/autocomplete.htm).
What I am trying to do is when a user enters a specific set of characters (say insert:) they will get an AJAX filled div with possible selectable matches.
In a regular text box, this is of course simple, but in a text area I need to be able to popup the div in the correct location on the screen based on the cursor.
Can anyone provide any direction?
Thanks,
-M
You can get the caret using document.selection.createRange(), and then examining it to reveal all the information you need (such as position). See those examples for more details.
Implementing an autocomplete in a text area is not that easy. I implemented a jquery plugin that does that, and i had to create a clone of the texarea to guess where the cursor is positioned inside the textarea.
Its working, but its not perfect.
You can check it out here: http://www.amirharel.com/2011/03/07/implementing-autocomplete-jquery-plugin-for-textarea/
I hope it helps.
function getCursor(nBox){
var cursorPos = 0;
if (document.selection){
nBox.focus();
var tmpRange = document.selection.createRange();
tmpRange.moveStart('character',-nBox.value.length);
cursorPos = tmpRange.text.length;
}
else{
if (nBox.selectionStart || nBox.selectionStart == '0'){
cursorPos = nBox.selectionStart;
}
}
return cursorPos;
}
function detectLine(nBox,lines){
var cursorPos = getCursor(nBox);
var z = 0; //Sum of characters in lines
var lineNumber = 1;
for (var i=1; i<=lines.length; i++){
z = sumLines(i)+i; // +i because cursorPos is taking in account endcharacters of each line.
if (z >= cursorPos){
lineNumber = i;
break;
}
}
return lineNumber;
function sumLines(arrayLevel){
sumLine = 0;
for (var k=0; k<arrayLevel; k++){
sumLine += lines[k].length;
}
return sumLine;
}
}
function detectWord(lineString, area, currentLine, linijeKoda){
function sumWords(arrayLevel){
var sumLine = 0;
for (var k=0; k<arrayLevel; k++){
sumLine += words[k].length;
}
return sumLine;
}
var cursorPos = getCursor(area);
var sumOfPrevChars =0;
for (var i=1; i<currentLine; i++){
sumOfPrevChars += linijeKoda[i].length;
}
var cursorLinePos = cursorPos - sumOfPrevChars;
var words = lineString.split(" ");
var word;
var y = 0;
for(var i=1; i<=words.length; i++){
y = sumWords(i) + i;
if(y >= cursorLinePos){
word = i;
break;
}
}
return word;
}
var area = document.getElementById("area");
var linijeKoda = area.value.split("\n");
var currentLine = detectLine(area,linijeKoda);
var lineString = linijeKoda[currentLine-1];
var activeWord = detectWord(lineString, area, currentLine, linijeKoda);
var words = lineString.split(" ");
if(words.length > 1){
var possibleString = words[activeWord-1];
}
else{
var possibleString = words[0];
}
That would do it ... :)
an ugly solution:
for ie: use document.selection...
for ff: use a pre behind textarea, paste text before cursor into it, put a marker html element after it (cursorPos), and get the cursor position via that marker element
Notes: | code is ugly, sorry for that | pre and textarea font must be the same | opacity is utilized for visualization | there is no autocomplete, just a cursor following div here (as you type inside textarea) (modify it based on your need)
<html>
<style>
pre.studentCodeColor{
position:absolute;
margin:0;
padding:0;
border:1px solid blue;
z-index:2;
}
textarea.studentCode{
position:relative;
margin:0;
padding:0;
border:1px solid silver;
z-index:3;
overflow:visible;
opacity:0.5;
filter:alpha(opacity=50);
}
</style>
hello world<br/>
how are you<br/>
<pre class="studentCodeColor" id="preBehindMyTextarea">
</pre>
<textarea id="myTextarea" class="studentCode" cols="100" rows="30" onkeyup="document.selection?ieTaKeyUp():taKeyUp();">
</textarea>
<div
style="width:100px;height:60px;position:absolute;border:1px solid red;background-color:yellow"
id="autoCompleteSelector">
autocomplete contents
</div>
<script>
var myTextarea = document.getElementById('myTextarea');
var preBehindMyTextarea = document.getElementById('preBehindMyTextarea');
var autoCompleteSelector = document.getElementById('autoCompleteSelector');
function ieTaKeyUp(){
var r = document.selection.createRange();
autoCompleteSelector.style.top = r.offsetTop;
autoCompleteSelector.style.left = r.offsetLeft;
}
function taKeyUp(){
taSelectionStart = myTextarea.selectionStart;
preBehindMyTextarea.innerHTML = myTextarea.value.substr(0,taSelectionStart)+'<span id="cursorPos">';
cp = document.getElementById('cursorPos');
leftTop = findPos(cp);
autoCompleteSelector.style.top = leftTop[1];
autoCompleteSelector.style.left = leftTop[0];
}
function findPos(obj) {
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
}
return [curleft,curtop];
}
//myTextarea.selectionStart
</script>
</html>