How to notify an user when he tries to close a tab or close the browser - silverlight

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>

Related

polymer 1.0 .. importing a catalog element with a custom element throws an error

Had created and used my custom polymer element which is a table. Now, I want to use the check box element from their catalog in my table.
However, I keep getting this error when I reference the check box html file in my index page:
DuplicateDefinitionError: a type with name 'dom-module' is already
registered
This is how I have created my custom element:
<!-- Imports polymer -->
<link rel="import" href="polymer/polymer.html">
<script src="underscore-min.js"></script>
<!-- Defines element markup -->
<dom-module id="custom-table" >
<template>
<style>
ul {list-style-type:none; display:block}
ul li {display:inline; float:left; padding:20px; width:1.5em; border-bottom:1px solid #eee}
</style>
<h2>{{title}}</h2>
<table id="dataTable">
<thead id="tableHead"></thead>
<tbody id="tableBody"></tbody>
</table>
</template>
</dom-module>
<!-- Registers custom element -->
<script>
Polymer({
is: 'custom-table',
// Fires when an instance of the element is created
created: function() {
},
// Fires when the local DOM has been fully prepared
ready: function() {
var context= this;
this.pageNo=0;
this.totalPages=0;
// set the default paging size:
if(this.page== null|| this.page==undefined)
this.page=10;
// delegate the change selection handler to the table body
this.$.tableBody.addEventListener("click",function(e){
if(e.target && e.target.nodeName == "INPUT") ;
{
context.changeSelection(e.target);
}
});
},
// Fires when the element was inserted into the document
attached: function() {},
// Fires when the element was removed from the document
detached: function() {},
// Fires when an attribute was added, removed, or updated
attributeChanged: function(name, type) {
alert("changed");
},
loadData: function(columns,data){
this.data = data;
// add the selected property to the values
for(var i=0;i<this.data.length; i++) { this.data[i].Selected = false;}
this.filteredData=this.data;
this.columns = columns;
//initialize the filteredData
this.filteredData=data;
// calculate the total number of pages
this.totalPages= Math.ceil(data.length/this.page);
this.drawTableHeader();
_.defer(this.applyFilters,this);
_.defer(this.drawTableBody,this);
},
drawTableHeader:function(){
var columns = this.columns;
// load the header
var headTr = document.createElement('tr');
//add a blank header for the check box;
var th=document.createElement('th');
headTr.appendChild(th);
for(var i = 0; i<columns.length ;i++)
{
var td=document.createElement('th');
// if the column is sortable then add the event listener for sorting it
if(columns[i].Sortable)
{
td.addEventListener("click",function(){ this.sortBy(columns[i].Title); });
}
td.innerText = columns[i].Title;
headTr.appendChild(td);
}
this.$.tableHead.appendChild(headTr);
},
drawTableBody: function(context){
// this is a defered function
var context = context;
// get the number of items according to the current page number
var pageItems= context.filteredData.slice((context.page*context.pageNo),((context.page*context.pageNo)+context.page));
console.log(pageItems);
// print the page items
for(var i=0; i < pageItems.length; i++)
{
var currItem = pageItems[i];
var tr= document.createElement("tr");
// add the check box first
var checkbox= document.createElement("input");
checkbox.type="checkbox";
checkbox.checked=pageItems[i].Selected;
var ItemId = currItem.Id;
checkbox.setAttribute("data-ItemId",ItemId-1);
var td=document.createElement('td');
td.appendChild(checkbox);
tr.appendChild(td);
// for every column specified add a column to it
for(var j = 0; j< context.columns.length; j++)
{
var td=document.createElement("td");
td.innerText= pageItems[i][context.columns[j].Title];
tr.appendChild(td);
}
//append the row to the table;
context.$.tableBody.appendChild(tr);
} // end for i
},
applyFilters:function(context){
if(context.filter)
{
alert("filterApplied");
}
},
changeSelection:function(checkbox){
var ItemId = checkbox.getAttribute("data-ItemId");
this.data[ItemId].Selected= checkbox.checked;
console.log(this.data[ItemId]);
},
properties:{
title :String,
columns:Array,
data:Array,
page:Number,
filters:Object,
Selectable:Boolean
}
});
</script>
and here is what my index page looks like:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title><my-repo></title>
<!-- Imports polyfill -->
<script src="webcomponents-lite.min.js"></script>
<!-- Imports custom element -->
<link rel="import" href="my-element.html">
<link rel="import" href="bower_components/paper-checkbox/paper-checkbox.html">
</head>
<body unresolved>
<!-- Runs custom element -->
<custom-table title="This is data table"></custom-table>
<script>
document.addEventListener("WebComponentsReady",function(){
var data = [{'Id':1,'firstName':'aman',age:25},{'Id':2,'firstName':'gupta',age:25}];
var cols = [{Title:'firstName',Sortable:true},{Title:'age',Sortable:false}];
var a = document.querySelector('my-element');
a.loadData(cols,data);
});
</script>
</body>
</html>
I've just started out with polymer and I'm not quite sure what's going on here..
Thank you in advance :)
I got what the problem is..
My custom element was referencing a different Polymer.html file.
Silly me :D
I'm using Polymer Starter Kit Yeoman generator on Windows and I had the same problem:
Error: DuplicateDefinitionError: a type with name 'dom-module' is already registered
This error is triggered in Firefox console. Chrome works fine.
The components created with the generator (example: yo polymer:el my-element) have this polymer.html import:
<link rel="import" href="..\..\bower_components/polymer/polymer.html">
The base path is described with "backslash".
In some custom polymer elements I created by myself, I imported polymer.html with:
<link rel="import" href="../../bower_components/polymer/polymer.html">
And I think this lead to a duplication of some kind. To solve the problem, I just changed all automatically created imports, using only forward slashes /.
Hope this helps someone.

