Why does calling the YUI Datatable showCellEditor not display the editor? - yui

Clicking on the second cell (any row) in the datatable causes the cell editor to display. But, I am trying to display the cell editor from code. The code looks like the following:
var firstEl = oDataTable.getFirstTdEl(rowIndex);
var secondCell = oDataTable.getNextTdEl(firstEl);
oDataTable.showCellEditor(secondCell);
When I debug into the datatable.js code (either with a click or from the code above) it follows the same path through the showCellEditor function but the above code will not display the editor.
I am using YUI version 2.8.0r4.

I think this is blur events issue.
So, for example, I have link that must add record to datatable, and show its editor.
var mymethod = function (e) {
YAHOO.util.Event.stopEvent(e);
var r = {};
r.id = 0;
r.value = 'hello world';
myDataTable.addRow(r);
var cell = myDataTable.getLastTrEl().cells[0];
myDataTable.showCellEditor(cell);
}
YAHOO.util.Event.addListener('mylink2addrecord_ID', 'click', mymethod);
Without stopEvent you will never see editor, because there is tableBlur event called when you click on yourlink....

You can try this - this is ONLY a snippet from a larger piece of an event handler set of code I have. EditNext is the function that moves over a cell and displays the editor, if the cell has one:
this.myDataTable.subscribe("editorKeydownEvent",function(oArgs) {
var self = this,
ed = this._oCellEditor, // Should be: oArgs.editor, see: http://yuilibrary.com/projects/yui2/ticket/2513909
ev = oArgs.event,
KEY = YAHOO.util.KeyListener.KEY,
Textbox = YAHOO.widget.TextboxCellEditor,
Textarea = YAHOO.widget.TextareaCellEditor,
DCE = YAHOO.widget.DateCellEditor,
cell = ed.getTdEl(),
col = ed.getColumn(),
row,rec,
editNext = function(cell) {
cell = self.getNextTdEl(cell);
while (cell && !self.getColumn(cell).editor) {
cell = self.getNextTdEl(cell);
}
if (cell) {
self.showCellEditor(cell);
}
},

As mac said, you need to stop the previous event. For some reason it (the tableBlur event) conflicts with the showCellEditor function. This is the first place which had a resolution to the problem.
To sum it up, all I did was:
YAHOO.util.Event.stopEvent(window.event);<br/>
dt.showCellEditor(td); // dt = yui datatable obj, td = {record: yuirecord, column: yuicolumn}
Of course if you have the event object readily available as mac's post does, you can pass it to stopEvent(e) like he did.

Related

Get the fill color of a range of cells officejs

I'm new to office.js and making add ins and I'm trying to make an add in for Excel. I've run into an issue for one thing that seems like it should be very easy, but isn't. I'm just trying to get the background color of the selected cells. From what I can tell, I'll need to loop through each selected cell and check the fill.color value individually, which is fine, except I keep getting an error when trying to read this property.
Error PropertyNotLoaded: The property 'color' is not available. Before reading the property's value, call the load method on the containing object and call "context.sync()" on the associated request context.
I don't quite understand why I would have to run the context.sync() for this, when it's already being run and I'm trying to use the code that was already generated by Visual Studio for the add in.
The error is confusing because I'm able to set the color like this without any issues. Here is the code I've added trying to get the fill color. The first line is commented out, but adds an orange fill to the selected cells no problem. I only added this to see if I could read out a value I knew was already set. I'm trying to get the user defined fill for a selected range though. The second line is where the error gets thrown.
//sourceRange.getCell(i, j).format.fill.color = "orange"; // this sets the color no problem when uncommented
$('#fa-output').append("color: " + sourceRange.getCell(i,j).format.fill.color + "<br>"); //this is where it can't get the fill color
I'm using the example that Visual Studio generates where it will randomly generate 9 cells of random numbers and highlight the highest number in the selected range. Here is the full code for this method:
// Run a batch operation against the Excel object model
Excel.run(function (ctx) {
// Create a proxy object for the selected range and load its properties
var sourceRange = ctx.workbook.getSelectedRange().load("values, rowCount, columnCount, format");
// Run the queued-up command, and return a promise to indicate task completion
return ctx.sync()
.then(function () {
var highestRow = 0;
var highestCol = 0;
var highestValue = sourceRange.values[0][0];
// Find the cell to highlight
for (var i = 0; i < sourceRange.rowCount; i++) {
for (var j = 0; j < sourceRange.columnCount; j++) {
//sourceRange.getCell(i, j).format.fill.color = "orange"; // this sets the color no problem when uncommented
$('#fa-output').append("color: " + sourceRange.getCell(i,j).format.fill.color + "<br>"); //this is where it can't get the fill color
if (!isNaN(sourceRange.values[i][j]) && sourceRange.values[i][j] > highestValue) {
highestRow = i;
highestCol = j;
highestValue = sourceRange.values[i][j];
}
}
}
cellToHighlight = sourceRange.getCell(highestRow, highestCol);
sourceRange.worksheet.getUsedRange().format.font.bold = false;
// Highlight the cell
cellToHighlight.format.font.bold = true;
$('#fa-output').append("<br>The highest value is " + highestValue);
})
.then(ctx.sync);
})
.catch(errorHandler);
You have a lot of commented out code in your code that makes it hard to read.
At any rate, this is expected behavior. You have to load() and then sync() when you want to read a property of an object in the workbook. It's the load-and-sync that brings the value of the property from the workbook to the JavaScript in your add-in so you can read it. Your code is trying to read a property that it hasn't first loaded. The following is a simple example:
const cell = context.workbook.getActiveCell();
cell.load('format/fill/color');
await context.sync();
console.log(cell.format.fill.color);
ES5 version:
const cell = context.workbook.getActiveCell();
cell.load('format/fill/color');
return context.sync()
.then(function () {
console.log(cell.format.fill.color);
});
You should also take a look at the Range.getCellProperties() method, which is a kind of wrapper around the load.

tabulator get column from custom column titleFormatter

I have a custom function that hides/shows columns in my tabulator. The column I click on is supposed to hide and several other columns are shown. I have this function working correctly from onclick on an object in a custom cell formatter, but I would like to call it from clicking on the column header. It works except that I can't seem to get a handle of the column I clicked on from column header in order to hide the column.
I'm trying to get the column object and pass it to my function so I can hide that column while I show the others. I'm open to other ways to do this.
this works (cell formatter)
var showForecastCell = function(cell, formatterParams, onRendered){
...
span.onclick = function(){showForecast(cell.getColumn())};
return span
}
this doesn't work (column titleFormatter)
var showForecastHeader = function(t,e,o,i,n){
...
span.onclick = function(){showForecast(t.getColumn())};
return span
}
Is there any way to pass the column object from clicking on the column header? otherwise, if there is a simpler way to hide the column after clicking on the header, I am open to suggestions. I must admit that javascript isn't my strongest language and if I am overlooking something basic, please let me know.
You can check this JsFiddle it hides all other columns except the one you click
for Column call backs you can check documentation here and here
const hideAllButThis = function(e, column) {
const showField = column._column.field;
const columns = column._column.table.columnManager.columns;
for (let i = 0; i < columns.length; i++) {
if (columns[i].field !== showField) {
table.hideColumn("" + columns[i].field + "")
}
}
};

Make an Entire Cell in a MigraDoc Table a Link

Is there a way in MigraDoc to make an entire table cell a link? I have a tabular table of contents, and the page number is difficult to click. I would prefer if the entire cell was clickable to navigate to a specified page. Here is an example of my code:
// Create the table within the document
var document = new Document();
var section = document.AddSection();
var table = section.AddTable();
// Create a column in the table
var column = table.AddColumn();
column.Width = "2cm";
// Create a row in the table
var row = table.AddRow();
row.Height = "1cm";
// Add a hyperlink to the appropriate page
var paragraph = row.Cells[0].AddParagraph();
var hyperlink = paragraph.AddHyperlink("MyBookmarkName");
hyperlink.AddPageRefField("MyBookmarkName");
...
// Create the bookmark later in the document
I'm afraid there is no easy way to make the whole cell clickable. I haven't tried it myself, but you can add images (visible or transparent) or text to the hyperlink.
This will make the clickable area bigger - and if you use e.g. blue underlined text there will be a visual hint that the text is clickable.
I was inspired by the answer from the PDFsharp Team to try and fill the cell with a blank hyperlink image, with text over the hyperlink. Since my ultimate goal was to actually make an entire row a hyperlink, I came up with the following solution.
First, add an additional zero-width column prior to the first column in the table that you want to be a hyperlink. Next, add a paragraph, hyperlink, and transparent 1-pixel image to each zero-width cell. Specify the image height and width to fill however many table cells you want to be a link. Also, be sure to set the font size of the paragraph containing the link to nearly zero (zero throws an exception, but images are aligned on the font baseline, so you need a very small number to prevent the paragraph from being larger than the image).
Note that a zero-width column, even with borders, does not change the apparent border width when viewing the resulting PDF. The following code illustrates my approach:
// Declare some constants
var _rowHeight = new Unit(.75, UnitType.Centimeter);
// Create the document, section, and table
var document = new Document();
var section = document.AddSection();
var table = section.AddTable();
// Format the table
table.Rows.Height = _rowHeight;
table.Rows.VerticalAlignment = VerticalAlignment.Center;
// Define the column titles and widths
var columnInfos = new[] {
new { Title = "Non-Link Column", Width = new Unit(8, UnitType.Centimeter) },
new { Title = "" , Width = new Unit(0 ) },
new { Title = "Link Column 1" , Width = new Unit(8, UnitType.Centimeter) },
new { Title = "Link Column 2" , Width = new Unit(8, UnitType.Centimeter) },
};
// Define the column indices
const int colNonLink = 0;
const int colHyperlink = 1;
const int colLink1 = 2;
const int colLink2 = 3;
// Create all of the table columns
Unit tableWidth = 0;
foreach (var columnInfo in columnInfos)
{
table.AddColumn(columnInfo.Width);
tableWidth += columnInfo.Width;
}
// Remove the padding on the link column
var linkColumn = table.Columns[colHyperlink];
linkColumn.LeftPadding = 0;
linkColumn.RightPadding = 0;
// Compute the width of the summary links
var linkWidth = tableWidth -
columnInfos.Take(colHyperlink).Sum(ci => ci.Width);
// Create a row to store the column headers
var headerRow = table.AddRow();
headerRow.Height = ".6cm";
headerRow.HeadingFormat = true;
headerRow.Format.Font.Bold = true;
// Populate the header row
for (var colIdx = 0; colIdx < columnInfos.Length; ++colIdx)
{
var columnTitle = columnInfos[colIdx].Title;
if (!string.IsNullOrWhiteSpace(columnTitle))
{
headerRow.Cells[colIdx].AddParagraph(columnTitle);
}
}
// In the real code, the following is done in a loop to dynamically add rows
var row = table.AddRow();
// Populate the row header
row.Cells[colNonLink].AddParagraph("Not part of link");
// Change the alignment of the link cell
var linkCell = row.Cells[colHyperlink];
linkCell.VerticalAlignment = VerticalAlignment.Top;
// Add a hyperlink that fills the remaining cells in the row
var linkParagraph = linkCell.AddParagraph();
linkParagraph.Format.Font.Size = new Unit(.001, UnitType.Point);
var hyperlink = linkParagraph.AddHyperlink("MyBookmarkName");
var linkImage = hyperlink.AddImage("Transparent.gif");
linkImage.Height = _rowHeight;
linkImage.Width = linkWidth;
// Populate the remaining two cells
row.Cells[colLink1].AddParagraph("Part of link 1");
row.Cells[colLink2].AddParagraph("Part of link 2");
// Add a border around the cells
table.SetEdge(0, 0, columnInfos.Length, table.Rows.Count,
Edge.Box | Edge.Interior, BorderStyle.Single, .75, Colors.Black);
The result of the above code is a document containing a table with 2 rows, 3 visible columns, where the entirety of the last two cells in the final row are a hyperlink to "MyBookmarkName". Just for reference, I did modify the PDFSharp source code according to the advice here to remove borders around hyperlinks, which looked wonky at certain zoom levels in Adobe Acrobat Reader.

AS3 call function upon clicking a line from a textfield

How do you call a different function when a line of text from a TextField/TextArea is clicked?
I already have a function which retrieves a description when any point of the TextField is clicked:
list.text = "chicken";
list.addEventListener(MouseEvent.CLICK, getter);
var descriptionArray:Array = new Array();
descriptionArray[0] = ["potato","chicken","lemon"];//words
descriptionArray[1] = ["Round and Brown","Used to be alive","Yellow"];//descriptions
function getter(e:MouseEvent):void
{
for (var i:int = 0; i < descriptionArray.length; i++)
{
var str:String = e.target.text;//The text from the list textfield
if (str == descriptionArray[0][i]) //if the text from List is in the array
{
trace("found it at index: " + i);
description.text = descriptionArray[1][i];//displays "Used to be alive".
}
else
{
trace(str+" != "+descriptionArray[0][i]);
}
}
}
It works fine, and returns the correct description.
But I want it to instead retrieve a different description depending on what line in the TextField/TextArea was clicked, like, if I used list.text = "chicken\npotato"
I know I can use multiple textfields to contain each word, but the list might contain over 100 words, and I want to use the TextArea's scrollbar to scroll through the words in the list, and if I used multiple textfields/areas, each one would have its own scrollbar, which is pretty pointless.
So, how do I call a different function depending on what line I clicked?
PS: It's not technically a different function, it's detecting the string in the line that was clicked, I just put it that way for minimal confusion.
There are a few built-in methods that should make your life easier:
function getter(e:MouseEvent):void
{
// find the line index at the clicked point
var lineIndex:int = list.getLineIndexAtPoint(e.localX, e.localY);
// get the text at that line index
var itemText:String = list.getLineText(lineIndex).split("\n").join("").split("\r").join("");
// find the text in the first array (using indexOf instead of looping)
var itemIndex:int = descriptionArray[0].indexOf(itemText);
// if the item was found, you can use the sam index to
// look up the description in the second array
if(itemIndex != -1)
{
description.text = descriptionArray[1][itemIndex];
}
}

Find value in spreadsheet using google script

Situation:
1 spreadsheet
multiple sheets
1 cell selected (may vary)
What I'd like to do is to find and set focus to the next cell in any sheet that matches the selected cell (case insensitive) upon clicking a button-like image in the spreadsheet. Sort of like a custom index MS Word can create for you.
My approach is:
- set value of the selected cell as the variable (succeeded)
- find the first cell that matches that variable (not the selected cell) (no success)
- set value of found cell as variable2 (no success)
- set the focus of spreadsheet to variable2 (no success)
function FindSetFocus()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var activecell = sheet.getActiveCell();
var valueactivecell = activecell.getValue();
//here comes the code :)
}
I have found this snippet in the following topic, but I'm having a little trouble setting the input and doing something with the output: How do I search Google Spreadsheets?
I think I can replace 'value' with 'valueactivecell', but I don't know how to set the range to search through all sheets in the spreadsheet. Also, I'd like the output to be something I can set focus to using something like 'ss.setActiveSheet(sheet).setActiveSelection("D5");'
/**
* Finds a value within a given range.
* #param value The value to find.
* #param range The range to search in.
* #return A range pointing to the first cell containing the value,
* or null if not found.
*/
function find(value, range) {
var data = range.getValues();
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].length; j++) {
if (data[i][j] == value) {
return range.getCell(i + 1, j + 1);
}
}
}
return null;
}
also found this but no luck on getting it to work on the selected cell and setting focus: How do I search for and find the coordinates of a row in Google Spreadsheets best answer, first code.
Please bear in mind that I'm not a pro coder :) If code samples are provided, please comment inline hehe.
Thanks in advance for any help.
Edit 24/10: Used the code from the answer below and edited it a bit. Now able to look through multiple sheets in a spreadsheet to find the value. The only problem with this bit is: My cell is highlighted yellow, but the cell with the value found isn't selected. See code below for hopping through sheets. I can't get my head around this :)
function SearchAndFind() {
//determine value of selected cell
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getActiveSheet();
var cell = ss.getActiveCell();
var value = cell.getValue();
//create array with sheets in active spreadsheet
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
//loop through sheets to look for value
for (var i in sheets) {
//Set active cell to A1 on each sheet to start looking from there
SpreadsheetApp.setActiveSheet(sheets[i])
var sheet = sh.getActiveSheet();
var range = sheet.getRange("A1");
sheet.setActiveRange(range);
//set variables to loop through data on each sheet
var activeR = cell.getRow()-1;
var activeC = cell.getColumn()-1;
var data = sheets[i].getDataRange().getValues()
var step = 0
//loop through data on the sheet
for(var r=activeR;r<data.length;++r){
for(var c=activeC;c<data[0].length;++c){
step++
Logger.log(step+' -- '+value+' = '+data[r][c]);
if(data[r][c]==''||step==1){ continue };
if(value.toString().toLowerCase()==data[r][c].toString().toLowerCase()){
sheet.getRange(r+1,c+1).activate().setBackground('#ffff55');
return;
}
}
}
}
}
Here is an example of such a function, I inserted a drawing in my spreadsheet representing a button which I assigned the script so it's easy to call.
I added a feature to set a light yellow background on the resulting selected cell so it's easier to see the selected cell but this is optional.
Code
function findAndSelect(){
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getActiveSheet();
var cell = ss.getActiveCell();
cell.setBackground('#ffff55');// replace by cell.setBackground(null); to reset the color when "leaving" the cell
var activeR = cell.getRow()-1;
var activeC = cell.getColumn()-1;
var value = cell.getValue();
var data = ss.getDataRange().getValues();
var step = 0
for(var r=activeR;r<data.length;++r){
for(var c=activeC;c<data[0].length;++c){
step++
Logger.log(step+' -- '+value+' = '+data[r][c]);
if(data[r][c]==''||step==1){ continue };
if(value.toString().toLowerCase()==data[r][c].toString().toLowerCase()){
ss.getRange(r+1,c+1).activate().setBackground('#ffff55');
return;
}
}
}
}
Caveat
This code only searches 'downwards', i.e. any occurrence in a row that would precede the selected cell is ignored, same for columns...
If that's an issue for you then the code should be modified to start iterating from 0. But in this case if one need to ignore the initial starting cell then you should also memorize its coordinates and skip this value in iteration.

Resources