Adding an image to only one node within a Tree View - asp.net-mvc-5

I'm currently working on modifying a Tree View control (Telerik MVC Extensions) for a customer request. Their request is a simple one: if an item within the tree has an Attachment, add a paperclip beside the node to identify it.
I have so far been able to do so but, found a small hiccup with this. I can add the image to certain nodes that have an Attachment, however, all nodes that don't should have no image (by that, I mean they should appear normal within the tree). Instead though, I find that the tree places a blank the size of the paperclip image.
Is there a way to dynamically turn off this blank (aka not add an Image Url if unnecessary)? Below is my code where I'm executing this process (is done on the expansion method of the tree due that only the bottom level shows the Attachments).
Navigation Controller
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult GetNextTreeViewLevel(TreeViewItem node)
{
...
//If bottom layer, then execute the following
var data = _TreeRepo.GetProcessesByParcel(int.Parse(values[1]), cntTreeList);
nodes = from item in data
select new TreeViewItem
{
Text = item.strProcess,
Value = "PR" + "," + item.cntProcess.ToString(),
LoadOnDemand = false,
Enabled = true,
Selected = SelectedSearchResult.ToString().Length > 0
&& SelectedSearchResult.ToString().Split('~').Length > 3
&& decimal.Parse(SelectedSearchResult.ToString()
.Split('~')
.Last()
.Substring(2)) == item.cntProcess
ImageUrl = item.ysnHasAttachment.HasValue && item.ysnHasAttachment.Value == 1
? #"/Content/NewImages/attachment.png"
: string.Empty
};
return new JsonResult { Data = nodes };
}
Screen shots of what it looks like without/with code for Image Url:

I at long last came up with a solution to this issue. The problem was how I was getting my data added to the nodes. The original logic was doing a Linq query after fetching the data to get an IEnumerable object.
Because of that, every node was trying to add an image (even if there was none). Hence the weird looking space. Below is how I reworked this logic to correctly get my data.
var processNodes = new List<TreeViewItem>();
var data = _TreeRepo.GetProcessesByParcel(int.Parse(values[1]), cntTreeList);
foreach (var item in data)
{
#region Process has at least one Attachment
if (item.ysnHasAttachment.HasValue && item.ysnHasAttachment.Value == 1)
processNodes.Add(new TreeViewItem
{
Text = item.strProcess,
Value = "PR" + "," + item.cntProcess.ToString(),
LoadOnDemand = false,
Enabled = true,
Selected = SelectedSearchResult.ToString().Length > 0
&& SelectedSearchResult.ToString().Split('~').Length > 3
&& decimal.Parse(SelectedSearchResult.ToString()
.Split('~')
.Last()
.Substring(2)) == item.cntProcess,
ImageUrl = "/Content/NewImages/smallAttachment.png"
});
#endregion
#region Process has no Attachments
else
processNodes.Add(new TreeViewItem
{
Text = item.strProcess,
Value = "PR" + "," + item.cntProcess.ToString(),
LoadOnDemand = false,
Enabled = true,
Selected = SelectedSearchResult.ToString().Length > 0
&& SelectedSearchResult.ToString().Split('~').Length > 3
&& decimal.Parse(SelectedSearchResult.ToString()
.Split('~')
.Last()
.Substring(2)) == item.cntProcess
}
#endregion
}
nodes = processNodes;
At this point, you can now return the nodes. Those that should have had an Attachment icon will, and those that shouldn't won't. Funny how 4 months later, you can come up with something off the cuff.

Related

CodedUI "FindMatchingControls()" works 10% of the time but usually returns about half of the controls

Problem: I am using FindMatchingControls() to create a Collection of rows in a WPF table. I have written a loop that will set the ComboBox in each row to a given value. The whole thing works sometimes but more often than not, FindMatchingControls() actually finds about half of the rows. How can I configure timeouts or change settings to make it find all 50 controls every time or perhaps to find the first 10 and then to find the next 10 etc?
Background: I am testing a WPF window and on it, there's a table, each row in the table has a drop down list. There are 50 rows and in future there could be more so it is not feasible for me to record the setting of each one, my recorded test would be out of date with each new version (every month or so).
I have therefore recorded the setting of 1 ComboBox and then I used FindMatchingControls() to create a Collection. I loop through the Collection setting each ComboBox in that collection to the desired selection. The first 23 rows are shown on my current screen resolution. The only problem is that FindMatchingControls() sometimes returns 23, sometimes 26 , sometimes 34 and sometimes it returns all 50 rows! My question is, how do I fix the code below so that it always return all 50 rows (and possibly more in future).
You can see from the code that I found the Parent control twice so pseudo code is below.
Psuedo Code:
1) Find Parent Container (table)
2) Define a row (that is a child of the parent table)
3) Use FindMatchingControls to get a Collection of Rows
4) Loop through the Collection, finding the ComboBox in each row and setting it's selection to a value passed into the method.
CODE:
public void PlaceAnOrderScreen_SelectItems_List(String item /*Value to set all 50 ComboBoxes to*/)
{
WpfControl rowOfOrderItems = new WpfControl(this.UIOptimalOrderSystemClientShWindow.UIItemCustom22.UIListViewAutoID37Table);
rowOfOrderItems.SearchProperties[WpfControl.PropertyNames.ControlType] = "DataItem";
rowOfOrderItems.SearchProperties[WpfControl.PropertyNames.ClassName] = "Uia.ListViewItem";
rowOfOrderItems.WindowTitles.Add("Order Management System");
rowOfOrderItems.Find();
rowOfOrderItems.DrawHighlight(); //Visible diagnostic
//should get a collection of 50 controls ...
//... but this is dodgy, it sometimes finds 23, 26, 34 or ocassionaly all 50 controls.
//There are 23 visible controls and the rest, you have to scroll down to see.
UITestControlCollection itemRows = rowOfOrderItems.FindMatchingControls();
int c = 0;
int i = 1;
string label = String.Empty;
foreach (var auditSelectionBox in itemRows)
{
//After the top 15 drop down selections have been made, strat scrolling down.
//This is because setting the Value for a list box that is off the screen
//causes it to complain the control is blocked...
if (c >= 15)
{
if (i >= 3) //The scroll wheel moves 3 rows at a time, so only scroll once for every 3 rows...
{
Mouse.MoveScrollWheel(-1);
i = 0;
}
}
i++;
c++;
WpfCell auditDDL1 = new WpfCell(auditSelectionBox);
auditDDL1.SearchProperties[WpfCell.PropertyNames.ColumnHeader] = "Total";
auditDDL1.WindowTitles.Add("OrderSystem 5");
//Works but takes 5 - 16 seconds per drop down list
auditDDL1.Value = item;
}
}
Instead of trying to find matching controls based on another row, you could use a method that takes the parent (in your case the table) and returns all it's children in a recursive way. It digs all the way down until all available children have been found. It shouldn't matter how much row's your table has, it will try and get all of them. It's usable for any UITestControl.
public ParentControl GetChildControls(UITestControl parentControl)
{
ParentControl parent = new ParentControl();
if (parentControl != null)
{
List<ParentControl> children = new List<ParentControl>();
foreach (UITestControl childControl in parentControl.GetChildren())
{
children.Add(GetChildControls(childControl));
}
parent.Children = new KeyValuePair<UITestControl, List<ParentControl>>(parentControl, children);
}
return parent;
}
The parent class
public class ParentControl
{
public KeyValuePair<UITestControl, List<ParentControl>> Children { get; set; }
public string Value
{
get
{
return Children.Key.Name;
}
}
}
I just added the Value property for easy access to the name of UITestControl.
PixelPlex (above) has provided the best answer. All I had to add to PixelPlex's code was an If statement to set the ComboBox to a value when it was found. The foreach is therefore as below in my case ...
foreach (UITestControl childControl in parentControl.GetChildren())
{
children.Add(GetChildControls(childControl));
//Added below If statement to set ComboBox selected item to "Carrots"...
if (childControl.ClassName == "Uia.ComboBox")
{
WpfComboBox cb = (WpfComboBox)childControl;
cb.SelectedItem = "Carrots";
}
}
This selects Carrots from my ComboBox... Everything that does not satisfy my If statement is not relevant so I don't do anything with it.

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];
}
}

Insert image into a specified location

I have a Google Apps script which replaces placeholders in a copy of a template document with some text by calling body.replaceText('TextA', 'TextB');.
Now I want to extend it to contain images. Does anybody have idea how to do this?
Thank you,
Andrey
EDIT: Just to make it clear what my script does. I have a Google form created in a spreadsheet. I've created a script which runs upon form submission, traverses a sheet corresponding to the form, find unprocessed rows, takes values from corresponding cells and put them into a copy of a Google document.
Some fields in the Google form are multi-line text fields, that's where '\r\r' comes from.
Here's a workaround I've come up with by now, not elegant, but it works so far:
// replace <IMG src="URL"> with the image fetched from URL
function processIMG_(Doc) {
var totalElements = Doc.getNumChildren();
for( var j = 0; j < totalElements; ++j ) {
var element = Doc.getChild(j);
var type = element.getType();
if (type =='PARAGRAPH'){
var par_text = element.getText();
var start = par_text.search(new RegExp('<IMG'));
var end = par_text.search(new RegExp('>'));
if (start==-1)
continue;
// Retrieve an image from the web.
var url = getURL_(par_text.substring(start,end));
if(url==null)
continue;
// Before image
var substr = par_text.substring(0,start);
var new_par = Doc.insertParagraph(++j, substr);
// Insert image
var resp = UrlFetchApp.fetch(url);
new_par.appendInlineImage(resp.getBlob());
// After image
var substr = par_text.substring(end+1);
Doc.insertParagraph(++j, substr);
element.removeFromParent();
j -= 2; // one - for latter increment; another one - for increment in for-loop
totalElements = Doc.getNumChildren();
}
}
}
Here is a piece of code that does (roughly) what you want.
(there are probably other ways to do that and it surely needs some enhancements but the general idea is there)
I have chosen to use '###" in the doc to mark the place where the image will be inserted, the image must be in your google drive (or more accurately in 'some' google drive ).
The code below uses a document I shared and an image I shared too so you can try it.
here is the link to the doc, don't forget to remove the image and to put a ### somewhere before testing (if ever someone has run the code before you ;-)
function analyze() { // just a name, I used it to analyse docs
var Doc = DocumentApp.openById('1INkRIviwdjMC-PVT9io5LpiiLW8VwwIfgbq2E4xvKEo');
var image = DocsList.getFileById('0B3qSFd3iikE3cF8tSTI4bWxFMGM')
var totalElements = Doc.getNumChildren();
var el=[]
for( var j = 0; j < totalElements; ++j ) {
var element = Doc.getChild(j);
var type = element.getType();
Logger.log(j+" : "+type);// to see doc's content
if (type =='PARAGRAPH'){
el[j]=element.getText()
if(el[j]=='###'){element.removeFromParent();// remove the ###
Doc.insertImage(j, image);// 'image' is the image file as blob
}
}
}
}
EDIT : for this script to work the ### string MUST be alone in its paragraph, no other character before nor after... remember that each time one forces a new line with ENTER the Document creates a new paragraph.

