How to check element rectangle by id in Elm? - javascript

I would like to check position and dimensions of some element (knowing its id) in Elm, without using JS if it's possible. There is package for DOM (http://package.elm-lang.org/packages/debois/elm-dom/latest/DOM), but there are no examples of usage and I am confused with it.
Understanding the Elm nature I would keep this rectangle as something like Maybe (Int, Int, Int, Int) in my model and update it probably by some subscription or port.
What is the simplest way to achieve it?

The debois/elm-dom package will only give you information about the current event (e.g. you could click a button and find out its dimensions). If you want to get information on an arbitrary DOM element given an ID, you will have to use ports.
This is by design: Any time you need to query the DOM, you are no longer within the purity of Elm; you are querying something that has side effects, and that needs to go through the Cmd and Sub ports to allow custom javascript. You will need two ports: One to send the request to the DOM and the other to return the results back from javascript to Elm.
port fetchBoundingClientRect : Id -> Cmd msg
port setBoundingClientRect : (Maybe BoundingClientRect -> msg) -> Sub msg
Your javascript could look something like this:
var app = Elm.Main.embed(document.querySelector('main'))
app.ports.fetchBoundingClientRect.subscribe(function(id) {
var entity = document.getElementById(id);
app.ports.setBoundingClientRect.send(entity ? entity.getBoundingClientRect() : null);
});
This is just a simplified example. You can see it on ellie-app.com. In the real world you would probably want to retain more information, like including the ID of the element on the incoming subscription (in case you query multiple elements and need to keep track of which one is queried).

Related

Mirth channelMap in source JavaScript

