I'm trying to use an ActiveX control in an out-of-browser Silverlight5 application.
This code (for in-browser) works:
Host Html page:
<script type="text/javascript">
function GetAXObjectStatus() {
var axObject = document.getElementById("axObject");
return axObject != null ? axObject.GetStatus() : -1;
}
</script>
</head>
<body>
<object id="axObject" classid="CLSID:my-cls-id"></object>
Silverlight:
string result = HtmlPage.Window.Invoke("GetAXObjectStatus").ToString(); // works fine
But the following (for out-of-borwser), which is my goal, doesn't work:
// Application.Current.HasElevatedPermissions == true
// AutomationFactory.IsAvailable == true
dynamic axObject = AutomationFactory.CreateObject("my_prog_id"); // returns a non-null object
axObject.GetStatus(); // produces a "Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))"
Any idea what might be wrong?
Related
I am working on an ionic app and we have a button to Call someone. This doesn't make a whole lot of sense when using a tablet so I would like to not show this button if the person is using a tablet.
Is there an easy way using ionic/cordova that I can detect if the device is a tablet (or I suppose I could also detect if the device has a phone application)?
You can see how call feature detection is done in CordovaCallNumberPlugin.
There are tablets which support calling so I would check for this, but this is of course up to you and depends on your application.
Android:
private boolean isTelephonyEnabled(){
TelephonyManager tm = (TelephonyManager)cordova.getActivity().getSystemService(Context.TELEPHONY_SERVICE);
return tm != null && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
}
iOS:
if(![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:number]]) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:#"NoFeatureCallSupported"];
}
It depends what platforms you are supporting as to how easy this is.
Cordova "out-of-the-box" can't determine if a device is a tablet.
For iOS, a simple bit of Javascript can be used to detect if the device is an iPad by examining the user agent string:
var isTablet = !!navigator.userAgent.match(/iPad/i);
However, for Android, JS isn't good enough, it requires some native Java:
private boolean isTabletDevice(Context applicationContext) {
boolean device_large = ((applicationContext.getResources().getConfiguration().screenLayout &
Configuration.SCREENLAYOUT_SIZE_MASK) >=
Configuration.SCREENLAYOUT_SIZE_LARGE);
if (device_large) {
DisplayMetrics metrics = new DisplayMetrics();
Activity activity = this.cordova.getActivity();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (metrics.densityDpi == DisplayMetrics.DENSITY_DEFAULT
|| metrics.densityDpi == DisplayMetrics.DENSITY_HIGH
|| metrics.densityDpi == DisplayMetrics.DENSITY_MEDIUM
|| metrics.densityDpi == DisplayMetrics.DENSITY_TV
|| metrics.densityDpi == DisplayMetrics.DENSITY_XHIGH) {
Log.d(LOG_TAG, "Is Tablet Device");
return true;
}
}
Log.d(LOG_TAG, "Is NOT Tablet Device");
return false;
}
This plugin wraps up both these approaches in an easy-to-use package for Android and iOS: https://github.com/dpa99c/phonegap-istablet.
You can use ngCordova plugin $cordovaDevice: http://ngcordova.com/docs/plugins/device/
Just add $cordovaDevice as a dependency in your controller and use it to tell what device is being used.
Perhaps you can build an array of models and check if the model is inside of that array, if it is, then disable the button with an ng-if or ng-show in the HTML.
Example
JS
app.controller('MyCtrl', [
'$scope',
'$cordovaDevice',
function($scope, $cordovaDevice) {
var model = $cordovaDevice.getModel();
var listOfModels = ['model1', 'model2', 'model3'];
if (listOfModels.indexOf(model) > -1) {
console.log("Model found inside array");
$scope.enablePhoneCall = false;
} else {
console.log("Model NOT found inside array");
$scope.enablePhoneCall = true;
}
}
]);
HTML
<button class="button button-calm" ng-if="enablePhoneCall">Call</button>
More info:
http://ngcordova.com/docs/plugins/device/
https://github.com/apache/cordova-plugin-device
List of models: http://theiphonewiki.com/wiki/index.php?title=Models
PS: Don't forget to add ngCordova as a dependency when you define your ionic app.
Ionic adds various platform classes to the document body. In iOS you can simply check for the classes platform-ipad or platform-ipod to check for a non-iPhone. Source: Ionic Platform Body Classes & Platform Classes.
On Android this won't be so straight forward and the answer #Ariel gave seems like a good approach to this issue.
Found an easier way that doesn't need plugins and works for both IOS and Android tablets.
Just add to the run function of your app the following piece of code.
angular.module('app').run(function ($rootScope, $window) {
// Get the current platform.
var platform = ionic.Platform.platform();
// Initialize isTablet and isApp to false.
$rootScope.isTablet = $rootScope.isApp = false;
if (platform === 'android' || platform === 'ios') {
// Check if the larger size of your window is bigger than 700px.
// The reason I am checking for the max is because the tablet
// might be in landscape mode.
Math.max($window.innerHeight, $window.innerWidth) > 700 ?
$rootScope.isTablet = true : $rootScope.isApp = true;
}
}
Now anywhere throughout your app you can use easily know if it is an app or a tablet or desktop.
In Html:
<!-- App Logic -->
<div ng-if="isApp">
...
</div>
<!-- Tablet Logic -->
<div ng-if="isTablet">
...
</div>
<!-- Desktop Logic -->
<div ng-if="!isApp && !isTablet">
...
</div>
In JS Controllers
angular.module('app').controller('myController', function($rootScope) {
if ($rootScope.isApp) {
// App Logic
...
} else if ($rootScope.isTablet) {
// Tablet Logic
...
} else {
// Desktop Logic
...
}
}
P.S. Don't forget to change the word 'app' in my examples to the name of your ionic app, and to inject $rootScope in any controller that you will be using it.
P.P.S. if indeed one of the new phones coming out today or tomorrow have a bigger size than 700px on the larger dimension of their screen, I would treat it as a tablet.
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.
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
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());
}
}
}
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>