Browser embedded in WPF not handling pointer events

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

Composite C1 - Using MVC RenderSections or the like

In Composite C1 I'm using Razor syntax to create my master layout. For faster loadtimes it's recommended to put your scripts just before the end body tag instead of inside the head tag. That's why I put jQuery and other scripts just before the end body tag.
When I use a Razor function with JavaScript that refers to jQuery I get an error because jQuery hasn't been loaded yet. The HTML from the Razor function is output before the jQuery script is loaded:
Uncaught ReferenceError: $ is not defined
In MVC I can use RenderSection in the master layout to accomplish this (rendering the JavaScript below my master layout scripts
#RenderSection("FooterScripts", false)
Then in my views I can define a section like this:
#section FooterScripts {
<script type="text/javaScript">
$(function () {
...
});
</script>
}
Which will render the HTML in the correct place in the final HTML. Is this possible to do in Composite C1? I couldn't get RenderSection to work even though Intellisence tells me it's available.
There's no built in way to insert html markup from a C1 function to a specific place in a layout.
Possible ways to implement your own logic would be:
Collect the scripts to be insterted in f.e. Context.Items collection, and insert them in the end.
Implement some post processing logic that would move the script tags to the bottom of the page after it is rendered.
First way is easier to implement, here's a short working example:
C1 Function code:
#inherits RazorFunction
#using Composite.Examples
#functions {
}
#{
LayoutHelper.AddDelayedScript(Script());
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
Inserting a script at the bottom of a page
</body>
</html>
#helper Script() {
<script type="text/javascript">
alert("I'm inserted!");
</script>
}
Layout code:
....
#LayoutHelper.RenderDelayedScripts()
</body>
</html>
Class LayoutHelper, defined in App_Code:
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace Composite.Examples
{
public static class LayoutHelper
{
private const string HttpItems_Key = "delayedscripts";
public static void AddDelayedScript(IHtmlString script)
{
var context = HttpContext.Current;
lock (context.Items.SyncRoot)
{
if (!context.Items.Contains(HttpItems_Key))
{
context.Items.Add(HttpItems_Key, new List<IHtmlString>());
}
(context.Items[HttpItems_Key] as List<IHtmlString>).Add(script);
}
}
public static IHtmlString RenderDelayedScripts()
{
var context = HttpContext.Current;
var sb = new StringBuilder();
if (context.Items.Contains(HttpItems_Key))
{
foreach (var delayedscript in context.Items[HttpItems_Key] as IEnumerable<IHtmlString>)
{
sb.Append(delayedscript.ToHtmlString());
}
}
return new HtmlString(sb.ToString());
}
}
}

Google Map v3 Ground Overlay?

I have spent two days puzzling this and failed. Any assistance will be greatly appreciated.
I need a map centered on -18.975750, 32.669184 in a canvas of 1500px x 900px. I then to need to overlay coverage PNGs (obtained form www.heywhatsthat.com) with set code- transparency.
I have eventually arrived at the following code and it fails. I would like to add more than one PNG bound by it's co-ords, but cant even get one to work.
<script src="http://maps.google.com/maps?file=api&v=3&key=AIzaSyAGbZjXr2wr7dT2P3O5pNo5wvVF3JiaopU&sensor=false"
type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
if (GBrowserIsCompatible()) {
var map = new google.maps.MAP(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(-18.975750, 32.669184), 13);
map.setUIToDefault();
var imageBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-19.000417,30.999583),
new google.maps.LatLng(-17.999583,32.000417));
var oldmap = new google.maps.GroundOverlay(
"http://www.earthstation.mobi/cloakpS19E031.png",imageBounds);
oldmap.setMap(map);
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<div id="map_canvas" style="width: 1500px; height: 900px"></div>
</body>
</html>
What am I mssing and please point me in the right direction add multiple png overlays with transparency in the options.
Thanks
Brian
Zimbabwe
You have a lot of issues with your code. It looks like you're trying to migrate from V2 to V3, and you still have V2 methods and objects in your code. You're also not loading the JS APi correctly when you call in the of your HTML.
Here is functional code that displays the overlay using the V3 API, but it looks like the original center coordinates that you used do not place the map at the center of the overlay (you'll need to figure that out yourself). I've added comments where relevant so that you can see where you went astray. Note the call to the API library in the first script tag.
<script src="http://maps.googleapis.com/maps/api/js?key=AIzaSyAGbZjXr2wr7dT2P3O5pNo5wvVF3JiaopU&sensor=false"
type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
//You don't need to use GBrowserIsCompatible, it's only for V2 of the API
//if (GBrowserIsCompatible()) {
//You need to set up options for the map that you reference when you
//instantiate the map object
var myOptions = {
center: new google.maps.LatLng(-18.975750, 32.669184),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
//Your code references google.maps.MAP; it's google.maps.Map
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var imageBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-19.000417,30.999583),
new google.maps.LatLng(-17.999583,32.000417));
var oldmap = new google.maps.GroundOverlay(
"http://www.earthstation.mobi/cloakpS19E031.png",imageBounds);
oldmap.setMap(map);
//} <--Your code was missing this closing bracket for the conditional
//But the conditional is not even needed, since GBrowserCompatible is a V2 thing
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width: 1500px; height: 900px"></div>
</body>
</html>

jQuery mobile calendar with 3-state day colours

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>

Resources