Trying to dynamically navigate to a new page using dojo - dojo

I am new to javascript and dojo, and am trying to write code to navigate to
another URL dynamically. This seems easy to do with javascript, but I can't
get it to work with dojo/on.
Here is my example code. The trivial callback works fine. The dojo/on callback
invokes the callback, but the new page never appears. I have to do this
dynamically and with dojo because, well just because my project requires it.
Anyone know why this is failing and how to make it work?
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js">
</script>
<script type="text/javascript">
callback = function() {
window.location.href = "about:blank";
console.debug("callback invoked");
}
function init() {
var node = dojo.byId("test");
var childNode = dojo.create("a", { href : "" }, node);
childNode.innerText = "dojo callback click here";
require(["dojo/on"], function(on){
on(childNode, "click", callback);
});
}
dojo.ready(init);
</script>
<div id="test">
<p>
trivial callback click here
</div>

Starting with Dojo 1.7, the AMD loader is the preferred way of using Dojo modules.
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>
<script type="text/javascript">
require(['dojo/on', 'dojo/dom', 'dojo/domReady!'], function(on, dom){
on(dom.byId('theDiv'), 'click', function(){
alert("Click!") // replace this line with location changes
})
})
</script>
</head>
<body>
<div id="test">
Click Me
</div>
</body>
</html>
In this example, the core Dojo.js is loaded (as you requested), but the difference is I used the require method, attaching the click method of dojo/on to the div. Ideally, you would use separate javascript files to dictate the behavior of your page, but for this example, embedding the js into the index page is sufficient.
Using the parser, you can use declarative <script type="dojo/on" data-dojo-event="click">...</script>, but for a variety of reasons you should use programmatic parsing and use javascript files for maximum efficiency.
In addition, defining functions/methods/variables in the global scope:
<script type="text/javascript">
callback = function() {
window.location.href = "about:blank";
console.debug("callback invoked");
}
</script>
... isn't recommended and there are better alternatives.

Related

How to display a basic autodesk forge viewer in a vue-cli app?

