SkillAgentSearch skills...

Onfmready.js

A developer utility for working with the FileMaker web viewer JavaScript object in FileMaker Pro/WebDirect.

Install / Use

/learn @stephancasas/Onfmready.js
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

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 FileMaker object is available for use immediately. No helper is needed, but OnFMReady will still provide the utility events filemaker-ready and filemaker-expected.

All this in-mind, details regarding the FileMaker object 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.js and onfmready.min.js. If you require support for Microsoft Internet Explorer 11 in your project, use onfmready.es5.js or onfmready.es5.min.js — generated by the command npm run build or npm 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

View on GitHub
GitHub Stars45
CategoryDevelopment
Updated1mo ago
Forks8

Languages

TypeScript

Security Score

95/100

Audited on Mar 7, 2026

No findings