I am trying to print a VueJS component with custom print style.
Three Vue plugins look interesting on this subject:
1.printd
2.vue-print-nb
3.html-to-paper
Out of the three only html-to-paper has a options object that can pass a custom css style in order to dynamically pass some print css.
My issue is that i can't seem to load the custom css, and also bootstrap classes are messed up on print action.
This is basically what i am doing.
import VueHtmlToPaper from 'vue-html-to-paper'
const options = {
name: '_blank',
specs: [
'fullscreen=yes',
'titlebar=yes',
'scrollbars=no'
],
styles: [
'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css',
'./myPrint.css'
]
}
Vue.use(VueHtmlToPaper, options)
Any suggestion is welcomed.
Thanks
I have tried all these three I think the best one is print.js which is not specifically for Vue.js but it is easily install-able and usable in the vue components.
For example
<script>
import print from "print-js";
export default {
methods: {
printing() {
const style =
"#page { margin-top: 400px } #media print { h1 { color: blue } }";
const headerStyle = "font-weight: 300;";
printJS({
printable: "rrr",
type: "html",
header: "Doctor Name",
headerStyle: headerStyle,
style: style,
scanStyles: false,
onPrintDialogClose: () => console.log("The print dialog was closed"),
onError: e => console.log(e)
});
},
printVisit(id) {
this.$htmlToPaper("rrr");
this.$htmlToPaper("rrr", () => {
console.log("Printing completed or was cancelled!");
});
}
}
};
</script>
VueHtmlToPaper opens a new window with its own style tag. So when you pass a CDN it works, if u pass a local file it does not because it tries to access the resource in your web server but in the wrong URL. Let's see how the page looks when we use a CDN and a local CSS file.
CDN
<html>
<head>
<link rel="style" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
</head>
<body>
</body>
</html>
Local CSS file
And let's say you are calling the print function from http://localhost:8080/somepage
<html>
<head>
<link rel="style" href="./myPrint.css">
</head>
<body>
</body>
</html>
This will try to open http://localhost:8080/somepage/myPrint.css. Obviously this will not be accessible to print dialogue.
Solution
Put your custom CSS file in the public or static folder (Where you usually keep favicon)
Modify script path in options, prepend server basepath with the CSS file
Sample Option
import VueHtmlToPaper from 'vue-html-to-paper'
/* This will change according to your server */
let basePath= 'http://localhost:8080';
const options = {
name: '_blank',
specs: [
'fullscreen=yes',
'titlebar=yes',
'scrollbars=no'
],
styles: [
'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css',
`${basePath}/myPrint.css`
]
}
Vue.use(VueHtmlToPaper, options)
Also, the simplest way to access root-relative path is to use /. User /style.css instead of ./style.css
Related
I have created a Tab App in Teams. Now I want to make a dialog from one tab accessible via a Message Extension App. This works partially now through embedding the contentUrl of the specific tab as an iFrame in the Task Module of the Message Extension like here: https://learn.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/action-commands/create-task-module?tabs=dotnet#create-a-task-module-with-an-embedded-web-view
. The issue is the authentication. Api Calls won't work and the dialog is not able to retreive or send data.
In the manifest.json of the Tab App are the contentUrls of the tabs in the "staticTabs" section:
"staticTabs": [
{
"entityId": "dashboard",
"name": "Dashboard",
"contentUrl": "https://cdne-stcsfeedbackuidev.azureedge.net/tabs/dashboard.html?app.locale={locale}&page.subPageId={subEntityId}&app.theme={theme}",
"scopes": [
"personal"
]
}
],
I gave the dialog a specific Route via React Router so that you can access the dialog via subPageId. This works fine.
The Problem is, if you access the contentUrl, you won't be authenticated and API calls to the Graph API and own API won't work. This issue does not go away if I embed the tab via contentUrl in a Task Module for the Message Extension to give it a Teams Context:
public async handleTeamsMessagingExtensionFetchTask(
context: any,
action: any
): Promise<any> {
return {
task: {
type: 'continue',
value: {
width: 925,
height: 925,
title: 'Feedback Dialog',
url: "https://2e70-37-201-241-91.ngrok.io/feedbackDialog.html",
fallbackUrl: "https://cdne-stcsfeedbackuidev.azureedge.net/tabs/dashboard.html?page.subPageId=feedbackDialog"
}
}
};
}
Directly embedding the url like in "fallbackUrl" will result in an empty Task Module so I embedded the Url in a like this in feedbackDialog.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World Feedback!</title>
</head>
<body>
<script src="https://statics.teams.microsoft.com/sdk/v1.7.0/js/MicrosoftTeams.min.js"></script>
<script>
microsoftTeams.initialize();
microsoftTeams.getContext((context) => {
console.log(context);
microsoftTeams.authentication.getAuthToken({
successCallback: (token) => {
console.log(token);
},
failureCallback: (reason) => {
console.error(reason);
}
});
});
</script>
<div style="padding:50px;">
<iframe id="feedbackDialog" width="800" height="800", frameBorder="0"
src="https://cdne-stcsfeedbackuidev.azureedge.net/tabs/dashboard.html?page.subPageId=feedbackDialog"></iframe>
</div>
</body>
</html>
The dialog gets displayed in the Task Module this way like if I open the contentUrl in the browser directly. But the Authentication does not work. The Teams context can be retreived but all API calls return with the Error: "Error: SDK initialization timed out".
Is there a simple way for me to authenticate the user here because this runs in Teams as a MessageExtension App and the embedded content in the Task Module comes from a Teams Tab App. Or do I need to manually implement something using MSAL?
I'm looking for the right url to reference static assets, like images within Vue javascript.
For example, I'm creating a leaflet marker using a custom icon image, and I've tried several urls, but they all return a 404 (Not Found):
Main.vue:
var icon = L.icon({
iconUrl: './assets/img.png',
iconSize: [25, 25],
iconAnchor: [12, 12]
});
I've tried putting the images in the assets folder and the static folder with no luck. Do I have to tell vue to load those images somehow?
For anyone looking to refer images from template, You can refer images directly using '#'
Example:
<img src="#/assets/images/home.png"/>
In a Vue regular setup, /assets is not served.
The images become src="data:image/png;base64,iVBORw0K...YII=" strings, instead.
Using from within JavaScript: require()
To get the images from JS code, use require('../assets.myImage.png'). The path must be relative (see below).
So your code would be:
var icon = L.icon({
iconUrl: require('./assets/img.png'), // was iconUrl: './assets/img.png',
// iconUrl: require('#/assets/img.png'), // use # as alternative, depending on the path
// ...
});
Use relative path
For example, say you have the following folder structure:
- src
+- assets
- myImage.png
+- components
- MyComponent.vue
If you want to reference the image in MyComponent.vue, the path sould be ../assets/myImage.png
Here's a DEMO CODESANDBOX showing it in action.
A better solution would be
Adding some good practices and safity to #acdcjunior's answer, to use # instead of ./
In JavaScript
require("#/assets/images/user-img-placeholder.png")
In JSX Template
<img src="#/assets/images/user-img-placeholder.png"/>
using # points to the src directory.
using ~ points to the project root, which makes it easier to access the node_modules and other root level resources
In order for Webpack to return the correct asset paths, you need to use require('./relative/path/to/file.jpg'), which will get processed by file-loader and returns the resolved URL.
computed: {
iconUrl () {
return require('./assets/img.png')
// The path could be '../assets/img.png', etc., which depends on where your vue file is
}
}
See VueJS templates - Handling Static Assets
Right after oppening script tag just add import someImage from '../assets/someImage.png'
and use it for an icon url iconUrl: someImage
this finally worked for me, image passed as prop:
<img :src="require(`../../assets/${image}.svg`)">
What system are you using? Webpack? Vue-loader?
I'll only brainstorming here...
Because .png is not a JavaScript file, you will need to configure Webpack to use file-loader or url-loader to handle them. The project scaffolded with vue-cli has also configured this for you.
You can take a look at webpack.conf.js in order to see if it's well configured like
...
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
...
/assets is for files that are handles by webpack during bundling - for that, they have to be referenced somewhere in your javascript code.
Other assets can be put in /static, the content of this folder will be copied to /dist later as-is.
I recommend you to try to change:
iconUrl: './assets/img.png'
to
iconUrl: './dist/img.png'
You can read the official documentation here: https://vue-loader.vuejs.org/en/configurations/asset-url.html
Hope it helps to you!
It works for me by using require syntax like this:
$('.eventSlick').slick({
dots: true,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: false,
autoplaySpeed: 2000,
arrows: true,
draggable: false,
prevArrow: '<button type="button" data-role="none" class="slick-prev"><img src="' + require("#/assets/img/icon/Arrow_Left.svg")+'"></button>',
Having a default structure of folders generated by Vue CLI such as src/assets you can place your image there and refer this from HTML as follows <img src="../src/assets/img/logo.png"> as well (works automatically without any changes on deployment too).
I'm using typescript with vue, but this is how I went about it
<template><div><img :src="MyImage" /></div></template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';
export default class MyPage extends Vue {
MyImage = "../assets/images/myImage.png";
}
</script>
You could define the assets path depending on your environment
const dev = process.env.NODE_ENV != 'production';
const url = 'https://your-site.com';
const assets = dev ? '' : url;
<template>
<img :src="`${assets}/logo.png`"/>
<p>path: {{assets}}</p>
</template>
<script>
export default {
data: () => ({
assets
})
}
</script>
Ideally this would be inside an utils js file, or as an extended app defineProperty, like:
const app = createApp(component);
app.config.globalProperties.$assets = assets;
app.mount(element);
and will be available as:
<template>
<img :src="`${$assets}/logo.png`"/>
<p>path: {{$assets}}</p>
</template>
<script>
export default {
mounted() {
console.log(this.$assets);
}
}
</script>
load them in created, mounted or where you need them
async created() {
try {
this.icon = (await import('#assets/images/img.png')).default;
} catch (e) {
// explicitly ignored
}
and then
<img :src=icon />
Inside code you can directly require image using.
const src = require("../../assets/images/xyz.png");
Or
In order to dynamically load image need this.
const image = new window.Image();
image.src = require("../../assets/images/xyz.png");
image.onload = () => {
// do something if needed
};
I was trying to use to embed the svg picture but it does not show anything. I looked at some other threads and it was suggested to add type="image/svg+xml", however, it did not solve the issue. When I am trying to look at the DOM for some reason it seems to create an endless loop. I attached the picture
This is the compononent
<template>
<div class="logo">
<object type="image/svg+xml" data="logo.svg">
</object>
</div>
</template>
This is the app.vue
template>
<div id="app">
<Demo></Demo>
</div>
</template>
<script>
import Demo from './components/Demo.vue'
export default {
name: 'app',
components: {
Demo
}
}
</script>
```[![Snapshot][1]][1]
[1]: https://i.stack.imgur.com/Q6ipO.png
This happen because vue-loader doesn’t recognize paths in just any attribute. By default just recognize these ones: https://vue-loader.vuejs.org/options.html#transformasseturls
So, there are 3 possible solutions
Note: If you are not using eslint as linter you could remove eslint comments
1: Bind the route to your image
First add the next variable to your data in the component
data() {
return {
// eslint-disable-next-line global-require
mySvg: require('../assets/logo.svg'),
};
},
Next modify your template
<object type="image/svg+xml" :data="mySvg">
2: Add vue-loader rule
If you don't want to have to bind every svg image, you could add a rule to vue-loader in order to say how to handle data attribute in a object
Go to your webpack config file, if you created the project using vue-cli 3.x you have to create a vue.config.js file in the root (same level that package.json)
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap((options) => {
// eslint-disable-next-line no-param-reassign
options.transformAssetUrls = {
object: 'data',
};
return options;
});
},
};
if you want to check that the config was added, execute vue inspect > webpack.config and expect see something like this (inside webpack.config):
{
loader: 'vue-loader',
options: {
...
transformAssetUrls: {
object: 'data'
}
}
}
More info: https://cli.vuejs.org/guide/webpack.html#working-with-webpack
3: Replace default loader and use svg as vue components
Other option is use vue-svg-loader. This loader inlines the SVGs which enables you to modify them using css. Also optimize your files with SVGO
See more: https://vue-svg-loader.js.org/#vue-cli
It is worth checking that you don't have a CSS rule hiding object tags. Otherwise it seems correct. You probably need to check the path and make sure you can reach your image. I assume your filename is a dummy, but try to use an absolute path. And make sure you can hit the path and see the image in your browser.
I have been trying to get someone to explain to me how the dojo AMD loading works and to get a simple piece of code to work. I understand that if using for example the CDN, one has to call the dojo library and load all modules you wish to use. I have tried to implement other javascript functions based on activity from the main page and I will always get the function either undefined or an error related to a dojo control undefined. It seems that all the modules that initially load are not available to the rest of the code. Any helpful explanations would be really appreciated.
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojo/resources
/dojo.css" />
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dijit/themes/
tundra/tundra.css" />
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojox/mobile/themes/
iphone/iphone.css" />
<title> DOJO </title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/
dojo/dojo.js"
data-dojo-config="async:true"></script>
<script type="text/javascript" src="Scripts/login.js"></script>
<script type="text/javascript">
require(["dojox/mobile/parser",
"dojo/parser",
"dojo/on",
"dojo/request/xhr",
"dijit/form/Form",
"dojo/store/Observable",
"dojo/store/Memory",
"dijit/Toolbar",
"dijit/Dialog",
"dojo/io/script",
"dojo/query",
"dojo/_base/lang",
"dijit/layout/ContentPane",
"dojox/mobile/Button",
"dojox/mobile/deviceTheme",
"dojox/mobile/compat",
"dojox/mobile/Heading",
"dojox/mobile/TextBox",
"dojox/mobile/Opener",
"dijit/form/TextBox",
"dijit/form/HorizontalSlider",
"dijit/form/ValidationTextBox",
"dijit/Calendar",
"dojox/mobile/ScrollableView",
"dojo/dom",
"dojo/domReady!",
"dojox/mobile"],
function (dom, domReady ,mobile, ScrollableView,
parser, query, domClass, domStyle, on, event, xhr,Form,
lang, Button, deviceTheme, compat, Heading) {
dojox.mobile.parser.parse();
});
</script>
From my understanding is that the way I have the code above is that my interface will load correctly and all widgets in the body of html will be displayed and it works fine. The problem is that I have a form that gets input from the user and on a button click event calls a function that handles the webrequests. I could not get this to work and it is merely a problem with where I am placing this function. I have added a simplified version:
What I have done is add that function to a script file to separate it from the rest of the code:
var dojoXhr;
function correctInput(div, td, msg) {
dojo.domStyle.set(div, 'display', '');
td.innerHTML = msg;
}
require(["dojo/_base/declare", "dojo/parser", "dojo/query", "dojo/dom-class",
"dojo/dom-style", "dojo/on",
"dojo/_base/event",
"dojo/request/xhr", "dijit/form/ValidationTextBox", "dojo/domReady!"],
function chklogin(declare, parser, query, dom-class, dom-style,
on, event, xhr,ValidationTextBox, domReady) {
var lname = dijit.byId('login').get('value');
var psswd = dijit.byId('password').get('value');
var feedback = document.getElementById('feedback');
var feedbackTD = dojo.query('td.feedback')[0];
if (lname == '' || psswd == '') {
correctInput(feedback, feedbackTD, 'Please enter a valid login!');
dojo.domStyle.set(feedback, 'display', '');
dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
feedbackTD.innerHTML = "Please enter a valid login!";
return;
}
if (!(lname == 'login') || !(psswd == 'password')) {
correctInput(feedback, feedbackTD, 'Please enter a valid login!');
return;
}
else {
dojo.domStyle.set(feedback, 'display', '');
dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
feedbackTD.innerHTML = "THATS IT BRO!";
return;
}
});
I got advice on the dojo forum to put my function in a define function and then use a require to call it all. I could not figure out how to do this.
It seems that all the modules that initially load are not available to
the rest of the code.
You are using a CDN to load the dojo toolkit. When you use CDN you are required to define the location of the module packages. You need to edit the dojoConfig for the code to work.
See this article about Using Custom Modules with a CDN. The important part is the packages object.
<script data-dojo-config="async: 1, dojoBlankHtmlUrl: '/blank.html',
packages: [ {
name: 'custom',
location: location.pathname.replace(/\/[^/]+$/, '') + '/js/custom'
} ]"
src="//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js">
</script>
Edit: Below is a simple dojo application.
So in my case create a module called chklogin, then require it, and
when the user clicks the button it will call that module chklogin from
within the main require[] function. Correct?
I would say yes. You are correct. I think your concept is a viable option. I hope this example helps with implementing define() to create your own modules. I will try to help where I can as you develop your idea. You can download the project here while available.
Directory Structure:
/index.html
/js/config.js
/js/controller/Controller.js
/js/modules/MyFirstModule.js
/index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css">
<script src="js/config.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js"></script>
<script>
require(["app/Controller", "dojo/domReady!"], function(Controller) {
//Initiate the entire application by calling main method of our Controller class.
Controller.main();
//Call our getter method of the Controller class to show how to access a private variable.
console.log(Controller.getWelcomeMessage());
});
</script>
</head>
<body class="claro" id="appBody"></body>
</html>
/js/config.js
We use packages to reference the CDN dojo files. Now we can call dojo classes by our package name
For example, "dojo/domReady!", "dijit/form/Button", "dojox/app/main". The dojo files
are stored on the google servers, which is referenced by the
<script src='http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js'>< /script>
in the index.html file.
Here we create our own custom packages. This could be for your modules, widgets, etc. The package
locations will map to the javascript directory that you store your custom dojo files in.
For example, myModules can be found in the /js/modules directory. You will reference any custom
dojo files via "myModules/MyModule", which locates and loads "/myModules/MyModule.js" file.
For an explanation of the baseURL, see: http://dojotoolkit.org/documentation/tutorials/1.9/hello_dojo/
"Defining and Requiring Modules". This code registers the correct location of our own packages so
we can load Dojo from the CDN whilst still being able to load local modules.
I created a package called "app" as you can see below. This is how I initialize my app in my project.
This was designed to allow me to keep the separation of code the best I know how. It is loaded and
called in the index.html page. So i give it a package name of app. It is physically located in the
js/controller/Controller.js file.
This dojoConfig object is used in the index.html and must be loaded prior to < script src='...dojo.js' > tag.
var dojoConfig = {
async: true,
tlmSiblingOfDojo: false,
baseUrl: location.pathname.replace(/\/[^/]*$/, ''),
packages: [
{ name: "myModules", location: "js/modules" },
{ name: "app", location: "js/controller", main: "Controller" }
]
};
if you choose to host the dojo files on your own server, you can reference them like below. Assuming the dojo js files are located in the "/js/dojo/*" directory.
packages: [
{ name: "dojo", location: "dojo/dojo" },
{ name: "dijit", location: "dojo/dijit" },
{ name: "dojox", location: "dojo/dojox" },
{ name: "myModules", location: "js/modules" },
{ name: "app", location: "js/controller", main: "Controller" }
]
/js/controller/Controller.js
Here is the controller which I use to initialize the web app.
define(["myModules/MyFirstModule"], function(MyFirstModule) {
//Private Variables...
var privateVariable1 = "Welcome to my Dojo Application!";
var privateVariable2;
/**
* init. This is a private function that is only available within this object.
*/
init = function() {
// proceed directly with startup
console.log("Startup functions are firing...");
//Render our "form" which only contains a single text box.
renderForm();
},
renderForm = function() {
MyFirstModule.createForm("appBody");
}
/**
* Enclose all public methods in the return object
*/
return {
/**
* main. This is a public function that can be called from other code.
*/
main: function() {
//Run init() method.
init();
},
/**
* getWelcomeMessage. This public function returns the value of the privateVariable1.
* This mimics a getter method.
*/
getWelcomeMessage: function() {
return privateVariable1;
}
};
}); //end define
/js/modules/MyFirstModule.js
This is an example of a custom Module. It is required by the Controller class as a dependency.
define([
//The required dependencies for this module.
"dojo/dom", "dojo/on", "dijit/form/TextBox", "dijit/form/Button"
], function(dom, on, TextBox, Button){
// Once all modules in the dependency list have loaded, this
// function is called to define the myModules/myFirstModule module.
//
// The dojo/dom module is passed as the first argument to this
// function; additional modules in the dependency list would be
// passed in as subsequent arguments (on, TextBox, and Button).
// Private variables
var firstNameTextBox;
var submitButton;
privateFunction = function() {
console.log("I am a private function. I can only be called from this class.");
};
// This returned object becomes the defined value of this module when called elsewhere.
return {
/**
* createForm. This method creates a simple form. Textbox and button.
* #param placeMeHere This is where to place the form elements. In this demo, the are placed in the
* body of the html document. This is executed in the Controller class.
*/
createForm: function(placeMeHere) {
//Create new TextBox.
firstNameTextBox = new TextBox({
name: "firstname",
value: "" /* no or empty value! */,
placeHolder: "type in your name"
}, "firstname");
//Place me in the DOM.
firstNameTextBox.placeAt(placeMeHere);
//Render
firstNameTextBox.startup();
//Create Button
submitButton = new Button({
label: "Say Hi"
}, "submitButton");
submitButton.placeAt(placeMeHere);
submitButton.startup();
//Greet the user.
on(submitButton, "click", function(evt){
console.log("Hi there, " + firstNameTextBox.get("value"));
});
}
};
});
I have Bing Maps on a page in my WinJS Windows 8 Application.
The Map has a few pins each with its own Infobox. When clicking on the pin it displays the infobox correctly with its content. The content contains a hyperlink that links to a different page in the Windows 8 Application. The app navigates to this page correctly, however the back button stops working and the App Bar can't be accessed either. (Navigating to the page normally works fine)
I think something goes wrong with how the page navigates and how the navigator records the state. I am new to this so it might also just be a stupid question.
Here is the code in the page's .js file:
// For an introduction to the Page Control template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/testBing/testBing.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: initMap });
}
});
})();
var pinInfobox = null;
function initMap() {
try {
var mapOptions =
{
credentials: "credentials",
center: new Microsoft.Maps.Location(-33.961176, 22.420985),
mapTypeId: Microsoft.Maps.MapTypeId.road,
zoom: 5
};
var mapDiv = document.querySelector("#mapdiv");
map = new Microsoft.Maps.Map(mapDiv, mapOptions);
centerPosition();
}
catch (e) {
var md = new Windows.UI.Popups.MessageDialog(e.message);
md.showAsync();
}
}
function addPushPin(location) {
map.entities.clear();
var pushpin = new Microsoft.Maps.Pushpin(location, null);
pinInfobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { title: 'My Pushpin', visible: true, description: "<a href='/pages/player/player.html'>Profile</a>" });
Microsoft.Maps.Events.addHandler(pushpin, 'click', displayInfobox);
Microsoft.Maps.Events.addHandler(map, 'viewchange', hideInfobox);
map.entities.push(pushpin);
map.entities.push(pinInfobox);
}
function hideInfobox(e) {
pinInfobox.setOptions({ visible: false });
}
function centerPosition() {
var geolocator = new Windows.Devices.Geolocation.Geolocator();
geolocator.getGeopositionAsync().then(function (loc) {
var mapCenter = map.getCenter();
mapCenter.latitude = loc.coordinate.latitude;
mapCenter.longitude = loc.coordinate.longitude;
map.setView({ center: mapCenter, zoom: 15 });
addPushPin(mapCenter);
});
}
function displayInfobox(e) {
pinInfobox.setOptions({ title: e.target.Title, innerHTML: e.target.Description, visible: true, offset: new Microsoft.Maps.Point(0, 25) });
pinInfobox.setLocation(e.target.getLocation());
}
The HTML just has the following
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!--Bing Mapps Reference -->
<script type="text/javascript" src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>
<link href="testBing.css" rel="stylesheet" />
<script src="testBing.js"></script>
</head>
<body>
<div class="testBing fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Welcome to testBing</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<div id="mapdiv"></div>
</section>
</div>
</body>
</html>
The comment by Dominic Hopton is correct: foo.html gets loaded as the whole page instead of as part of your app's navigation process. If the links are supposed to do an app navigation (as opposed to open in an external web browser), you can add this code to your page's ready function to convert the link click into a navigation event.
WinJS.Utilities.query("a").listen("click", function (e) {
e.preventDefault();
nav.navigate(e.target.href);
});
If you have some links that should navigate and some that should open in a browser, you can modify the query. For example, if can can add a CSS class to links that should open in a web browser, you could change the query to:
WinJS.Utilities.query("a:not(.defaultClick)")
You might also be able to modify the query to examine the href attribute of the link to check for "http" like so:
WinJS.Utilities.query("a:not([href^=http])")
I have not tested this last example yet, but if it works as I suspect it would, it would have a links that start with "http" (so including "https") behave normally, while all links that have a relative URL or a package URL will be converted to navigation events.
I don't recommend that you do this blindly, but depending on your app, this simple shortcut might change the behavior to match your expectations.