Office web add-in : Office.initialize() function - ms-office

I am struggling to understand, and don't find an example to exactly match what I am trying to achieve. Which is to have an MS Outlook ribbon bar icon, which when clicked displays a Dialogue Box. I played about with a demo, threw out superfluous functionality and got a Hello World going - but it is JQuery and I want to use to use AngularJs, to reuse much of an existing app.
Firstly, the example manifests all seem to have something like
<DesktopFormFactor>
<FunctionFile resid="functionFile" />
This seems to be for functions which are invoked when the user clicks an icon on the ribbon bar. Would I be correct to assume that I don't need that, if I just use a <script src=> tag to include an such files of functions?
My app will have only a single view, so whereas in the demo all *.js files have something like
// The Office initialize function must be run each time a new page is loaded
Office.initialize = function (reason) {
Would I be correct to assume that I need only have such call one, in the controller of my sole view?
Sorry if this seems pretty basic stuff, but all of the demos & docs seem to be close to what I want, but not exactly. Happy holidays!

Use of FunctionFile
FunctionFile specifies the source code file for operations that an add-in exposes through add-in commands(Ribbon buttons) that execute a JavaScript function instead of displaying UI.
Add-ins can decide either to display some UI in task pane or execute a javascript function in background. For UI-less add-ins, you will have to specify a FunctionFile.
In your case, FunctionFile can be ignored.
Use of Office.initialize
Office Add-ins include the Office.js library and the library expects your start-up code not to call any APIs until the library is fully loaded. There are two ways that your code can ensure that the library is loaded.
Use Office.initialize: An initialize event fires when the Office.js library is fully loaded and ready for user interaction. You can assign a handler to it.
Use Office.onReady: Office.onReady() is an asynchronous method that returns a Promise object while it checks to see if the Office.js library is fully loaded.
Examples:
Office.initialize = function () {
// Office is ready
};
Or
Office.onReady(function(info) {
if (info.host === Office.HostType.Outlook) {
// Based on host, decide what to display.
}
if (info.platform === Office.PlatformType.PC) {
// Make minor UI changes, if required.
}
});
In your case, you can use initialize/onReady once.

Related

Callback "headerContext" not working in Tabulator 5.2

Im using the headerContext-Callback on specific columns for the purpose of hiding/showing a set of additional columns. This worked fine in Tabulator 5.1.8 but somehow lost its functionality since I updated to version 5.2. Instead of calling the specified function it just opens the browsers default right-click-popup.
{title: exampleColumnGroup, columns:[
{title:"exampleAdditionalColumn", field:"xxx", visible:false},
{title:"exampleToggleColumn", field:"yyy", headerContext:headerClickfunc},
],},
Additional info: I chose to use a callback on specific columns instead of tableEvents because I couldn't get tableEvents to work in combination with ColumnGroups.
Any thoughts what im doing wrong or maybe overlooked some deprecated functionality?
edit:
i forgot to show an example of the function that should be called on rightclick:
function headerClickfunc(e, column){
e.preventDefault();
switch(column.getField()) {
case "yyy":
table.toggleColumn("xxx");
}};
Problem is, that this function is never called via headerContext:headerClickfunc since i upgraded to Tabulator 5.2
I can manage to get the function called via:
table.on("headerContext", function(e, column){
headerClickfunc(e, column);
});
but in this case the colum.getField() results in "undefined" which is somehow related to the use of a columngroup (tested it whithout the use of columngroups which works fine).
edit2:
Here is a jsfiddle of the not working Code (headerContext does nothing) with Tabulator 5.2.7
Here is a jsfiddle of the working code (headerContext calls the intended function) with Tabulator 5.1.8
The Code on both jsfiddles is exactly the same. Only difference is the version of tabulator.min.js i used as external ressource (via cdn-link in the ressoruces tab on the left).
The headerContext option, is simply a click listener, if you want to prevent the default browser context menu from opening then you need to call the preventDefault function on the event
{title:"exampleToggleColumn", field:"yyy", headerContext:function(e){
e.preventDefault() ///prevent browser context menu from opening
}},
If you were using Tabulators built in Menu System then you should be using the headerContextMenu option, not the headerClick option.
Also the 5.2 release introduced the concept of popups to allow the built in triggering of custom popup elements. Checkout the Popup Documentation for more info on these

Trigger a dialog box in background script

I have a chrome extension, where I periodically throw out an alert based on something.
The thing is that the default alert in Javascript is very ugly and I am trying to replace it with something more beautiful.
The problem is that currently the alert is triggered from the background script. Google doesn't allow us to include any external libraries in the background html.
Given this problem, how do I go about replacing the default alert with a more modern UI alert?
I was looking to replace the default alert with something like the SweetAlert.
My background.js currently looks like this:
// on some alarm trigger
function showpopup() {
console.log(" in show popuup");
console.log(Date());
alert("ugly alert");
}
I also explored the option of injecting another js file from my background file.
function showpopup() {
console.log(" in show popuup");
console.log(Date());
var s = document.createElement('script');
// added "script.js" to web_accessible_resources in manifest.json
s.src = chrome.extension.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
}
My script.js currently just calls an alert
alert("ugly alert now in script.js");
I am not able to figure out how to create my own dialog box in this javascript file script.js.
The problem is where your alert will be shown?
In an browser/OS dialog window? That's what alert() and friends do; as you see yourself, it's ugly and inflexible. In addition, it's technically challenging: it's an old mechanism that stops execution of JS code until closed, which can lead to API malfunctioning; Firefox WebExtensions specifically don't support calling this from the background page.
In the background page? By definition, it's invisible. You can add DOM nodes with an alert there, but you will not see it. Your problem isn't loading a library, your problem is where to display results.
(invisible, so no picture here!)
In the currently open tab? Hijacking an arbitrary page to show your own UI is hard, prone to break, would require draconian permissions with user warnings at install, won't always work. Wouldn't recommend.
In a fresh window? Possible (see chrome.windows API), but hardly "modern UI" at all (at least you can hide the URL bar).
In a browser action popup? Still not possible to trigger it to open in Chrome, so that's out.
The de-facto standard for informing the user about such things is the chrome.notifications API. It offers limited customization, but that's the "modern" approach considering that your extension has no UI surfaces already open at alert time.
You can insert your code into the tab content via
JS: chrome.tabs.executeScript()
CSS: chrome.tabs.insertCSS()
The second possibility would be to use a content script (content.js). But then you would have to use messaging to communicate between background.js and content.js.

Run a function from injected js

I have been going around in circles with this, so I would appreciate some help
This is what I want to achieve
User presses my extension ison
Popup appears with two buttons, 'run function a' and 'run function b'
When they press a button it runs the function in my own js file, that I have injected.
Function a for example, could be to count the number of elements of a certain type in the active tab
So, I can inject my js file on page load (this is in my contentscript.js)
var s = document.createElement('script');
s.src = chrome.extension.getURL('temp-file.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
This works, and I can see the js being excuted
But what I can do is to have a function run that is in temp-file.js
For example in the popup I have
chrome.tabs.executeScript(null, {code:"shows();"});
I get this: Uncaught ReferenceError: shows is not defined
If I enter shows(); into the console, it works as expected
I presume that the issue is all about the context. I tried various things in the popup.js page to also inject the file but nothing seemed to work
Is anyone able to point me in the right direction please
Thanks
Grant
I presume that the issue is all about the context.
You're right about it.
The file "temp-file.js" has been injected into host page, so it is now part of host page context. Extension can mess with it - since it is in different context.
Run a function from injected js
Solution:
Not sure about what you are trying to achieve. pick what suits you:
Split injected file
Code/functions you want to execute on a page - use them as contentscript.
In this case split you "temp-file.js" - part extension has execute (becomes part of contentscript) and part host page has to execute(your code snippet).
use custom event
Use custom event - generate custom event in contenscript - listen for it injected script. custom event
Your question does not say what exactly you are trying to achieve.
This is what I understood. You want to execute a function on your contentscript.js from your popup.js.
If that is the case then you can call a method on contentscript from popup.js like mentioned here https://developer.chrome.com/extensions/messaging

How can I add a bit of custom functionality to every CRM 2011 grid ribbon?

I have a small bit of custom functionality which I need to run from each and every grid ribbon in CRM 2011. The functionality is in a JS web-resource and I can attach it to a button enable rule and it all works fine.
The issue is that I need this to run on every grid in CRM, but I'm struggling to find something in the ribbon which appears on every screen. I did try attaching it to one of the buttons in the Jewel menu, but this only fires if the user clicks on the "File" tab.
Any thoughts...?
The jewel menu button is a good idea.
Add an anonymous JavaScript function to the library you are adding to the jewel button.
This will run when the library is loaded, just after the page loads:
var whatever = 30; // maybe you do not need a parameter
(function (what) {
/* Do what you need to do */
}(whatever));
If it’s on premise I‘d inject my script to the ribbon.js or global.js or some other js and ping from there.
Another option, less intrusive , is to use a resource that runs in each and every form i.e. myframewrok.js. This resource can check for the opener and inject the script to the opener dynamically.
A third options might be to ping a web service using a plug-in registered on execute or retrieve multiple messages which fire repeatedly for any grid in the system.
In the end we attached it to the "Advanced Find" button as this appeared on every ribbon that we needed the functionality on. The Jewel menu did not seem to work for us as it only fired when the user actually clicked the "File" button.

Does view.postscript() allow you to call functions loaded as output scripts?

I am using <xpScriptBlock> to store the contents of two rather long client side functions that loads an ExtJS grid. I can call the function using clientside javascript just fine.
I discovered that I need to show a different grid based on a condition in the underlining document. To reference the backend I moved the code to serverside and then tried to call the grid using view.postScript. This does not work and is the basis of my question.
Is this approach even possible? I do not wish to put all the code into the event. The functions are quite long and better kept in a script block for readability and maintainability. The functions are definitely loaded in the client, as I can manually load them using the firebug console. Perhaps I am missing something simple so I wanted to ask before changing my approach.
var typePO = document1.getItemValueString("typePO");
if(typePO == "AFS"){
view.postScript("loadGridAFS();")
} else {
view.postScript("loadGridOther();")
}
This code is in the serverside onClientLoad event of a panel. I have tried adding the 'return' keyword and it makes no difference.
UPDATE: I can't even get simple alerts to work using view.postscript(). Does this method only work in certain types of events in SSJS???
After some experimenting using a simple alert I can say that view.postScript() does NOT work everywhere.
For a test, I put the same code in an six event of the xpage. Here is an example of the code I used: view.postScript("alert('onClientLoad');"); I just changed the message to match the event.
Here are the results:
onClientLoad = nothing
beforePageLoad = XSP error
afterPageLoad = WORKS!
afterRestoreView = nothing
beforeRenderResponse = WORKS!
afterRenderResponse = nothing
I haven't tried every available event out there, but the bottom line here is that you shouldn't count on view.postscript() to work everywhere. And if it does do nothing, try a simple alert first to see of the event supports view.postscript before questioning the client javascript code you are attempting to run.

Resources