How to load multiple files in ifc.js - javascript

Hi I must be the first person to ask about ifc.js in SO but someone gotta start this, i have multiple files coming out of my Revit file for different treads and all of them share the same coordination point, is it possible to modify the code to load more than one model into the viewer?
const ifcLoader = new IFCLoader();
ifcLoader.setWasmPath("../");
const url = "STRC-B-L10.ifc";
window.addEventListener('DOMContentLoaded', (event) => {
ifcLoader.load(url, (geometry) => scene.add(geometry));
});

You can just load multiple models and the loader will be able to handle all of them out of the box. For instance, you can try opening several models in any of the live examples. You can also close them with the close() method.
We are building the docs right now, so don't hesitate to let us know of any suggestions you may have.
Really cool to see the first question about IFC.js in SO 😄

Related

Mocha + WebDriverIO - Common Functions

I have a test which contains steps that I'll want to reuse in multiple files.
I'm thinking I could create a file called common.js, list all the functions in there and just call as and when I need.
Is this a recommended approach?
The only issue I feel is having a super long file of common methods and if i seperate then I'd need to use lots of require statements.
The simplest would be to do what you have hinted to make a commonSpec.js file and use it anywhere by importTest() which would be something like this :
commonSpec.js
describe('Common Steps that will be used by all', () => {
it('Can log in', () => {
//log in code
});
it('land on a particular page', () => {
// assertion code for the particular page
});
});
commonSpecUsed.js
describe("Common Specs", () => {
importTest("common specs", './commonSpec.js');
});
The above approach is best and simple when they share the same specs and assert the same values. But when the assertions are different for e.g
A normal user will land on a simple user page
Registered user will land on their "my account" page
Admin will land on their dashboard page ..etc..etc..
Then you might want to make your commonSpec.js file more dynamic by enabling it to accept parameters. This would be entirely based on your test requirements. Can be more helpful if you could please share some code snippet.
Hope this helps.
One option is to set up Page Objects, as defined in the official docs. I also have a video covering subject on YouTube.
If you don't want to do page objects, you can add custom commands to WebdriverIO using the 'addCommand' command.

How can I access the DOM of a <webview> in Electron?