I was trying to convert the basic viewer example code into a simple vue.js viewer app. When I try to run `npm run serve'(vue-cli).Things are getting rendered correctly and I am getting all the console logs in the console.
But even before the script getting executed the eslint-loader is showing Autodesk is not defined error. But I can see the viewer loaded the document in the background.I will attach a screenshot of it here.
Can someone correct me with the code for creating a basic viewer as a simple vue.js app?
/public/index.html
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- Autodesk Forge Viewer files -->
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css" type="text/css">
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
/src/App.vue
<div id="forgeViewer"></div>
</template>
<script>
export default {
mounted(){
var viewer;
var options = {
env: 'AutodeskProduction',
api: 'derivativeV2', // for models uploaded to EMEA change this option to 'derivativeV2_EU'
getAccessToken: function(onTokenReady) {
var token = 'eyJhbGciOiJIUzI1NiIsImtpZCI6Imp3dF9zeW1tZXRyaWNfa2V5In0.eyJzY29wZSI6WyJidWNrZXQ6Y3JlYXRlIiwiYnVja2V0OnJlYWQiLCJkYXRhOnJlYWQiLCJkYXRhOndyaXRlIl0sImNsaWVudF9pZCI6Ikp2Vk40bzdBQ0V0ZE81TVpnZ21QMk9WM1RoNFJnRW54IiwiYXVkIjoiaHR0cHM6Ly9hdXRvZGVzay5jb20vYXVkL2p3dGV4cDYwIiwianRpIjoiMXBQcVhxOFBZVVU0WmtpTURsaGpUSUxCM3I1UEpBWk9kbTY4dTY2R1ZjajhDY3VzYjB3VFVId0E3emZPVk5JRCIsImV4cCI6MTU4ODIzNDEwOX0.zmY_BFmoZgL4TbtSVyTWKlrFdImEKbQTUsfQxBjsPV4';
var timeInSeconds = 3600; // Use value provided by Forge Authentication (OAuth) API
onTokenReady(token, timeInSeconds);
}
};
Autodesk.Viewing.Initializer(options, function() {
var htmlDiv = document.getElementById('forgeViewer');
viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
var startedCode = viewer.start();
if (startedCode > 0) {
console.error('Failed to create a Viewer: WebGL not supported.');
return;
}
console.log('Initialization complete, loading a model next...');
});
var documentId = 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6ZmFjaWxpb25ld2NsaWVudGJ1Y2tldC9yYWNfYWR2YW5jZWRfc2FtcGxlX3Byb2plY3QucnZ0';
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
}
},
methods:{
onDocumentLoadSuccess:function(viewerDocument){
var defaultModel = viewerDocument.getRoot().getDefaultGeometry();
viewer.loadDocumentNode(viewerDocument, defaultModel);
viewer.addEventListener( Autodesk.Viewing.SELECTION_CHANGED_EVENT, event=>{
})
},
onDocumentLoadFailure:function(){
console.error('Failed fetching Forge manifest');
}
}
}
</script>
<style>
</style>
You have to fix your Eslint errors one by one.
1.- Declare autodesk as a global in .eslintrc
"globals": {
"Autodesk": true
}
2.- Declare viewer
const viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
3.- Remove event listeners if not being used or just console.log(event)
Alternatively you can disable eslint but I'd never recommend that.
check out these working samples here:
https://github.com/dukedhx/forge-tools-hub/blob/master/components/Viewer.vue
https://github.com/alvpickmans/forge-vuer
In the main.js you can add:
Vue.prototype.$Autodesk = window.Autodesk;
And use it in the vue components like below:
this.$Autodesk

Why onClick event not work on dojo MenuItem?

I'm studying Dojo 1.10.4, my problem is that the onClick event does not work on dijit/MenuItem. I tried it on other item widgets like dijit/CheckedMenuItem and dijit/RadioMenuItem, none of their click events work, and the API docs didn't give any tips about it.
At last, I found it only works if it's contained in dijit/MenuBar. Should Item widgets be contained in dijit/MenuBar or dijit/Menu? How are the events processed on dojo widgets?
For example:
<html>
<head>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dijit/themes/claro/claro.css">
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"
data-dojo-config="async:true,parseOnLoad: true"></script>
<script>
require(["dojo/parser"],function(parser){
parser.parse();
});
</script>
</head>
<body class="claro">
<div data-dojo-type="dijit/MenuBar" >
<div data-dojo-type="dijit/MenuItem" onclick="alert();">it works</div>
</div>
<div data-dojo-type="dijit/MenuItem" onclick="alert();">it doesn't work</div>
</body>
</html>
In this case MenuItem needs a ContainerWidget like Menu or MenuBar. You add the Item as a child like :
require([
"dojo/dom",
"dijit/MenuItem",
"dijit/DropDownMenu",
"dijit/form/DropDownButton"
],
function(dom,MenuItem,DropDownMenu,DropDownButton){
var myMenu = new DropDownMenu();
var menuItem1 = new MenuItem({
id:"M1",
label:"Show M1",
onClick:function(){
//do what you want to do here
}
});
myMenu.addChild(menuItem1);
});
Studying this might help you too to understand how it works.
http://dojotoolkit.org/reference-guide/1.10/dijit/DropDownMenu.html#dijit-dropdownmenu
Regards

Closure's SeamlessField is covering text with a scrollbar

I'm trying to use Google's Closure library for the HTML editor. I created a goog.editor.SeamlessField but if I enter a word that is too long for the width, it puts a scrollbar in and covers the text. How do I fix this?
This appears to be happening only in Firefox. Here is some HTML that demos the problem:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='/closure-library/closure/goog/base.js'></script>
<script>
goog.require('goog.dom');
goog.require('goog.editor.SeamlessField');
</script>
<script>
function init() {
var d = goog.dom.getElement('div1');
var f = new goog.editor.SeamlessField(d);
f.makeEditable();
}
</script>
</head>
<body>
<div style='width:150px;'>
<div id='div1'>
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
</div>
</div>
<button onclick='init();'>Create editor</button>
</body>
</html>
DOM fragments generated by this SeamlessField component differ for Chromium and Firefox. The former gets an classic div element, the later issues an iFrame. The scheme has something to do with how Firefox handles content-editable elements. By styling the iFrame, you should be able to avoid the scrollbar.

Add Dynamically Links to jQuery Mobile

I read a lot about how to add stuff dynamically in jquery mobile, but I couldn't figure out how to add links.
Currently my solution looks like this:
Add a new Page - with id (id="list-1")
Creating a Link for it (href="#list-1")
This solution works perfectly in static pages, but I want to do it dynamically. I have tried a lot with page() and stuff like that but nothing helped me.
My questions are:
How do I add dynamic links & pages?
Did I choose the right way to use ids & anchors (#list-1) as links or is there another solution for jquery mobile?
Let me know if you need more information
To add dynamic links, I have found the easiest way is to just have an event listener waiting for a click on those links. This event listener then saves any parameters you want to pass into the next page you are visiting. You pass the parameters from the list element to the event listener by just specifying parameters within each "li" element.
(create the HTML for a list dynamically & store it into list-1-html)
$("div#my-page div[data-role=content]").html(list-1-html);
$("div.list-1 ul").listview();
$("div.list-1 ul").listview('refresh');
Then your event listener would look something like:
$('#my-page').delegate('li', 'click', function() {
passedParameter = $(this).get(0).getAttribute('passed-parameter');
});
When jQuery Mobile loads your next page, you'll probably want to load this page dynamically and you'll have this passedParameter variable available to you. To load the page dynamically, just add a listener that waits for JQM to try to load the page:
$('[data-role=page]').live('pageshow',function(e, ui){
page_name = e.target.id;
if (page_name == 'my-page-2'){
(do something with passedParameter)
}
});
This is the workflow I use with jQuery Mobile and it has been working just fine. I'm guessing in future releases, though, that they'll build in some kind of support for passing dynamic parameters to pages.
Any new enhancement to the DOM should be done before the page initializes. But by default JQM automatically initializes the page once the page is load in browser.
Hence first you need to set autoInitializePage property to false and then call initializePage() method after the new page and links are add to the document. Hope this helps.
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script>
$(document).bind("mobileinit", function(){
$.mobile.autoInitializePage = false;
});
</script>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
<script>
$(document).ready(function() {
//add a link.
$("#page1 div[data-role='content']").append('Next Page');
//add a page.
$('body').append(' <div data-role="page" id="page2" data-title="next page"><header data-role="header" class="header"> <h5>Page 2</h5></header><div data-role="content"><h3>Good Morning...</h3>Back</div><footer data-role="footer" data-position="fixed"><h5>© All rights reserved</h5></footer></div>');
});
window.onload = function() {
$.mobile.initializePage();
};
</script>
</head>
<body>
<div data-role="page" id="page1">
<header data-role="header" class="header">
<h5>jQuery Mobile</h5>
</header>
<div data-role="content">
<form method="get" action="" data-transition="slideup">
<label for="email">Email:</label>
<input type="email" name="email" id="email" value=""/>
</form>
</div>
<footer data-role="footer" data-position="fixed"><h5>© All rights reserved</h5></footer>
</div>
</body>
</html>

change dojo namespace

I need to change the dojo namespace to something else. I found this stackoverflow post, but it refers to a dojo documentation page that no longer exists. Below is something I tried based on this page, but didn't work:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojo/dojo.xd.js" djConfig="scopeMap: [[ 'dojo', 'newns' ]]"></script>
<script>
newns.addOnLoad(function(){
console.debug("hello world");
});
</script>
</head>
<body>
</body>
</html>
Help!
I just pulled the document out of the old Dojo book and put it in the new doc system:
http://docs.dojocampus.org/multiversion/index
For your specific example, the djConfig object needs to be declared in a script tag before the Dojo file loads, and it is recommended that you map dijit and dojox too:
<html>
<head>
<script>
var djConfig = {
scopeMap: [
['dojo', 'newns'],
['dijit', 'newnsw'],
['dojox', 'newnsx']
]
}
</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojo/dojo.xd.js"></script>
<script>
newns.addOnLoad(function(){
console.debug("hello world");
});
</script>
</head>
<body>
</body>
</html>