How to revert the changes in text file, if "Save & Close" on a page is not clicked? - tridion

I am passing the page id component id and template id to a aspx page as querystring with this java script:
var masterTabControl = $controls.getControl($("#MasterTabControl"),
"Tridion.Controls.TabControl");
p.compPresTab = masterTabControl.getPage("ComponentPresentationsTab");
p.selectedComponentPresentation = p.compPresTab.getSelectedComponentPresentation();
p.selectedComp = p.selectedComponentPresentation.getComponentId();
window.open("http://" + location.hostname + ":path/test.aspx?pgId=" + pageId +
"&comId=" + p.selectedComponentPresentation.getComponentId() +
"&comTmpId=" +
p.selectedComponentPresentation.getComponentTemplateId(),
"myWindow", "status = 1,
toolbar=no,width=300,height=200,resizable=no,scrollbars=yes");
Now on the test.aspx page i am reading the id and with some additional information from the user i am saving it into a text file.
On a button click on popup test.aspx page i am saving it in text file:
sLogDetails = PageId + "| " + ComponentId + "|" + ComponentTemplateId +
"|" + text ;
//Move the contents to the temp file other than the existing one.
using (var sr = new StreamReader(permanentFile))
{
using (var sw = new StreamWriter(#"" + tempFile , true))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string[] parts = line.Split('|');
PageId = parts[0].Trim();
ComponentId = parts[1].Trim();
ComponentTemplateId = parts[2].Trim();
//Check there exist same record already
if (SPageId != PageId.Trim() || SComponentId != ComponentId.Trim()
|| SComponentTemplateId != ComponentTemplateId.Trim())
sw.WriteLine(line);
}
//Delete the Permanent file & create permanent file from temporary file
File.Delete(permanentFile);
File.Move(tempFile, permanentFile);
// Insert changes to the Permanent file
using (StreamWriter w = File.AppendText(permanentFile))
{
// Close the writer and underlying file.
w.WriteLine(sLogDetails);
w.Flush();
w.Close();
}
If the id is already present in the text file then i am populating it in the text field on popup test.aspx page like :
using (StreamReader r = File.OpenText(strPath + "Log.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
// Console.WriteLine(line);
string[] parts = line.Split('|');
PageId=parts[0].Trim();
ComponentId = parts[1].Trim();
ComponentTemplateId = parts[2].Trim();
//If there exist a record populate the data fields
if (SPageId == PageId.Trim() && SComponentId == ComponentId.Trim()
&& SComponentTemplateId == ComponentTemplateId.Trim())
{
txtRuleName.Text = (string)parts[3];
}
}
r.Close();
}
Now I am getting stuck here. When it's populating in the text field, user can edit the text area in popup test.aspx page and on click of ok it will get saved in text file. And if user is closing the page window without "save & Close", then the changes made by him in text field should not get saved in text file. It should revert back to old one.
Any idea how can i make it?

It is fairly difficult to respond to "something that didn't happen".
So is there any way you can create a list of other ways that the user can exit that Window? With that list you can register the relevant event handlers (or override the relevant commands) and implement your roll back there.
Alternatively you can consider making the change to the file in a temporary location from your popup. And then only commit it to your text file when the user clicks Save and Close.
Note that his file-based approach will start failing when you scale out your Tridion GUI and Content Manager to run on multiple machines. In general you should be wary of storing things in files on a server, when you are working on enterprise level software. What is a single server now (and will always be a single server in your development environment) will turn into multiple servers at some point in the future at which time your solution will cause problems.

Related

Boolean search using Google AppMaker

I am creating an app using Google AppMaker and wish to create a boolean search option (text box where I can use AND/OR options to search multiple combinations of strings). This is similar to how I can search currently on Gmail or LinkedIn etc. How can I create it?
Here is one way to accomplish this:
Make a new datasource for the model you want to search in.
Select Query Script as the query type.
Add a string parameter called searchCriteria
Add a bunch of parameters called parameter0, parameter1, parameter2, etc.
Enter this code as the Server Script (assuming the field you want to search in is called Name):
var searchCriteria = query.parameters.searchCriteria;
if(searchCriteria === null) return query.run();
var searchArray = searchCriteria.split(/( and | or )/i);
var searchString = '';
for(var i = 0; i < searchArray.length; i++){
if(i % 2 === 0 ){
searchString += 'Name contains :parameter' + i.toString() + ' ';
query.parameters['parameter' + i.toString()] = searchArray[i];
}else{
searchString += searchArray[i];
}
}
query.where = searchString;
return query.run();
Then on your page bind the text box you want to search with to #datasource.query.parameters.searchCriteria
Finally modify the onValueEdit of the search box to Reload Datasource
This technique is limited by how many numbered parameters you create and doesn't allow using parenthesis.

Custom button "Mark as Complete and New" on Phone Call form or other activity form in CRM 2013

Sometimes there is a need to have one button which will automatically complete and create a new phone call where some data from the old one are transfered to new one, there is a solution. It is also possible to implement this behaviour on other forms.
Download the Visual Ribbon Editor for CRM 2011/2013 from ​http://crmvisualribbonedit.codeplex.com/
Create ​Phone Call Ribbon Scripts which will be used by button created in later steps.
Define the following source of the script created in previous step. The script mark as completed the phone call and open a new phone call - regarding and description fields are sent through url. Therefore the url has to be shortened if it exceeds 2000 chars, otherwise the link does not work.
function SaveAsCompleteAndNew() {
// Attempt to save Activity and Mark it as Complete
SaveAsCompleted();
// If the form is not valid
if (!Xrm.Page.data.getIsValid())
return;
var url = "/main.aspx?etn=phonecall&pagetype=entityrecord&extraqs=";
var regardingString = "";
var regardingValue = Xrm.Page.getAttribute("regardingobjectid").getValue();
if (regardingValue != null) {
regardingString += "&regarding_id=" + regardingValue[0].id;
regardingString += "&regarding_name=" + regardingValue[0].name;
regardingString += "&regarding_type=" + regardingValue[0].entityType;
regardingString = encodeURIComponent(regardingString);
}
var descriptionValue = Xrm.Page.data.entity.attributes.get("description").getValue();
var descriptionString = ((descriptionValue != null) ? encodeURIComponent("description=" + descriptionValue) : "");
// The url length is limited to about 2k chars, otherwise the link cannot be opened. Therefore the length has to be limited.
var maxDescriptionLength = 1970 - (url.length + regardingString.length);
if (descriptionString.length > maxDescriptionLength) {
var shortenedText = descriptionString.substr(0, maxDescriptionLength - 25);
// Patt1 checks if it ends with e.g. %1 and patt2 with %. These are not allowed because they have been reduced by
// substr. Correct format is three chars like %20 for white space. If there are not in correct format, url does not work
var patt1 = new RegExp("%\\d$");
var patt2 = new RegExp("%$");
if (patt1.test(shortenedText))
shortenedText = shortenedText.substr(0, shortenedText.length - 3);
else if (patt2.test(shortenedText))
shortenedText = shortenedText.substr(0, shortenedText.length - 2);
descriptionString = shortenedText + encodeURIComponent("\n...shortened...");
}
var extraqsEncoded = descriptionString + regardingString;
window.open(url + extraqsEncoded);
}
Run Visual Ribbon Editor for CRM 2011/2013, connect to CRM instance, select the Phone Call entity and add a new button "Complete And New" through New button fucntion. Define the following setting on the Details tab:
Note: As you can see there are also icons defined. Load these icons as web resource to the CRM.
Select Action tab and define the action which should be perfomed on click command of "Complete And New button". As a Function Name use the same name as defined in step 3. Library should be a path to the script created also in step 3.
You can also define Display Rules - in our case we show the button only to people who has right to write to the current phone call entry and also if the phone call is in Open status (statuscode = 1).
Save all changes in Visual Ribbon Editor for CRM 2011/2013 and publish them. Also do not forget to publish changes in CRM customization otherwise added webresources are not available.

Dynamic controls(Textbox) in asp.net

I want to create dynamic text boxes during run time.
Suppose im gettng a text from a database as "# is the capital of India" now i want to replace that "#" by text box while it is rendered to user as below
<asp:TextBox runat="server" id = "someid"></asp:TextBox> is the capital of India
Im able to get the textbox and text as combination. However I cannot access the textboxes with the given id and when any event occurs on the page the textboxes are lost as they logically does not exist untill their state is stored.
I also went through the concepts of place holder and Viewstate to store the dynamically created controls and make their id's available for the methods, but as far as I tried I could not meet the textbox and text combination requirement.
Im looping over the entire text recieved from database and checking if there is any"#". Is yes then i want to replace it with a textbox on which i can call methods to take back the value entered in the text box to database and store it.
eg: text is "#" is the capital of India
for (int i = 0; i < que.Length; j++) //que holds the text
{
if (que[i] == '#')
{
//Textbox should be created
}
else
{
//the texts should be appended before or after the textbox/textboxes as text demands
}
}
On button click I'm passing request to database, which will send me necessary details i.e. question text, options and also saves the current checked value etc.
protected void BtnLast_Click(object sender, EventArgs e)
{
CheckBox1.Checked = false;
CheckBox2.Checked = false;
CheckBox3.Checked = false;
CheckBox4.Checked = false;
QuestionSet q = new QuestionSet();
StudentB b = new StudentB();
q = b.GetQuestion(1, 1, qid, 'L', 0, Checked, date);
qid = Convert.ToInt32(q.Question_Id);
Checked = q.Checked;
if (q.Question_Type == 11) //indicates its objective Question
{
//ill bind data to checkboxes
}
else if (q.Question_Type == 12) // indicate its fill in the blanks question
{
for (int j = 0; j < que.Length; j++)
{
if (que[j] == '#')
{
count++;
string res = "<input type = 'text' runat = 'server' id ='TxtBoxFillUp" + count + "'/>";
htm = htm.Append(res);
}
else
{
htm = htm.Append(que[j]);
}
}
}
}
Any help will be greatly appreciated, thanks in advance.
Adding control in the way you do it won't create control as asp.net creates it. You do have to create controls as usual .net object.
TextBox myNewTextBox = new TextBox() {};
// Set all initial values to it
And add this cotrol to placeholder or panel, whatever you use. Keep in mind that asp.net page events fire even if you use update panel, so in order to maintain state and events of newly created controls you have take care of creating such controls long before page's Load event fires. Here is my answer to another simialiar question.
Seeing the requirements you have:
1.) You need to use JavaScript. Since the ASP.NET will not recreate controls which are dynamically added. Dynamically added controls need to be recreated after every postback. This is the reason why your TextBoxes are Lost after every postback.
2.) You can write JavaScript code to Hide and show the textboxes for blank texts since at every button click you can call Client side functions using: OnClientClick() property of buttons.
3.) Also to Get the TextBoxes using ID property, add them in Markup( .aspx ) portion itself.