In my source connector, I'm using javascript for my database work due to my requirements and parameters.
The end result is storing the data.
ifxResults = ifxConn.executeCachedQuery(ifxQuery); //var is declared
I need to use these results in the destination transformer.
I have tried channelMap.put("results", ifxResults);.
I get the following error ReferenceError: "channelMap" is not defined.
I have also tried to use return ifxResults but I'm not sure how to access this in the destination transformer.
Do you want to send each row as a separate message through your channel? If so, sounds like you want to use the Database Reader in JavaScript mode. Just return that ResultSet (it's really a CachedRowSet if you use executeCachedQuery like that) and the channel will handle the rest, dispatching an XML representation of each row as discrete messages.
If you want to send all rows in the result set aggregated into a single message, that will be possible with the Database Reader very soon: MIRTH-2337
Mirth Connect 3.5 will be released next week so you can take advantage of it then. But if you can't wait or don't want to upgrade then you can still do this with a JavaScript Reader:
var processor = new org.apache.commons.dbutils.BasicRowProcessor();
var results = new com.mirth.connect.donkey.util.DonkeyElement('<results/>');
while (ifxResults.next()) {
var result = results.addChildElement('result');
for (var entries = processor.toMap(ifxResults).entrySet().iterator(); entries.hasNext();) {
var entry = entries.next();
result.addChildElement(entry.getKey(), java.lang.String.valueOf(entry.getValue()));
}
}
return results.toXml();
I know this question is kind of old, but here's an answer just for the record.
For this answer, I'm assuming that you are using a Source connector type of JavaScript Reader, and that you're trying to use channelMap in the JavaScript Reader Settings editing pane.
The problem is that the channelMap variable isn't available in this part of the channel. It's only available in filters and transformers.
It's possible that what you want can be accomplished by using the globalChannelMap variable, e.g.
globalChannelMap.put("results", ifxResults);
I usually need to do this when I'm processing one record at a time and need to pass some setting to the destination channel. If you do it like I've done in the past, then you would first create a globalChannelMap key/value in the source channel's transformer:
globalchannelMap.put("ProcID","TestValue");
Then go to the Destinations tab and select your destination channel to make sure you're sending it to the destination (I've never tried this for channels with multiple destinations, so I'm not sure if anything different needs to be done).
Destination tab of source channel
Notice that ProcID is now listed in the Destination Mappings box. Click the New button next to the Map Variable box and you'll see Variable 1 appear. Double click on that and put in your mapping key, which in this case is ProcID.
Now go to your destination channel's source transformer. There you would enter the following code:
var SentValue = sourceMap.get("ProcID");
Now SentValue in your destination transformer has whatever was in ProcID when your source channel relinquished control.

Listening for changes on Firebase

I have the following structure on my firebase database:
{
"gateways_pr" :{
"gateway_1":{
"avisos" : {
"00":{
"aviso_1" : "0",
"aviso_2" : "0"
},
"01":{
"aviso_1" : "0",
"aviso_2" : "0"
}
}
}
}
}
I have a small demo javascript webPage that is listening to child_change in gateways_pr/gateway_1/avisos:
var gateWayRef = firebase.database().ref("gateways_pr/gateway_1/avisos");
gateWayRef.on('child_changed',function(data){
console.log("CHILD_CHANGE");
console.log(data.val());
var datos = data.val();
console.log(datos);
});
When I changed for example gateway_1/avisos/00/aviso_1 and set it to 2 I can track the change with chrome developer tools looking into the frames of the websocket and I receive:
{"t":"d","d":{"b":{"p":"gateways_pr/gateway_1/avisos/00/aviso_1","d":"2"},"a":"d"}}
So I´m only receiving the change made.
The problem is that, on my code, data.val() has the following value:
{aviso_1: "2", aviso_2: "0"}
Calling data.ref.path.toString() returns :
/gateways_pr/gateway_1/avisos/00
That means that the Firebase API shows you everything below the children that had it´s property changed (00 in this case).
it´s there anyway of knowing what was the change (in this case should return "aviso_1")?
The only workaround I´ve found so far is making my code to listen on every child. In this case I should listen to gateways_pr/gateway_1/avisos/00 and gateways_pr/gateway_1/avisos/01, but if I add new entries to "avisos" I should start listening to them too, and at the end my program could end listening to thousand of referecenes.
When you attach a child_changed listener to gateways_pr/gateway_1/avisos, you're asking the Firebase client to inform you when something changes in a child under that level. If something changes on a lower level, the Firebase client will raise the child_changed event on the level that you registered for. There is no way to change this behavior.
When you have the need to know precisely what changed under the listener, it typically means that you've modeled the data wrong for your use-case.
For example: if you want to listen for changes across the entire hierarchy, you should model a list of changes across the entire hierarchy and then attach a listener to that list. This is one of the many reasons that the Firebase documentation recommends keeping flat data structures.

Firebase get all values of specific key

I have a users table on Firebase and each user has an email prop.
Structure looks like:
Users -> User UID (looks like n8haBbjgablobA2ranfuabu3aaaga2af) -> User Obj which includes email prop.
I'd like to get an array of all the users' emails (~1m).
How can I most efficiently do this?
Ps.:
I tried:
usersRef.startAt(0).endAt(20).once("value", function(snapshot) {
console.log('FIRST 20');
console.log(snapshot.val()); // null
});
But that fails.
Probably the most efficient approach in terms of data reads would be to denormalize your data. You could store the email addresses both in the individual user nodes and in an emailAddresses node. Then you could just query the emailAddresses node directly for your list of emails.
Still ~1m email address nodes would probably be too much all at once. I'd probably grab it in chunks... I'm guessing.
Update
"Grabbing in chunks" is essentially pagination. I would try to use something off the shelf before trying to roll my own pagination solution.
Pagination libraries to check out:
Firebase Utils Pagination: This is developed by Firebase, but they say it is experimental and not ready for production use. But, it's probably still worth messing around with.
firebase-paginator: this is developed by a community member and it seems pretty solid.
If you want to roll your own pagination, check out:
#kato's response in this StackOverflow answer He makes an interesting point about the potential problem with paginating a real time data set, but then provides some good starter code
Here's a good blog entry that talks about the code that I think is a part of the firebase-paginator library I linked to above
Everybody in their answers said that it was an easy thing, yet had no working solutions. Here's what I came up with:
usersRef.orderByChild('uid').limitToFirst(100).once('value', function (snapshot) {
var users = snapshot.val()
var uids = Object.keys(users);
var lastUid = uids[uids.length - 1];
// could be another property than uid, for example email, or username. Ps.: Consider that the last ID from the previous chunk will be duplicated.
usersRef.orderByChild('uid').startAt(lastUid).limitToFirst(100).once('value', function (snapshot) {
var users = snapshot.val()
var uids = Object.keys(users);
console.log(uids);
var lastUid = uids[uids.length - 1];
// re-run function until done
})
})
Since this is a one-time deal, an option is to simply iterate over each node in the parent 'data' node capturing the child data, stripping out the email address and dumping that to a file.
the event you want is
child_added: retrieve lists of items or listen for additions to a list
of items. This event is triggered once for each existing child and
then again every time a new child is added to the specified path. The
listener is passed a snapshot containing the new child's data.
and the code to iterate all of the child nodes in the data node is
var dataRef = firebase.database().ref('myRootRef/data');
datRef.on('child_added', function(data) {
//data.val() will contain the child data, such as the email address
//append it to a text file here (for example), save to disk etc.
});
The key here is that this event is triggered once for each child, similar to iterating over all of the indexes in an array.
This will retrieve each child and present it to your app, one child at a time, iterating over all the children within the node.
It's going to take a while with that many nodes to chew through.

Find all class and id names in an Ace Editor HTML script

What I'm trying to do:
Collect all the class and id names in an Ace Editor html script.
Right now my plan is to detect user changes (.on('change'...)) and get the current token using the cursor position. If the token is a not 'unquoted' 'attribute-value' type, I want to iterate back through previous tokens in order to find the 'attribute-name' type token to which that 'attribute-value' belongs and identify whether it is a class or id (I can't just detect the creation of an 'attribute-name' token because the user can go back and change the attribute-values later without changing the name, and I need to detect those changes).
I can do everything except for get previous tokens. I looked up some documentation and the TokenIterator is supposed to be able to do that, but when I try to do something like var iter = new TokeIterator(), my console says that TokenIterator is undefined. I've searched google over and over, but found no results. If the truth is out there I'm obviously not using the right words to find it, but they're the only words I've got.
Is some way built into Ace to iterate through tokens? I know I'm not seeing all the properties and methods on the editor instance object when I console log it, because I can use methods in my script that I can't see in that log. Is there one there that does what I want?
If not, how do I load the TokenIterator? I think something similar went on when I tried to use SnippetManager a while back and it turned out I actually had to do this to make it work:
var tillPageLoaded = setInterval(function() { // Makes sure page doesn't load forever on startup
if( document.readyState === 'complete') {
clearInterval(tillPageLoaded);
ace.config.loadModule('ace/ext/language_tools', function () {
editor.insertSnippet( myString );
});
}
}, 5);
Is this the same kind of situation? If so, what needs to be in .loadModules(...)? Do I need to reference a script somewhere? Does it need to be loaded some other way?
Is there built in functionality for Ace that would already do everything I want?
Other than that, if anyone has any better ideas of how to go about this with Ace, those would be very welcome.
you can get TokenIterator by using
var TokenIterator = ace.require("ace/token_iterator").TokenIterator
see https://github.com/ajaxorg/ace/blob/master/lib/ace/mode/folding/xml.js#L38 for an example of its usage.

JQuery ()load in a specific page?id=# number

I have the following problem: I need to have multiple private chatrooms per user.
I managed it to make it work but if there is more than one private chat ongoing on the same moment, the appended content of these chats are broadcasted to all private chatrooms.
function RefreshPrivate(userid)
{
var string_url = "./functions/ShowMessagePrivate.php?id=" + userid;
var page_url = "private.php?id=" + userid ;
$("#chatPrivateBody").append($("<div>").load(string_url));
}
The problem happens because of the $("#chatPrivateBody"),every private.php has that <div>, what I was thinking was that if I can append the string_url to page_url specific <div>
e.g $(page_url,"#chatPrivateBody") but there's nothing for this in the documantation of jQuery.
You mention "every private.php". So I assume you have multiple instances of this page loaded up on the same page at the same time, which either means that each one is loaded into some container via AJAX, or each one is in an iframe. You haven't really specified what you do with page_url.
I assume you're loading the pages via AJAX. If that's the case, each private chatroom gets loaded into a separate container (probably a <div>).
And each container will probably have a unique id (probably something like chatroom-<userid>).
If this is true, then you can target the #chatPrivateBody within the specific chatroom you're looking for:
$('#chatroom-'+ userid)
.find('#chatPrivateBody')
.append($("<div>").load(string_url));

Categories

Resources