On the app i'm currently developping,
I have several hyperlink to standard sap backend transaction such as BP, PDL and so on.
i'm opening them by means of CrossApplicationNavigation.
they open new tab.
on my main app, I implemented a button to close every tab and returning to root view.
I tried the following :
Script to close other tabs or browser
here is my code :
var oCrossAppNavigator = sap.ushell.Container.getService("CrossApplicationNavigation");
var oExtUi = oEvent.getSource().getText();
var hash = oCrossAppNavigator.hrefForExternal({
target: {
semanticObject: "ZSIMM_PDL",
action: "display"
},
params: {
"UtilitiesPDL": oExtUi
}
});
var url = window.location.href.split("#")[0] + hash;
this._oComponent = sap.ui.component(sap.ui.core.Component.getOwnerIdFor(this.getView()));
this._myModel = this._oComponent.getModel("oModelWindow");
this._myModel.setProperty("/Window", window);
sap.m.URLHelper.redirect(url, true);
},
this way, i open the new tab with my semanticObject. and I register it in my Model.
the next step is the method linked with my button :
this._myModel = this._oComponent.getModel("oModelWindow");
var aWindow = this._myModel.getData().Window;
aWindow.close();
I'm loading the window of the tab I opened.
the instruction close doesn't work it writes :
"Scripts may close only the windows that were opened by it."
what I understand in CrossApplicationNavigation is that it opened a new tab and redirect by use of sap.m.URLHelper.redirect(url, true);
does the current screen before calling the new one know which page it opens ?
and this way is there a method to close it manually ?
I found a solution which is the following :
when opening the crossApplicationnavigation, I put on memory the tab opened :
var oExtUi = oEvent.getSource().getText();
var hash = oCrossAppNavigator.hrefForExternal({
target: {
semanticObject: "ZSIMM_PDL",
action: "display"
},
params: {
"UtilitiesPDL": oExtUi
}
});
var url = window.location.href.split("#")[0] + hash;
this._oComponent = sap.ui.component(sap.ui.core.Component.getOwnerIdFor(this.getView()));
this._myModel = this._oComponent.getModel("oModelWindow");
var aWindow = this._myModel.getData().Windows;
aWindow.push(window.open(url, "_blank"));
this._myModel.setProperty("/Windows", aWindow);
and in the button method, I recall all tab and close them all this way :
this._oComponent = sap.ui.component(sap.ui.core.Component.getOwnerIdFor(this.getView()));
this._myModel = this._oComponent.getModel("oModelWindow");
//then you can iterate over them and close them all like this:
var oWindow = this._myModel.getData().Windows;
for (var i = 0; i < oWindow.length; i++) {
oWindow[i].close();
}
that way when clicking the button all other tab are closed.
Related
I added a new button to my VSCode, such that when I click it - it compiles the current folder, and shows dialog boxes using vscode.window.showInformationMessage.
Each box shows a compilation error, and has a button in it. Once the user clicks the button - it opens the problematic file in a tab using vscode.workspace.openTextDocument.
I want to make the button to also navigate me to the problematic line in the problematic file.
My question is:
Given a number, is it possible to navigate to a specific line number inside a file?
Sample code of what I achieved so far:
// Bullshit to give some context
const pattern = /(In \w+.jack)/g;
var i = s.search(pattern);
var substring = s.substring(i + 1)
var j = substring.search(pattern);
var s = "bsadsdbla In main.jack (line 55) sqdwqe blasdsd wq qqweq"
let GoToFile = 'Go to File';
var k = s.search(/(\w+.jack)/);
var l = s.search(/(.jack)/)
var fileName = s.substring(k, l);
// ---------> This is the important part <----------------
vscode.window.showInformationMessage(s.substring(i, j), GoToFile).then(selection => {
if (selection === GoToFile) {
vscode.workspace.openTextDocument(currentDirectory + '\\' + fileName + '.jack')
.then(document => vscode.window.showTextDocument(document));
}
});
I am assuming you have some code/regex in place that gives you the line number. Whenever someone clicks your GoToFile method invoke the following code :
activeEditor.selections = [new vscode.Selection(lineToGo, lineToGo)];
var range = new vscode.Range(lineToGo, lineToGo);
activeEditor.revealRange(range);
Some background:
As #rioV8 mentioned, revealRange was the way to go, but the problem was that I couldn't understand how to use it using the VSCode API, so here #Shahriar Hossain came into the picture. #Shahriar Hossain's code works, however, there was an important declaration missing, and I also had to figure out how to run the code when the user clicks the button.
This is the full solution:
vscode.window.showInformationMessage(s.substring(i), GoToFile).then(selection => {
if (selection === GoToFile) {
vscode.workspace.openTextDocument(currentDirectory + '\\' + fileName + '.jack')
.then(document => vscode.window.showTextDocument(document))
// Whatever code inside this "then" block
// will be executed on button click
.then(x => {
let m = s.substring(i, j).search(/\(line \d+\)/);
let subStr = s.substring(m + 6);
let n = subStr.search(/\)/);
subStr = subStr.substring(0, n);
let lineToGo = parseInt(subStr.match(/\d+/));
// The missing declaration of the activeEditor
let activeEditor = vscode.window.activeTextEditor;
let range = activeEditor.document.lineAt(lineToGo - 1).range;
activeEditor.selection = new vscode.Selection(range.start, range.end);
activeEditor.revealRange(range);
})
}
});
i need to build the page by binding aggregation as below
view
<NavContainer
id="navCon"
class="navContainerControl sapUiSmallMarginBottom" height="50%">
</NavContainer>
controller
onInit : function()
{
var navCon = this.getView().byId("navCon");
navCon.bindAggregation('pages',{
path:'/pages',
factory : jQuery.proxy(this.createPages,this)
});
}
createPages : function(sid,context)
{
var eachpageData = context.getObject();
var grid = new sap.ui.layout.Grid({
defaultSpan:"L4 M6 S6"
});
var page = new sap.m.Page({
id : eachpageData.name,
title : eachpageData.name,
content : grid
});
grid.bindAggregation('content',{path:'data',factory :this.createPageContent});
return page;
},
But when i see from the debugger it has only one page
But when i call navto
handleNav : function(evt)
{
var navCon = this.getView().byId("navCon");
var target = evt.getSource().getText();
if (target) {
//var animation = this.getView().byId("animationSelect").getSelectedKey();
navCon.to(this.getView().byId(target));
} else {
navCon.back();
}
}
and if i see the navCon.getPages() will give 2 pages.
What mistake i have done here?
You are trying to pass the DOM element to the NavContainers.to(DOM) method. This is where its gone wrong.
But NavContainers.to() method can accept id(String) as parameter.
Change your handleNav method as follows it will work.
handleNav : function(evt)
{
var navCon = this.getView().byId("navCon");
var target = evt.getSource().getText();
if (target) {
navCon.to(target);
} else {
navCon.back();
}
}
NavContainers can display only one page. You can add more pages to the pages aggregation, but they will be visible only if a navigation event is fired with the proper parameters. After that, the layout of the new page is loaded and added to the DOM.
In case of SplitApp, application can display two pages (master and detail) if you see it on tablet or desktop; however it's implemented by the use of two NavContainers.
That's why the control inspector returns with one page before the navigation, second page is not part of the DOM until you navigates to it.
If you place a breakpoint into your code instead of using the control inspector, you can call the navCon.getPages() which should return with the number of pages in the aggregation.
In my firefox sdk addon, I want to use a custom webpage from my data directory as my settings/about page.
But I am having trouble keeping tabs on the tab!
So I have a button that calls the OptionsPanel() function to open my webpage in a new tab. Now, I want to make it so if the user forgets that tab is open and pushes the button again, that it activates the already-open settings tab. That means I need to know that the tab is open and I need to be able to switch to it if it is OR open it if it is not already open.
Here is what I've come up with so far, but it doesn't work; it just always opens a new tab. I don't even know if I'm barking up the right tree.
const tabs = require("sdk/tabs");
var optionsTab;
function OptionsPanel(){
var opsTab = GetTabByID(optionsTab.id);
if(opsTab == null){
tabs.open( data.url("OptionsPanel.html") );
optionsTab.id = tabs.tab.id; <======errors out as undefined
}else{
opsTab.activate();
}
}
//return a handle to the tab that matches specified tab id
function GetTabByID(whatid){
for(let thistab of tabs){
if(thistab.id = whatid){
return thistab;
}
}
return null;
}
So, here are my goals:
Open my page in a new tab if it isn't already open.
If the tab is already open, then switch to that tab.
If the page is open when the browser loads, then be ready to switch to that tab if the user pushes the options button.
Why would you think tabs module has a tab property?
Normally you would use the activeTab property instead. However it does not get updated immediately after tabs.open is called. One has to use tabs[tabs.length - 1] instead.
const tabs = require("sdk/tabs");
var optionsTabId;
function OptionsPanel(){
var opsTab = GetTabByID(optionsTabId);
if (opsTab == null) {
tabs.open( data.url("OptionsPanel.html") );
optionsTabId = tabs[tabs.length - 1].id;
} else {
opsTab.activate();
}
}
Additionally, you made a mistake in GetTabByID.
//return a handle to the tab that matches specified tab id
function GetTabByID(whatid){
for(let thistab of tabs){
if(thistab.id == whatid){ // use == to compare
return thistab;
}
}
return null;
}
Keep in mind this assumes that it is not possible to navigate away from your options tab. I would check optsTab.url just in case.
Alternatively you could make use of the tab event interface
const tabs = require("sdk/tabs");
const OPTIONS_URL = data.url("OptionsPanel.html");
var optionsTab = null;
function OptionsPanel(){
if (optionsTab == null) {
tabs.open(OPTIONS_URL);
tabs.once('ready', function(tab) {
optionsTab = tab;
optionsTab.on('ready', function readyListener(tab) {
if (tab.url !== OPTIONS_URL) {
optionsTab.off('ready', readyListener);
optionsTab = null;
}
})
optionsTab.once('close', function(tab) {
optionsTab = null;
})
});
} else {
optionsTab.activate();
}
}
I have this google app script which should
show file upload dialog
store file in google drive
write the url of the file into the current cell
All goes well except step 3, where the cell updated is always cell A1 in the first sheet. But the cursor is on sheet #3 on another cell.
function onOpen(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var menuEntries = [];
menuEntries.push({name: "File...", functionName: "doGet"});
ss.addMenu("Attach ...", menuEntries);
}
function doGet(e) {
var app = UiApp.createApplication().setTitle("Attach file to sheet");
var form = app.createFormPanel().setId('frm').setEncoding('multipart/form-data');
var formContent = app.createVerticalPanel();
form.add(formContent);
formContent.add(app.createFileUpload().setName('thefile'));
formContent.add(app.createSubmitButton('Submit'));
app.add(form);
SpreadsheetApp.getActiveSpreadsheet().show(app);
return app;
}
function doPost(e) {
var fileBlob = e.parameter.thefile;
var doc = DocsList.getFolderById('0B0uw1JCogWHuc29FWFJMWmc3Z1k').createFile(fileBlob);
var app = UiApp.getActiveApplication();
var label = app.createLabel('file uploaded successfully');
var value = '=hyperlink("' + doc.getUrl() + '","' + doc.getName() + '")'
app.add(label);
app.close();
SpreadsheetApp.getActiveSheet().getActiveCell().setValue(value);
return app;
}
I tried SpreadsheetApp.getActiveSheet().getActiveCell().setValue(value); outside of the doPost() function and this works when called in a normal context. What am I missing here?
judging from this answer, it is not possible to get the current spreadsheet/cell from the doPost function, the way I got it working is to get it in the doGet function via hidden fields and pass it via the form. Full blown working example here.
I'm looking for simple code that adds a popup in my Google Apps Script Ui that comes up when I hit a submit button. The popup box would display a message and have a button to close the popup.
I've looked all over the place - everything seems so complicated and does way more than I need it to do.
This is the current code I have for the submit button.
function doGet() {
var app = UiApp.createApplication();
app.setTitle("My Logbook");
var hPanel_01 = app.createHorizontalPanel();
var vPanel_01 = app.createVerticalPanel();
var vPanel_02 = app.createVerticalPanel();
var vPanel_03 = app.createVerticalPanel();
var submitButton = app.createButton("Submit");
//Create click handler
var clickHandler = app.createServerHandler("submitData");
submitButton.addClickHandler(clickHandler);
clickHandler.addCallbackElement(hPanel_01);
////Test PopUp Panel
var app = UiApp.getActiveApplication();
var app = UiApp.createApplication;
var dialog = app.createDialogBox();
var closeHandler = app.createClientHandler().forTargets(dialog).setVisible(false);
submitButton.addClickHandler(closeHandler);
var button= app.createButton('Close').addClickHandler(closeHandler);
dialog.add(button);
app.add(dialog);
//////
return app;
}
Since UiApp is depreciated, HTMLService should be used to create custom user interfaces.
To prompt simple popup to display a message, use alert method of Ui class
var ui = DocumentApp.getUi();
ui.alert('Hello world');
will prompt simple popup with hello world and an ok button.
To display customized html template in Dialog, use HTMLService to create template and then pass it to showModalDialog method of Ui Class
var html = HtmlService.createHtmlOutput("<div>Hello world</div>").setSandboxMode(HtmlService.SandboxMode.IFRAME);
DocumentApp.getUi().showModalDialog(html, "My Dialog");
HtmlService.createHtmlOutputFromFile allows you to display html that is in a separate file. see the documentation
Have you tried using zIndex? It places the panel above all of your other panels...
var popupPanel = app.createVerticalPanel().setId('popupPanel')
.setVisible(false)
.setStyleAttribute('left', x)
.setStyleAttribute('top', y)
.setStyleAttribute('zIndex', '1')
.setStyleAttribute('position', 'fixed');
x = panel position from the left portion of your app
y = panel position from the top portion of your app
zIndex = the 'layer' your panel will appear on. You can stack panels using '1', '2', '3' etc.
position = your panel will be in a fixed position denoted by (x,y)
Visibility is set to false until you click submit, then have a client handler for your submit button make the popupPanel visible. When you click the button on your popupPanel, have the client handler set visibility to false once again and it will disappear.
One more thing, I noticed you get the active app and then create a new app. You do not need to create a new app...just new panels inside your app.
Hope this helps!
You can use a dialogbox to popup.
Add a button to the dialog-box. Add a client handler that sets the dialog box invisible,once you click the button.
var app = UiApp.createApplication;
var dialog = app.createDialogBox();
var closeHandler = app.createClientHandler().forTargets(dialog).setVisible(false);
var button= app.createButton('Close').addClickHandler(closeHandler);
dialog.add(button);
app.add(dialog);
This should help.
EDIT
Added "()" after .createClientHandler. That should remove issues related to TypeError: Cannot find function createDialogBox in object function createApplication() {/* */}
Popup - use something like this:
var table = app.createFlexTable();
table.setStyleAttribute("position", "absolute");
table.setStyleAttribute("background", "white");
add items to the table and hide and show as needed.