In kicking this idea around with another user I suggested a variation of this approach. What I suggested in that discussion was that numerous script triggers be attached to fields/buttons on the layouts that ran scripts when fields were entered or buttons clicked, etc. that reset the timer. Thus an active user was continually resetting the timer and the script to release a record that was open but inactive (usually, you'd commit the record), only kicks in if the timer runs down completely--and that only happens if the user leaves the record open while not doing anything with the file.
Another variation of this would be to have all such scripts update the value in a global variable by setting it with the current timestamp. The timer controlled script would then compare the timestamp in this variable with the current timestamp to compute the number of seconds between last user activity and the present. If the interval was a specified number of minutes or larger, then do what you need to do to release records back to the user base.
Add an OnObjectSave script tripper to commit the record to the popup/drop down fields and you should be go to go.
A good idea that may not always work. In some cases, that might trigger validation errors on other fields that have not yet been edited--such as a field that is set up as a required field. You can suppress that with the "skip data entry validation" option, but this might still commit an incomplete record--something that may not be desirable in all systems. So use it if it helps but carefully...
Another option, is to use a set of global fields for editing and creating new records. Data for an existing record is moved into global fields for editing and then the data is saved back to the database by a script that moves the data from the global fields back into the corresponding data fields. This keeps records from being edit locked, but in the case of editing exisitng records, you can have cases where two users edit the same record and the changes by the second user to "save" the record overwrite the changes made by the first user to "save" it.
It would work just fine. You'd get that same validation error if you chose a value from the list and committed the record by clicking on an empty part of the layout. Why should it make a difference what triggers this hypothetical validation error?
It's a simple answer that works.
The check is to determine if the user is actively typing in a field. Committing the record while they are doing that would cause the field to lose focus, and further changes typed after the commit would get lost. So we are trying to be nice to an active user.
Can you pass parameters to an 'install on timer' script? We were monkeying around with the idea of grabbing the window name when the layout is launched, and pass that to the timer script. Then have the timer script check that variable against the 'current window name'. But we seem to be losing our parameter on the timed script, i.e. Get(ScriptParameter) returns empty. (And how can we check the actual 'current' (i.e. foreground) window?)
Hmmm...based on the need of just returning the user to their current cursor position, what about using Get(ActiveField), Get(CurrentSelectionStart), and then using those to return to their position after committing the record (i.e. force commit)?
What is the context/perspective of a script running in a window that isn't the foreground window? It appears that "Get(Active...)" returns the foreground window. And from what I have read scripts are running in the context of the window that started them (unless they change windows). So how would a script running in the background window behave when the active field is a foreground window? And then how to return to that field? Maybe that script doesn't even really grab focus away? Is it running completely in the background and won't interfere with the user at all?
Just thinking out loud as we are thinking out loud. :)
You menitioned a specific problem with users making selections in drop down lists. The OnObjectSave trigger is intended to solve that.
Even if you put it on non-drop down list fields, the trigger would not fire while they were typing in a field. By definition an OnObjectSave trigger doesn't do that.
Instead of building some complex onTimer structure, I think it's worthwhile to try to prevent the user from being able to leave the record in an open state. Commiting records after a field's data changes does that. Also it sounds like new windows are launched by a button. Why not just add a commit upon new window launch?
Or...if you really want to use OnTimer, have it run as an OnFieldEnter script trigger. Give a user, say 5 minutes, then commit the record. Have an OnFieldSave trigger clear the OnTimer trigger. Technically the record isn't open onFieldEnter, but it's probably the best choice (you could even open the record as part of the script to lock others out).
@David, I agree that it's a simple answer that works. I did say it was a good answer...
It's just that there are situations where it won't so you need to consider all options before you use it. Imagine if field B comes after the drop down field in the tab order and the field is specified as a required field. With your method, the user gets hit with a validation error message every time they select a value in the drop down field with your script trigger as the field is empty and they haven't yet entered data in that other field. I don't think most users would like that result. (and there are ways to keep background clicks from committing records should that be needed)
@Justin, The method I described only commits records if the user is not actively editing the record and has not done so for a period of time you specify. Thus, there shouldn't be any cases where a user gets the record committed while they are actively editing data in a field.
As far as passing parameters to the on timer script, you can, set data in a global field or global variable and then the timer controlled script can access that data.
One other consideration is that this is part of a huge system (314 layouts to be exact). So to add a trigger to each layout/object isn't really a feasible idea at this juncture. :)
As for the script parameters to timer scripts, we wanted each parameter to be unique to that script (or nearly unique). That way the timer script could be checking what ever the active window is vs. the name of the window that launched the script. Hmm...would have to figure out how to get that first layout's name to persist, too. I guess that initial 'onlayoutentry' script doesn't persist either, so that parameter would only get passed on the first call. But that timer script needs to exist on a persistent basis somehow; wouldn't it also store any passed parameters (if they are accepted at all)? There's an entry in the system somewhere that says "run this script every XXX seconds". Doesn't it also store a passed aparameter to that script? (Our testing seems to indicate that the ontimer script doesn't get any passed parameters.) We want unique parameters because with multiple windows they would each keep overwriting each other.
So yes, I am still fixated on this timer script thing. :) It is already implemented, just in a not-quite-working-as-expected manner. We just need to figure out how to grab the right things to check if stuff is the same/different.
How often does it happen in practice? I mean the scenario where someone wants to edit a record and someone else is in it, but there's nobody home? Seeing as FM will helpfully tell you that the 'record is locked by User X' and you can call them/wander over to their desk and hit 'Enter', etc, it seems to me like the solution is comparatively a lot of effort - and does starting one Timer Script not kill any other timer scripts running? So, have you not 'used up' all your Timer-Script-lives for the whole file? If it solves the problem it would still seem like Pyrrhic victory to me.
Also, I'm surprised Phil hasn't chastised one for suggesting that developers are developing on the live file... (So that would remove another reason when the scenario may arise.) Bearing in mind also that this sleeping user is stopping folks from editing the odd record here and there, but the developers could easily stop every user working in a complete table. Or more.
Okay: it's my lazy streak again. (Although I like to think of it as merely 'Conservation of Energy'.)
@Phil You're raising imaginary objections. The OP hasn't said anything about validation or tab order or anything like that. If a developer has made a solution dependent on a user tabbing through fields I would say "don't do that". That's a bad user design choice.
@Justin You can add script triggers to all field objects just as easy as it is to add them to one object. (Click the field tool and Select All). You would have to go through all 300+ layouts, but that should take you only 2-5 hours.
If you've got a working solution, what isn't working exactly? If it's just the value list / pop up thing, the least expensive option is script triggers.
@Sorsbuster: This seems to be cropping up much more, recently. Yes, the problem is mostly associated with us Devs trying to do things on the live DB and running into users (yeah, not the best technique). The users don't seem to be experiencing any direct problems with it. However, we are not on site with the users, so we can't just walk over. And if they aren't at their desk to begin with, they aren't going to be answering their phone. (We try the built-in message thing, and that has worked a few times, but many times hasn't.)
We haven't been able to narrow it down to a specific layout, interaction, etc, that is leading to this...yet. So some of our targeting is a bit of guesswork. As far as using up the timer script, it is my understanding that there can be one (perhaps many?) for each window, even if they are the same script. We have run into evidence supporting this. (One question I posed above was about the context and instancing of these scripts.)
What about those parameters passed to timer scripts, though? It seems that what I have read vaguely indicates both ways - that you can or can't. Our tests seem to indicate that a parameter doesn't come through. So if you can, what is the trick? (Just putting it in the script call for the 'install ontimer' step is what we have tried. Not sure where else it could go.)
And also, how do you find the foreground window? There doesn't seem to be a command for finding the active window name. I have read many different things that indicate that such-and-such command references the foreground window, or that it CAN reference the foreground window, but the mechanics aren't explained. And then making that unique information persist; yeah global variables/fields could work, except that each instance of the script is going to be overwriting the same variable, so it's hard to compare that to a local instance's context.
It may not be restricted to drop-down lists. The issue could come up from other fields. I suppose any field could cause it, it is just that when they click a button the opens a new window that seems to cause the problem. (Again, some guesswork we are doing here.)
@David: adding script triggers like that kind of usurps the flexibility of the triggers, i.e. it prevents us from using triggers for other purposes. We do have some triggers around on various widgets, for specific situations.
@Phil You're raising imaginary objections.
@David, I don't care to make suggestions to folks without also pointing out cases where they don't work so that the OP can then avoid that particular pitfall if it should apply. This is the last post I will make on this argument.
I get the feeling you're married to this idea of onTimer scripts since you keep raising objections to triggers without giving thought, or asking, how to deal with the issues you're raising (having one trigger due several tasks is trivial).