I'm just getting started with Electron, with prior experience with node-webkit (nw.js).
In nw.js, I was able to create iframes and then access the DOM of said iframe in order to grab things like the title, favicon, &c. When I picked up Electron a few days ago to port my nw.js app to it, I saw advice to use webviews instead of iframes, simply because they were better. Now, the functionality I mentioned above was relatively easy to do in nw.js, but I don't know how to do it in Electron (and examples are slim to none). Can anyone help?
Also, I have back/forward buttons for my webview (and I intend on having more than one). I saw in the documentation that I could call functions for doing so on a webview, but nothing I have tried worked either (and, I haven't found examples of them being used in the wild).
I dunno who voted to close my question, but I'm glad it didn't go through. Other people have this question elsewhere online too. I also explained what I wanted to achieve, but w/e.
I ended up using ipc-message. The documentation could use more examples/explanations for the layperson, but hey, I figured it out. My code is here and here, but I will also post examples below should my code disappear for whatever reason.
This code is in aries.js, and this file is included in the main renderer page, which is index.html.
var ipc = require("ipc");
var webview = document.getElementsByClassName("tabs-pane active")[0];
webview.addEventListener("ipc-message", function (e) {
if (e.channel === "window-data") {
// console.log(e.args[0]);
$(".tab.active .tab-favicon").attr("src", e.args[0].favicon);
$(".tab.active .tab-title").html(e.args[0].title);
$("#url-bar").val(e.args[0].url);
$("#aries-titlebar h1").html("Aries | " + e.args[0].title);
}
// TODO
// Make this better...cancel out setTimeout?
var timer;
if (e.channel === "mouseover-href") {
// console.log(e.args[0]);
$(".linker").html(e.args[0]).stop().addClass("active");
clearTimeout(timer);
timer = setTimeout(function () {
$(".linker").stop().removeClass("active");
}, 1500);
}
});
This next bit of code is in browser.js, and this file gets injected into my <webview>.
var ipc = require("ipc");
document.addEventListener("mouseover", function (e) {
var hoveredEl = e.target;
if (hoveredEl.tagName !== "A") {
return;
}
ipc.sendToHost("mouseover-href", hoveredEl.href);
});
document.addEventListener("DOMContentLoaded", function () {
var data = {
"title": document.title,
"url": window.location.href,
// need to make my own version, can't rely on Google forever
// maybe have this URL fetcher hosted on hikar.io?
"favicon": "https://www.google.com/s2/favicons?domain=" + window.location.href
};
ipc.sendToHost("window-data", data);
});
I haven't found a reliable way to inject jQuery into <webview>s, and I probably shouldn't because the page I would be injecting might already have it (in case you're wondering why my main code is jQuery, but there's also regular JavaScript).
Besides guest to host IPC calls as NetOperatorWibby, it is also very useful to go from host to guest. The only way to do this at present is to use the <webview>.executeJavaScript(code, userGesture). This api is a bit crude but it works.
If you are working with a remote guest, like "extending" a third party web page, you can also utilize webview preload attribute which executes your custom script before any other scripts are run on the page. Just note that the preload api, for security reasons, will nuke any functions that are created in the root namespace of your custom JS file when your custom script finishes, however this custodial process will not nuke any objects you declare in the root. So if you want your custom functions to persist, bundle them into a singleton object and your custom APIs will persist after the page fully loads.
[update] Here is a simple example that I just finished writing: Electron-Webview-Host-to-Guest-RPC-Sample
This relates to previous answer (I am not allowed to comment): Important info regarding ipc module for users of Electron 1.x:
The ipc module was split into two separate modules:
ipcMain for the main process
ipcRenderer for the renderer process
So, the above examples need to be corrected, instead of
// Outdated - doesn't work in 1.x
var ipc = require("ipc");
use:
// In main process.
var ipcMain = require('electron').ipcMain
And:
// In renderer process.
var ipcRenderer = require('electron').ipcRenderer
See: http://electron.atom.io/blog/2015/11/17/electron-api-changes section on 'Splitting the ipc module'

Moving created files with JXA

I'm new to JXA scripting, but I'm attempting to troubleshoot some older scripts currently in place here at work. They loop through an InDesign document and create several PDFs based on it. Previously, they would be stored in a folder called "~/PDFExports". However, this doesn't work with 10.10.
If I change the code to just place the PDFs in "~/", it works fine. From there, I'd like to move the files to "~/PDFExports", but I can't seem to find an answer on how to do that. I've seen things about making calls to ObjC, or to call Application('Finder'), but neither work - they both return undefined.
Am I just missing something basic here, or is it really this hard to simply move a file with JXA?
EDIT: Some syntax for how I'm creating the folder in question and how I'm attempting to work with Finder.
//This is called in the Main function of the script, on first run.
var exportFolder = new Folder(exportPath);
if(!exportFolder.exists) {
exportFolder.create();
}
//This is called right after the PDF is created. file is a reference to the
actual PDF file, and destination is a file path string.
function MoveFile(file,destination){
var Finder = Application("Finder");
Application('Finder').move(sourceFile, { to: destinationFolder });
alert("File moved");
}
Adobe apps have long included their own embedded JS interpreter, JS API, and .jsx filename extension. It has nothing to do with JXA, and is not compatible with it.
InDesign's JSX documentation:
http://www.adobe.com/devnet/indesign/documentation.html#idscripting
(BTW, I'd also strongly advise against using JXA for Adobe app automation as it has a lot of missing/broken features and application compatibility problems, and really isn't fit for production work.)
Here's the link to Adobe's InDesign Scripting forum, which is the best place to get help with JSX:
https://forums.adobe.com/community/indesign/indesign_scripting
You could use Cocoa to create the folder
var exportFolder = $.NSHomeDirectory().stringByAppendingPathComponent("PDFExports")
var fileManager = $.NSFileManager.defaultManager
var folderExists = fileManager.fileExistsAtPath(exportFolder)
if (!folderExists) {
fileManager.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(exportFolder, false, $(), $())
}
and to move a file
var success = fileManager.moveItemAtPathToPathError(sourceFile, destinationLocation, $());
if (success) alert("File moved");
Consider that destinationLocation must be the full path including the file name
and both sourceFile and destinationLocation must be NSString objects like exportFolder
Could it be that the folder is missing ? Could be your reference to the folder object not valid ? Any syntax to show ?
I will share some of what I learned about JXA move and duplicate methods. I am not a professional programmer just an attorney that is passionate about automation. My comments come from much trial and error, reading whatever I could find online, and A LOT of struggle. The move method does not work well with Finder. Use the System Events move method instead. The duplicate method in Finder works just fine. The duplicate method does not work well in system events. This is a modified snippet from a script I wrote showing move() using System Events.
(() => {
const strPathTargetFile = '/Users/bretfarve/Documents/MyFolderA/myFile.txt';
const strPathFolder = '/Users/bretfarve/Documents/MyFolderB/';
/* System Events Objects */
const SysEvents = Application('System Events');
const objPathFolder = SysEvents.aliases[strPathFolder];
SysEvents.move(SysEvents.aliases.byName(strPathTargetFile), {to: objPathFolder});
})();

PyBossa loading and presenting tasks

I am trying to set up a project on CrowdCrafting.org by using the PyBOSSA framework.
I followed their tutorial for project development.
The first parts seemed very clear to me, creating the project and adding the tasks worked fine.
Then I built my own HTML webpage to present the task to the users. Now the next step would be to load the tasks from the project, present them to the users, and save their answers.
Unfortunately, I don't understand how to do this.
I will try to formulate some questions to make you understand my problem:
How can I try this out? The only way seems to be by updating the code and then running pbs update_project
Where can I find documentation for PyBossa.js? I just saw (in the tutorial and on other pages) that there are some functions like pybossa.taskLoaded(function(task, deferred){}); and pybossa.presentTask(function(task, deferred){});. But I don't know how they work and what else there is. This page looks like it would contain some documentation, but it doesn't (broken links or empty index).
How do I use the library? I want to a) load a task, b) present it to the user, c) show the user his progress, and, d) send the answer. So I think I'll have to call 4 different functions. But I don't know how.
Looking at the example project's code, I don't understand what this stuff about loading disqus is. I think disqus is a forum software, but I am not sure about that and I don't know what this has to do with my project (or theirs).
As far as I understand, the essential parts of the JS-library are:
pybossa.taskLoaded(function(task, deferred) {
if ( !$.isEmptyObject(task) ) {
deferred.resolve(task);
}
else {
deferred.resolve(task);
}
});
pybossa.presentTask(function(task, deferred) {
if ( !$.isEmptyObject(task) ) {
// choose a container within your html to load the data into (depends on your layout and on the way you created the tasks)
$("#someID").html(task.info.someName);
// by clickin "next_button" save answer and load next task
$("#next_button").click( function () {
// save answer into variable here
var answer = $("#someOtherID").val();
if (typeof answer != 'undefined') {
pybossa.saveTask(task.id, answer).done(function() {
deferred.resolve();
});
}
});
}
else {
$("#someID").html("There are no more tasks to complete. Thanks for participating in ... ");
}
});
pybossa.run('<short name>');
I will try to answer your points one by one:
You can either run pbs update project or go to the project page >
tasks > task presenter and edit the code there.
I believe this link works, and there you should find the
information you want.
So, once you've created the project and added the tasks and the
presenter (the HTML you've built) you should include the Javascript
code inside the presenter itself. You actually only need to write
those two functions: pybossa.taskLoaded(function(task,
deferred){}); and pybossa.presentTask(function(task, deferred){});
Within the first one you'll have to write what you want to happen
once the task has been loaded but before you're ready to present it
to the user (e.g. load additional data associated to the tasks,
other than the task itself, like images from external sites). Once
this is done, you must call deferred.resolve(), which is the way
to tell pybossa.js that we are done with the load of the task
(either if it has been successful or some error has happened).
After that, you must write the callback for the second one
(pybossa.presentTask) where you set up everything for your task,
like the event handlers for the button answer submission and here is
where you should put the logic of the user completing the task
itself, and where you should then call pybossa.saveTask(). Again,
you should in the end call deferred.resolve() to tell pybossa.js
that the user is done with this task and present the next one. I
would recommend you to do in inside the callback for
pybossa.saveTask(task).done(callbackFunc()), so you make sure you
go on to the next task once the current one has correctly been
saved.
You can forget about that discuss code. These are only templates
provided, in which there is included some code to allow people
comment about the tasks. For that, Disquss is used, but it is up to
you whether you want to use it or not, so you can safely remove this
code.

Adding Models to Backbone.js Collection Silently Fails

I am implementing a Blog Engine as a learning exercise for a new job. I have a Backbone.js Collection class called BlogList that is composed of BlogModel objects (a BlogModel is a single post to a blog). I have a masterBlogList that keeps all blog posts in memory for the lifetime of the application (I realize this is not a realistic design, but it is part of the spec).
I have chosen to use masterBlogList to hold the canonical state of the application. All new posts, edits, etc. are persisted to the database (MongoDB) as well as masterBlogList. When I want to display a subset of the posts in masterBlogList, I copy them into a new BlogList instance and then narrow this new instance down based on search criteria. Again, I realize this might not be the best design (cloning BlogModels and BlogLists), but it is what I've got and I'd prefer not to rework it.
The problem is that copying one BlogList to another is not working. Even when the source list is non-empty, the destination list always ends up being empty. I have tried to debug this every which way with no luck. Here is the relevant portion of the BlogList source code:
// BlogList
$ (function () {
App.BlogList = Backbone.Collection.extend ({
model : App.BlogModel,
url : '/blog-entries',
comparator : function (a) {
return -(new Date (a.get ('date')));
},
populateFromMemory : function (sourceList) {
// this.reset ();
var self = this;
sourceList.each (function (postModel) {
self.add(postModel);
});
var foo = new App.BlogModel();
this.add(foo);
},
(continued...)
Even the last bit regarding foo is not working. I've also tried adding a clone() of postModel and also new App.BlogModel(postModel.toJSON()).
Any help would be extremely appreciated!
Sorry to have bothered anyone :<, but I got it working. The code actually does work as written above. The problem is that my search criteria were filtering out all of the posts, so I wasn't seeing anything. End of a long day! Thanks to those who tried to help me...

Categories

Resources