How to use content slide with RECORD objects in typoscript

On one of my sites, content (Videos) is inherited from the levels above if the content column is empty (in this case: colPos=3 / Border)
To create the output, I use
temp.myObject < styles.content.getBorder
temp.myObject {
slide = -1
}
Easy, because this is taken from a CONTENT object and slide is a built-in function.
Due to our system setup I need to do something similar with the RECORDS object. But the following typoscript doesn't work - it generates empty output:
temp.myObject = RECORDS
temp.myObject {
tables = tt_content
source.cObject = CONTENT
source.cObject {
slide = -1
table = tt_content
renderObj = TEXT
renderObj.field = uid
}
}
The same happens with this snippet:
temp.myObject = RECORDS
temp.myObject {
tables = tt_content
source.cObject = CONTENT
source.cObject {
table = tt_content
select {
pidInList.data = leveluid:-1,slide
}
renderObj = TEXT
renderObj.field = uid
}
}
[Note: The complicated source part above provides the ID of a content element from where we extract an image file from the flexform xml]
Can somebody help me to achieve a contentslide solution based on the RECORDS object?
If there are any problems understanding the questions, please ask.
CONTENT object doesn't have "slide" property.
Try simulate slide using stdWrap.ifEmpty.cObject.... for Your RECORDS object, as it could be done for slide simulation for TYPO3 3.8.x.
Example on TYPO3 wiki :
http://wiki.typo3.org/wiki/Content_Slide#Content_Sliding_in_TYPO3_3.8.x_by_TS_only

cck image disappears when making node_save

I save a node with images which is beeing filled by a service. I write the image with drupal_write_record and the pictures appear in the node already. But when - at the end of the script - I call a node_save the image disappears again.
My Code:
$file_drupal_path= $filedata['location'];
$file = new stdClass();
$file->filename = $filedata['name'];
$file->filepath = $file_drupal_path;
$file->filemime = $filedata['mime'];
$file->filesize = filesize($file_drupal_path);
$file->filesource = $filedata['name'];
$file->uid = 1;
$file->status = FILE_STATUS_PERMANENT;
$file->timestamp = time();
$file->list = 1;
// fid is populated by drupal_write_record
drupal_write_record('files', $file);
$imageData = field_file_load($file->fid, TRUE);
return $imageData;
and the node_save
function transport_service_save($node) {
$node = (object) ($node);
$node->promote = 1;
node_save(node_submit($node));
return print_r( $node , TRUE );
}
in the cck image field in the node there are keys with unset values as well.
Andreas,
Had the exact same problem.
Using drupal_execute() as described here fixed the problem immediately:
// Save the node, updated or new
// Get the node object as an array the node_form can use
$values = (array)$node;
// Save the node (this is like pushing the submit button on the node edit form)
drupal_execute('abc_node_form', $values, $node);
Source:
http://www.drupalisms.com/gregory-go/blog/use-drupalexecute-instead-of-nodesave-to-save-a-node-programmatically
But a fair warning: it ran like a charm for the first few rounds, but now I get tonnes of errors type:
warning: call_user_func_array() [function.call-user-func-array]:
First argument is expected to be a valid callback, 'node_form' was given in ...
Can't see what changed. All I did was call the page that did the saving a few times to test it.
And a final (hopefully!) edit to this reply. It seems that including the node.module file that contains node_form is needed, so adding this:
module_load_include('', 'node', 'node.pages.inc');
in your code (like in hook_init()) will do the trick.
Worked here, and now my nodes save with images intact.

Resources