Displaying image using Image control in button click event

I am creating image comparison (images exists in directory) web based application. It compares images exists in particular directory with provided image. It compares each image with matching percentage but not displaying images from related directory even i have given the image url to that images also. When i write response.write then it shows matching percentage with that matching image, but not displaying images.
I have written code for that as follows :
protected void btnnew_Click(object sender, EventArgs e)
{
Bitmap searchImage;
try
{
//Image for comparing other images that are exists in directory
searchImage = new Bitmap(#"D:\kc\ImageCompare\Images\img579.jpg");
}
catch (ArgumentException)
{
return;
}
string dir = "D:\\kc\\ImageCompare\\Images";
DirectoryInfo dir1 = new DirectoryInfo(dir);
FileInfo[] files = null;
try
{
files = dir1.GetFiles("*.jpg");
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("Bad directory specified");
return;
}
double sim;
foreach (FileInfo f in files)
{
sim = Math.Round(GetDifferentPercentageSneller(searchImage, new Bitmap(f.FullName)), 3);
if (sim >= 0.95)
{
Image1.ImageUrl = dir + files[0];
Image2.ImageUrl = dir + files[1];
Response.Write("Perfect match with Percentage" + " " + sim + " " + f);
Response.Write("</br>");
}
else
{
Response.Write("Not matched" + sim);
}
}
}
ASP.NET pages follows control based development - so generally, you don't directly write to a response but rather update text for control such as label or literal.
As far as image goes, for image to visible in the browse, you need to set the url that is accessible from the browser. In above code, you are setting the physical file path and which is not going to be accessible as a URL from same/different machine. You need either to map a virtual directory to your image storage location and then generate a url for the same (by appending virtual directory path & file name) or to write a file serving handler (ashx) that would take the image partial path and serve the image (i.e. send its data to browser).

Connection closing after repeater databinding

I recently changed the way the connection worked on my web app and now I'm facing something that I don't understand.
I hava a page that call a function called "ItemGet" in the Page_Load and it work perfectly when there is no data in the first repeater (Repeater1). When I click on a button that reload the page with different data (I know there is data in the repeater), the connection is closed automatically right after that same repeater (Repeater 1). The problem, is that there is another repeater right after (RepeaterTopTen) that need the same connection. I closed manually the connection right after the call to that function but at least I need the connection to stay open during all the function.
Do any of you know the reason why it closed itself and what I can do to prevent it to close at this time?
Here is the code :
private void ItemsGet(string csCategory, string csTimeFrame)
{
DataSet data;
if (csCategory == null)
{
data = m_database.GetPost(Tools.GetPostLang(), Session["TimeFrame"].ToString());
Page.Title = m_database.GetTranslation(509);
}
else
{
data = m_database.GetPost(Convert.ToInt32(csCategory), Tools.GetPostLang(), Session["TimeFrame"].ToString());
Page.Title = m_database.GetTranslation(508) + m_database.GetCategoryName(Convert.ToInt32(csCategory));
}
// Populate the repeater control with the Items DataSet
PagedDataSource objPds = new PagedDataSource();
objPds.DataSource = (DataView)(data.Tables[0].DefaultView);
// Indicate that the data should be paged
objPds.AllowPaging = true;
// Set the number of items you wish to display per page
objPds.PageSize = 5;
// Set the PagedDataSource's current page
if (CurrentPage != 0)
objPds.CurrentPageIndex = CurrentPage;
else
objPds.CurrentPageIndex = 0;
lblCurrentPage.Text = m_database.GetTranslation(423) + (CurrentPage + 1).ToString() + m_database.GetTranslation(422) + objPds.PageCount.ToString();
// Disable Prev or Next buttons if necessary
btnPrev.Enabled = !objPds.IsFirstPage;
btnNext.Enabled = !objPds.IsLastPage;
Repeater1.DataSource = objPds;
Repeater1.DataBind();
DataSet dataTopTen = m_database.GetTopTenUser();
RepeaterTopTen.DataSource = dataTopTen;
RepeaterTopTen.DataBind();
}
Because no one answer that one, I created a function that check if the connection is open and if not, it open it. I checked carefully that it was closed each time.
If you declare your database object and call the open method on the database connection in your Page_Load method, then the database connection will remain open during your entire page life cycle. With your database connection declared in this function, the database object goes out of scope and gets closed when your function ends.

Resources