I am hosting a WebBrowser control in a Windows 7 WPF application.
Now I am having a problem with the javascript running within this browser. The DOM pointer events are not firing. When I click a DOM object, the mousedown and click events fire, but the pointerdown event does not fire, even though it fires when viewing the same page in Internet Explorer 11.
How can I make the DOM pointerdown events fire?
Here's what I see in the browser:
Here's what I see in the WPF application:
Here's the HTML document I'm testing with:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=11">
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
<title>Raw test page</title>
<style type="text/css">
#mouseTarget{
border: 2px solid purple;
background: steelblue;
font-weight: bold;
width: 300px;
height: 100px;
}
</style>
</head>
<body>
<div id="mouseTarget">Mouse Target</div>
<div id="logOutput"></div>
<script type="text/javascript">
var logOutput = function (text) {
$("<div></div>").text(text).appendTo($("#logOutput"));
};
var mouseTarget = document.getElementById('mouseTarget');
mouseTarget.addEventListener('pointerdown', function () {
logOutput('pointerdown event received');
}, false);
mouseTarget.addEventListener('mousedown', function () {
logOutput('mousedown event received');
}, false);
mouseTarget.addEventListener('click', function () {
logOutput('click event received');
}, false);
</script>
</body>
</html>
EDIT: Sorry it seems the setting isn't enough to FIRE the pointer events. Its just recognizing touch events but still only firing the mouse events. Very annoying...
The problem is that WebBrowser control isn't acting like a usual IE instance. First of all its using a legacy fallback IE7 mode by default. Other points are a legacy input model and some more.
I personally had the issue to set the browserMode to IE10 but pointer events where not working at all. The issue was, that the WebBrowser control pretended to support PointerEvents which I subscribed but due to an enabled legacy input model these were'nt fired.
You can set these policies dynamically from within you application for just that application :
private void SetBrowserCompatibilityMode()
{
// http://msdn.microsoft.com/en-us/library/ee330720(v=vs.85).aspx
// FeatureControl settings are per-process
var fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
if (String.Compare(fileName, "devenv.exe", true) == 0) // make sure we're not running inside Visual Studio
return;
using (var key = Registry.CurrentUser.CreateSubKey(#"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION",
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
// Webpages containing standards-based !DOCTYPE directives are displayed in IE10 Standards mode.
UInt32 mode = 10000; // 10000; or 11000 if IE11 is explicitly supported as well
key.SetValue(fileName, mode, RegistryValueKind.DWord);
}
using (var key = Registry.CurrentUser.CreateSubKey(#"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_NINPUT_LEGACYMODE",
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
// disable Legacy Input Model
UInt32 mode = 0;
key.SetValue(fileName, mode, RegistryValueKind.DWord);
}
}
Refer to: C# WebBrowser PanningMode
Related
I want to get array of currently visible clusters and then get each point data. I create method in React and it seems that method in theme for getClusterPresentation returns all possible clusters for all map zooms. How to get clusters data? This is my code:
const dataPoints = points.map(
point => new H.clustering.DataPoint(point.lat, point.lng, undefined, point),
);
const clusteredDataProvider = new H.clustering.Provider(dataPoints, {
clusteringOptions: {
eps: 32,
minWeight: 2,
},
});
const defaultTheme = clusteredDataProvider.getTheme();
clusteredDataProvider.setTheme({
getClusterPresentation: cluster => {
const clusterMarker = defaultTheme.getClusterPresentation(cluster);
return clusterMarker;
},
getNoisePresentation: noisePoint => {},
});
const layer = new H.map.layer.ObjectLayer(clusteredDataProvider);
map.addLayer(layer);
Please check the below code related to Marker Clustering. And you check same example in our Guide
/**
* Display clustered markers on a map
*
* Note that the maps clustering module https://js.api.here.com/v3/3.1/mapsjs-clustering.js
* must be loaded to use the Clustering
* #param {H.Map} map A HERE Map instance within the application
* #param {Object[]} data Raw data that contains airports' coordinates
*/
function startClustering(map, data) {
// First we need to create an array of DataPoint objects,
// for the ClusterProvider
var dataPoints = data.map(function (item) {
return new H.clustering.DataPoint(item.latitude, item.longitude);
});
// Create a clustering provider with custom options for clusterizing the input
var clusteredDataProvider = new H.clustering.Provider(dataPoints, {
clusteringOptions: {
// Maximum radius of the neighbourhood
eps: 32,
// minimum weight of points required to form a cluster
minWeight: 2
}
});
// Create a layer tha will consume objects from our clustering provider
var clusteringLayer = new H.map.layer.ObjectLayer(clusteredDataProvider);
// To make objects from clustering provder visible,
// we need to add our layer to the map
map.addLayer(clusteringLayer);
}
/**
* Boilerplate map initialization code starts below:
*/
// Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
// Step 2: initialize a map
var map = new H.Map(document.getElementById('map'), defaultLayers.vector.normal.map, {
center: new H.geo.Point(30.789, 33.790),
zoom: 2,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
// Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Step 4: create the default UI component, for displaying bubbles
var ui = H.ui.UI.createDefault(map, defaultLayers);
// Step 5: cluster data about airports's coordinates
// airports variable was injected at the page load
startClustering(map, airports);
#map {
width: 95%;
height: 450px;
background: grey;
}
#panel {
width: 100%;
height: 400px;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Marker Clustering</title>
<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
<link rel="stylesheet" type="text/css" href="demo.css" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<link rel="stylesheet" type="text/css" href="../template.css" />
<script type="text/javascript" src='../test-credentials.js'></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-clustering.js"></script>
<script type="text/javascript" src="./data/airports.js"></script>
</head>
<body id="markers-on-the-map">
<div class="page-header">
<h1>Marker Clustering</h1>
<p>Cluster multiple markers together to better visualize the data</p>
</div>
<p>This example displays a map showing the distribution of
airports across the world. The locations were obtained by using
the OpenFlights Airport Database.
Instead of adding a marker for each location, the data has been clustered,
and individual airports are only shown at higher zoom levels.</p>
<div id="map"></div>
<h3>Code</h3>
<p>Marker clustering requires the presence of the <code>mapsjs-clustering</code> module of the API.
The <code>H.clustering.Provider</code> class is used to load in data points and prepare them for clustering.
The result is added to the map as an additional layer using the <code>map.addLayer()</code> method.</p>
<script type="text/javascript" src='demo.js'></script>
</body>
</html>
I am generating an HTML/Javascript file from an Access365 database which plots pins on a Bing Map. Each of the pins has associated metadata about the location it is pinning which is viewed by clicking the pin. However, there can be pins which are at exactly the same location (lat and long) and only the metadata for the top pin is available.
How do I either show the combined metadata or have the pins move apart a bit say when the the user mouses over them? Does anyone know how to do that? I've gone round in circles looking at the MS documentation and can't find anything to help.
P.S. There is also a clusterLayer. If that needs removing to solve the problem that's Ok but it would be better if it could stay.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<!-- Reference to the Bing Maps SDK -->
<script type='text/javascript'
src='http://www.bing.com/api/maps/mapcontrol?callback=GetMap&key=[zzz]'
async defer></script>
<script type='text/javascript'>
function GetMap()
{
var map = new Microsoft.Maps.Map('#myMap', {center: new Microsoft.Maps.Location(53.50632, -7.2714), zoom:8});
var ourBlue = 'rgb(108, 162, 212)';
//Create an infobox at the center of the map but don't show it.
infobox = new Microsoft.Maps.Infobox(map.getCenter(), {
visible: false
});
//Assign the infobox to a map instance.
infobox.setMap(map);
var theLocations = [3];
var thePins = [3];
theLocations[0] = new Microsoft.Maps.Location(53.41, -7.1);
theLocations[1] = new Microsoft.Maps.Location(53.42, -7.1);
theLocations[2] = new Microsoft.Maps.Location(53.43, -7.1);
for (var i = 0; i < theLocations.length; i++){
var pin = new Microsoft.Maps.Pushpin(theLocations[i]);
pin.metadata = {
title: 'Pin ' + i, description: 'Description for pin' + i
};
Microsoft.Maps.Events.addHandler(pin, 'click', pushpinClicked);
Microsoft.Maps.Events.addHandler(pin, 'mouseover', splitOverlap);
Microsoft.Maps.Events.addHandler(pin, 'mouseout', function (e) {
e.target.setOptions({ color:'purple' });
});
thePins[i] = pin; //add pin to array of pins
}
Microsoft.Maps.loadModule("Microsoft.Maps.Clustering", function(){
clusterLayer = new Microsoft.Maps.ClusterLayer(thePins);
map.layers.insert(clusterLayer);
});
}
function splitOverlap(e) {
var ourBlue = 'rgb(108, 162, 212)';
e.target.setOptions({color:ourBlue});
}
}
function pushpinClicked(e) {
//Make sure the infobox has metadata to display.
if (e.target.metadata) {
//Set the infobox options with the metadata of the pushpin.
infobox.setOptions({
location: e.target.getLocation(),
title: e.target.metadata.title,
description: e.target.metadata.description,
visible: true
});
}
}
</script>
<script type='text/javascript' src='http://www.bing.com/api/maps/mapcontrol?callback=GetMap&key=Arvr3LDJsmNB-2OGHl_egpbP9RbwsYKGKrktnPBC06G38T9q3CzsfmwK6GNoW7R_' async defer></script>
</head>
<body>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
</body>
</html>
When you have clusters and you want to see individual metadate for items within the cluster there are two common approaches:
Have a popup that shows the first location metadata and buttons to step/page/tab through each item in the cluster.
Use the spider cluster visualization: https://bingmapsv8samples.azurewebsites.net/#Clustering_SpiderClusters
following up on
https://stackoverflow.com/questions/27975991/neptune-theme-buttons-unreadable- with-light-grey-backgrounds-on-visualforce-page
The sf css extended.css is loading after neptune.css and therefore overriding neptune for body button, body .x-btn etc.
I found this:
https://salesforce.stackexchange.com/questions/24575/how-to-ignore-salesforce-css-on-vf-page-with-header
in which the first answer with the jQuery link seems to be the most elegant. However I need help on this -
$("head").append("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'"); and
$("head link[rel='stylesheet']").last().after("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'");
are standard html css, not the sf way of
apex:stylesheet value="{!URLFOR($Resource.ExtJS42, '/ExtJS42/resources/ext-theme-neptune-all.css')}"
How is Bob Buzzard implementing this in apex-speak? tia.
removed the "<>" out of above code to get it to display
The code snippets that you have posted, e.g.
$("head").append("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'");
are JavaScript that relies on the JQuery library being present, so you'd actually need something like the following:
At the top of the file include jQuery - this is from a CDN, but you might want it as a static resource:
<apex:includescript value="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js" />
Then in the body
<script>
$(document).ready(function(){
$("head").append("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'");
});
</script>
putting this inside the ready handler means it will run as soon as the page is loaded.
<script type="text/javascript" >
j$ = jQuery.noConflict();
j$(document).ready(function() {
var stylesheet = document.styleSheets[(document.styleSheets.length - 1)];
for( var i in document.styleSheets ){
if( document.styleSheets[i].href && document.styleSheets[i].href.indexOf("extended.css")>0 ) {
stylesheet = document.styleSheets[i];
stylesheet.id = "cmnSheet"; // id would allow dynamic mods?
stylesheet.disabled = true;
break;
}
};
});
extjs css is loaded in apex page tag with
'<'apex:stylesheet value="{!URLFOR($Resource.ExtJS42, '/ExtJS42/resources/ext-theme-neptune-all.css')}" /'>'
(typing jQuery stuff from memory and notes so will correct later if needed but concept is there)
First of all, I always say the same: sorry about my english is very weak. I hope you can understand me well.
I need to notify an user when he tries to close a tab or close the browser.
Is there any way to fire an event to avoid the browser will be closed?
The application is made in silverlight.
Thanks in advance.
Take a look at the following example, there is also a sample application:
http://www.blog.jonnycornwell.com/2011/01/23/using-silverlight-and-javascript-to-prevent-leaving-a-webpage/
It's about using Silverlight and JavaScript to prevent leaving a webpage.
The javascript:
<script language="javascript" type="text/javascript">
window.onbeforeunload = askConfirm;
function askConfirm() {
var control = document.getElementById("silverlightControl");
var preventLeave = control.Content.Page.PreventLeave();
if (!preventLeave) {
return;
}
var message = control.Content.Page.LeaveRequested();
return message;
}
</script>
The silverlight code:
public MainPage()
{
InitializeComponent();
HtmlPage.RegisterScriptableObject("Page", this);
}
[ScriptableMember]
public string LeaveRequested()
{
return "You have unsaved changes to your current document?";
}
[ScriptableMember]
public bool PreventLeave()
{
return (bool)PreventLeaveCheckBox.IsChecked;
}
This can be done easily with javascript. For example:
<html>
<head>
<script type="text/javascript">
<!--
function closeIt(url,name)
{
return "Hi there! I'm a message!";
}
window.onbeforeunload = closeIt;
// -->
</script>
</head>
<body>
<p>I'm a webpage!</p>
</body>
</html>
I am looking at creating an event and reservation system.
I found the Stack Overflow question jQuery - Mobile date picker control which shows jquery-mobile-datebox and jQuery-Mobile-Themed-DatePicker.
I want to display a calendar where certain dates I get from the server are
available
not available
reserved
When a reserved or available date is touched, I want to show times - there can be more than one time per day. The user can then click on a time to reserve it which would hit off an Ajax request.
jQuery UI datepicker, for example, has
onSelect: function(date, inst) {
From what I can see in the above pickers, what I need is not readily available. Before I start hacking them myself:
Which one would lend itself best to what I want?
Are there perhaps better ones out there that already serve my needs?
UPDATE:
Firebug gave me
<div class="ui-datebox-griddate ui-corner-all ui-btn-up-e" data-date="25" data-theme="e">25</div>
where ui-btn-up-e can be changed from a - e.
Now I need to find out if data-theme also needs to be changed
$('.ui-datebox-griddate').click(function () {
alert($(this).attr("class"));
}
What is the nicest way to toggle through three of the classes and save the state each time?
$('.ui-datebox-griddate').toggle(
function () {
$(this).????? // change ui-btn-up-? to ui-btn-up-a
$.get(...)
},
function () {
$(this).????? // change ui-btn-up-a to ui-btn-up-b
$.get(...)
},
function () {
$(this).????? // change ui-btn-up-b to ui-btn-up-c
$.get(...)
}
);
UPDATE: NOTE: When I click, the calendar change the date, reloading the calendar completely. Perhaps I need to stop that :(
What is the nicest way to toggle through three of the classes and save the state each time?
Something like:
$('.ui-datebox-griddate').click(function (e) {
var $this = $(this);
var cycle = ["ui-btn-up-a", "ui-btn-up-b", "ui-btn-up-c"];
if (typeof $this.data("ui-btn-cycle") == "undefined" ) {
this.className = this.className.replace(/ui-btn-up-./, cycle[0]);
$this.data("ui-btn-cycle", cycle[0]);
}
for (var i=0; i<cycle.length; i++) {
if ( $this.hasClass(cycle[i]) ) {
$this.removeClass(cycle[i]).addClass(cycle[i % cycle.length]);
$this.data("ui-btn-cycle", [i % cycle.length]);
break;
}
}
$.get( ... );
e.preventDefault() // stop default click behaviour
});
This can cycle though an arbitrary amount of classes. The current state would be available through calling .data("ui-btn-cycle") on the respective element.
This is even nicer:
$('.ui-datebox-griddate')
.each(function () {
var cycle = ["ui-btn-up-a", "ui-btn-up-b", "ui-btn-up-c"];
$(this).data("ui-btn-cycle", cycle);
this.className = this.className.replace(/ui-btn-up-./, cycle[0]);
})
.click(function (e) {
var cycle = $(this).data("ui-btn-cycle");
$(this).removeClass(cycle[0]).addClass(cycle[1]);
cycle.push(cycle.shift());
e.preventDefault();
});
The current state would always be .data("ui-btn-cycle")[0] on the respective element. See it working here: http://jsfiddle.net/Tomalak/mAH4n/
Based on what J.T.Sage said I thought I would have a play with jQuery Mobile Calendar. I think I have something which could potentially be extended to fulfil your requirements. I am not sure to what extent multi-colour themeing would be possible (without extensive modifications).
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQueryMobile - DateBox Demos</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
<link type="text/css" href="http://dev.jtsage.com/cdn/datebox/latest/jquery.mobile.datebox.min.css" rel="stylesheet" />
<!-- NOTE: Script load order is significant! -->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
<script type="text/javascript">
$( document ).bind( "mobileinit", function(){ $.mobile.page.prototype.options.degradeInputs.date = 'text'; });
</script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
<script type="text/javascript" src="http://dev.jtsage.com/cdn/datebox/latest/jquery.mobile.datebox.min.js"></script>
<script type="text/javascript">
$('#page').live('pagecreate', function(event) {
$('#mydate').bind('change', function () {
alert($(this).val());
});
});
</script>
</head>
<body>
<div id="page" data-role="page">
<div data-role="content">
<input name="mydate" id="mydate" type="date" data-role="datebox" data-options='{"mode": "calbox", "calHighToday": false, "calHighPicked": false, "useInline": true, "useInlineHideInput": true, "highDates": ["2011-06-25", "2011-06-27", "2011-07-04"]}'></input>
</div>
</div>
</html>
UPDATE
I suppose the highDates mechanism could be bypassed completely and the individual days uniquely targeted. The plugin maintains a JavaScript Date object of the last date selected (or today if nothing has been selected) - so it should be possible to get the current month and iterate through all your matching data updating the matching days in the current month as appropriate (e.g. replacing the setColours method below with something that is data/state aware).
<script type="text/javascript">
$('#page').live('pagecreate', function(event) {
$('#mydate').bind('change', function () {
//alert($(this).val());
alert($('#mydate').data('datebox').theDate);
});
setColours();
$('#mydate').bind('datebox', function (e, pressed) {
setColours();
});
$('.ui-datebox-gridplus, .ui-datebox-gridminus').bind('vclick', function(){
// To handle changing months
setColours();
//alert($('#mydate').data('datebox').theDate);
});
function setColours(){
$('div.ui-datebox-griddate[data-date=25][data-theme]').css({"background-color":"red", "background-image":"none", "color" : "white"});
$('div.ui-datebox-griddate[data-date=26][data-theme]').css({"background-color":"green", "background-image":"none", "color" : "white"});
$('div.ui-datebox-griddate[data-date=27][data-theme]').css({"background-color":"blue", "background-image":"none", "color" : "white"});
}
});
</script>