Onfmready.js
A developer utility for working with the FileMaker web viewer JavaScript object in FileMaker Pro/WebDirect.
Install / Use
/learn @stephancasas/Onfmready.jsREADME
OnFMReady.js
OnFMReady is a developer utility for working with the FileMaker web viewer JavaScript object in FileMaker Pro/WebDirect. This is version 2.0 of the utility. If you're looking for version 1.0, it's here.
What happened to version 1.0?
As stated above, you can still get version 1.0 of OnFMReady here, but if you read its updated documentation or the documentation for version 2.0, I'm sure you'll agree that the newer version is much better. If you'd like to know more about what's changed, continue reading below.
Introduction
FileMaker 19 introduced new JavaScript interaction between the web viewer layout object and the FileMaker environment. Developers can call FileMaker scripts from their JavaScript code using FileMaker.PerformScript() and FileMaker.PerformScriptWithOption(). However, neither method can be immediately called, as FileMaker Pro or FileMaker WebDirect must first inject the FileMaker object for use.
OnFMReady removes the need to introduce additional JavaScript or FileMaker script logic which "waits" for injection of the FileMaker object to occur. Most importantly, it does this without requiring the developer to "wrap" their script calls inside of helper functions. Simply calling either FileMaker.PerformScript() or FileMaker.PerformScriptWithOption() will queue script execution requests, and dispatch them immediately after the FileMaker object has been injected.
:pencil: NOTE: FileMaker Pro for Microsoft Windows
During development/publishing, I finished writing this README, and then decided to test OnFMReady in FileMaker Pro for Microsoft Windows, which now uses Microsoft Edge (a Chromium-based browser) to provide the web viewer object. I haven't had a chance to pull-apart the injection logic Claris is using there, but what I do know is that the
FileMakerobject is available for use immediately. No helper is needed, but OnFMReady will still provide the utility eventsfilemaker-readyandfilemaker-expected.All this in-mind, details regarding the
FileMakerobject lifecycle, given below, apply to FileMaker Pro on macOS and FileMaker WebDirect (on all platforms, of course).
:pencil: NOTE: Microsoft Internet Explorer 11
Support for Microsoft Internet Explorer 11, which is used in FileMaker Pro prior to version 19.3, is built into the TypeScript source of OnFMReady and includes all required polyfills. This support is removed by default in the main distribution,
onfmready.jsandonfmready.min.js. If you require support for Microsoft Internet Explorer 11 in your project, useonfmready.es5.jsoronfmready.es5.min.js— generated by the commandnpm run buildornpm run build:es5.After build or installation from CDN, please send me a postcard from the year 2013, which is where I assume your project is located.
Install
To install the helper, include it as the first linked <script> in the <head> tag of your document. You may link it via CDN, or provide it as inline code:
CDN
<!-- Without Support for Obsolete Web Browsers That Won't Die -->
<script src="https://unpkg.com/onfmready.js@2.1.11/dist/onfmready.min.js"></script>
<!-- With Support for Microsoft Internet Explorer 11 -->
<script src="https://unpkg.com/onfmready.js@2.1.11/dist/onfmready.es5.min.js"></script>
:pencil: NOTE: Versioning
It is recommended that you pin a version number (shown as
@2.1.11) to prevent the introduction of potentially-breaking changes when updates are made to OnFMReady.
Inline Code
<!-- Without Support for The Browser You Used to Download Google Chrome -->
<script>
!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";(()=>{const e=window;let t,n,o=[];const i=()=>{if(!n){const t=new Event("filemaker-ready");e.dispatchEvent(t),document.dispatchEvent(t)}const t=Object.assign(new Event("filemaker-expected"),{filemaker:!n,FileMaker:!n});e.dispatchEvent(t),document.dispatchEvent(t)};if("object"==typeof e.FileMaker)return void setTimeout(i);e.OnFMReady=Object.assign({respondTo:{},noLogging:!1,unmount:!1},e.OnFMReady);const r={PerformScript:(e,t)=>r.PerformScriptWithOption(e,t),PerformScriptWithOption:(e,t,i=0)=>{n?s(e,t,i):o.push([e,t,i])}},s=(t,n,o)=>{const i=e.OnFMReady.respondTo[t];return i?i(n,o):e.OnFMReady.noLogging?null:console.log(Object.assign({script:t,param:n},o?{option:o}:{}))};let c,a,d=r;document.addEventListener("DOMContentLoaded",(()=>{(!t||t&&!t.stash)&&(d=null,a=!0),setTimeout((()=>{setTimeout((()=>{}))}))})),Object.defineProperty(window,"FileMaker",{set(e){d=e,a=!1,clearTimeout(c),null!=e&&setTimeout((()=>{const e=d,t=e?.PerformScriptWithOption||e.PerformScript;o.forEach((e=>{t(...e)})),o=[],i()}))},get:()=>t&&!t.stash&&!a&&(t.resolver(),t.stash)?null:(a&&(t=void 0,c=setTimeout((()=>{n=!0,e.FileMaker=e.OnFMReady.unmount?void 0:r}))),d)})})()}));
</script>
<!-- With Support for Microsoft Internet Explorer 11 -->
<script>
!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";!function(){var e,n=window;if(window.document.documentMode){if("function"!=typeof Object.assign&&Object.defineProperty(Object,"assign",{value:function(e,n){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),o=1;o<arguments.length;o++){var i=arguments[o];if(null!=i)for(var r in i)Object.prototype.hasOwnProperty.call(i,r)&&(t[r]=i[r])}return t},writable:!0,configurable:!0}),"function"!=typeof window.CustomEvent){function e(e,n){n=n||{bubbles:!1,cancelable:!1,detail:void 0};var t=document.createEvent("Event");return t.initEvent(e,n.bubbles,n.cancelable),Object.defineProperty(t,"detail",{value:n.detail}),t}e.prototype=window.Event.prototype,window.CustomEvent=e,window.Event=e}e={resolver:function(){try{var n=e.resolver.caller.caller.toString();e.stash=n.indexOf("if (window.FileMaker != null)")>=0}catch(n){e.stash=!1}},stash:!1}}var t,o=[],i=function(){if(!t){var e=new Event("filemaker-ready");n.dispatchEvent(e),document.dispatchEvent(e)}var o=Object.assign(new Event("filemaker-expected"),{filemaker:!t,FileMaker:!t});n.dispatchEvent(o),document.dispatchEvent(o)};if("object"!=typeof n.FileMaker){n.OnFMReady=Object.assign({respondTo:{},noLogging:!1,unmount:!1},n.OnFMReady);var r,a,c={PerformScript:function(e,n){return c.PerformScriptWithOption(e,n)},PerformScriptWithOption:function(e,n,i){void 0===i&&(i=0),t?u(e,n,i):o.push([e,n,i])}},u=function(e,t,o){var i=n.OnFMReady.respondTo[e];return i?i(t,o):n.OnFMReady.noLogging?null:console.log(Object.assign({script:e,param:t},o?{option:o}:{}))},l=c;document.addEventListener("DOMContentLoaded",(function(){(!e||e&&!e.stash)&&(l=null,a=!0),setTimeout((function(){setTimeout((function(){}))}))})),Object.defineProperty(window,"FileMaker",{set:function(e){l=e,a=!1,clearTimeout(r),null!=e&&setTimeout((function(){var e=l,n=(null==e?void 0:e.PerformScriptWithOption)||e.PerformScript;o.forEach((function(e){n.apply(void 0,e)})),o=[],i()}))},get:function(){return e&&!e.stash&&!a&&(e.resolver(),e.stash)?null:(a&&(e=void 0,r=setTimeout((function(){t=!0,n.FileMaker=n.OnFMReady.unmount?void 0:c}))),l)}})}else setTimeout(i)}()}));
</script>
Usage
OnFMReady provides both interception of calls to the FileMaker object as well an event emitter that fires once FileMaker is injected. In your own code, can make use of both or either utilities where appropriate:
Native Expression (Interception)
As stated before, OnFMReady intercepts calls to the FileMaker object, so you don't need to do anything other than use FileMaker.PerformScript() or FileMaker.PerformScriptWithOption() as you normally would. You can call either method anywhere in your code, so long as it's after the point in your document where you've installed OnFMReady.
In this way, you're able to use the web viewer as a kind of "script trigger" which calls a FileMaker script as soon as it's ready. There's no need to mess around with Pause[<duration>] script steps in your FileMaker scripts, or to introduce looping/checking logic in your JavaScript. As soon as FileMaker is injected, your script requests will automatically be fulfilled.
For example, to run a FileMaker script called Get Invoices you can simply call the following from anywhere in your code:
FileMaker.PerformScript('Get Invoices');
Event Listeners
When the FileMaker object is injected by FileMaker Pro or FileMaker WebDirect, OnFMReady will dispatch an Event, 'filemaker-ready', to window and document. You can add an event listener as you would any other:
window.addEventListener('filemaker-ready', () => {
console.log('FileMaker is ready!');
});
/*--- or ---*/
document.addEventListener('filemaker-ready', () => {
console.log('FileMaker is ready!');
});
In addition to dispatch of the filemaker-ready event, OnFMReady will also dispatch filemaker-expected with a filemaker boolean property at the point in the events cycle when FileMaker should have become available. You may leverage this event in your code to provide context in circumstances where you may be permitting access to your document both inside and outside of FileMaker, and thus wish to engage/disengage features which are exclusive to either context:
document.addEventListener('filemaker-expected', (event) => {
if (event.filemaker) {
/*--- feature enable/disable logic here ---*/
}
});
Note that if your document is being accessed from dual contexts, you should not evaluate against window.FileMaker to determine context, as OnFMReady will still have provided its fallback instance of FileMaker to the browser. Instead, make use of the utility event as shown above. In the event that you wish to remove the FileMaker object entirely when outsid
Related Skills
node-connect
350.8kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
110.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
350.8kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
350.8kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
