Getting a TinyMCE dropdown image list in an MVC3 application - asp.net-mvc-3

I am trying to get an MVC3 app to feed TinyMCE with an external image list javascript file. I have TinyMCE set up so that if I use a static image list file, I get the image list, so I know that part works. But since I need to dynamically create the image list per user, I need something more flexible than a static file. It is down to providing the javascript from the following controller action:
public JavaScriptResult TinyMCEImageList(int id)
{
ListHelper lh = new ListHelper();
string js = "var tinyMCEImageList = new Array(\r\n" + "// Name, URL\r\n";
Dictionary<string, string> dict = lh.GetPetImageURLs(id);
int i = dict.Count();
foreach (var item in dict)
{
js += "['" + item.Key + "', '" + item.Value + "']";
if (i > 1)
{
js += ",\r\n";
}
i--;
}
js += "\r\n);";
return JavaScript(js);
}
The ListHelper.GetPetImageURLs() returns a dictionary object, which is simply a convenient way to hold the caption and URL of each image. When I call this controller from the browser, with the appropriate id parameter, I get what I would think is a workable JS file. In fact, such results are what I used to create the static file I used to test the TinyMCE image list setup, and that got me an actual dropdown image list.
Here is my TinyMCE setup. This is inside the view containing a TinyMCE instance:
tinyMCE.init({
mode: "textareas",
theme: "advanced",
plugins: "lists,pagebreak,style,table,inlinepopups,advhr,advimage,preview,searchreplace,print,paste,visualchars,nonbreaking",
theme_advanced_buttons1: "newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,forecolor,backcolor,image",
theme_advanced_buttons3: "tablecontrols,|,visualaid,|,sub,sup,|,advhr,|,preview,print,|,visualchars,nonbreaking,template,blockquote,pagebreak",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true,
external_image_list_url: "/InstructionDocument/TinyMCEImageList/#ViewBag.PetID"
});
The #ViewBag.PetID is being used elsewhere, so I know it is valid. Even if I hardcode this value, or specifically point to the controller action, I still do not get a dropdown list of images. I'm sure there's something simple I'm missing; can someone point out to me what it is (or at least give me some reasonable guidance)?
[EDIT]
The output from the TinyMCEImageList() action follows:
var tinyMCEImageList = new Array(
// Name, URL
['System Guinea Pig - 4', 'http://www.remindapet.com/Content/images/galler/1_4_970BB64F7C1A4375AF5722B8A62C8708.jpg'],
['System Guinea Pig - 5', 'http://www.remindapet.com/Content/images/gallery/1_4_CBA0D3DDBBED41C583A6E6C46FC9DADF.jpg']
);
Also, here are the headers for the above javascript return from the action:
Server ASP.NET Development Server/10.0.0.0
Date Fri, 23 Dec 2011 00:14:31 GMT
X-AspNet-Version 4.0.30319
X-AspNetMvc-Version 3.0
Cache-Control private
Content-Type application/x-javascript; charset=utf-8
Content-Length 292
Connection Close
So, the action really is returning a JavascriptResult. I just haven't been able to come up with how to get TinyMCE to see it.
Thanks!

Instead of rendering an javascriptresult, create a js file while you are rendering the page.
Controller
public ActionResult Index()
{
MakeJSFile();
return View();
}
MakeJSFile() function will create the jsfile we need, then the page will be rendered.
MakeJSFile() function
public void MakeJSFile()
{
#region declare
var imgPath = Server.MapPath("~/Content/images/gallery/");
var jsPath = Server.MapPath("~/Scripts/image_list.js");
List<string> fileList = populateList(imgPath, ".jpg");
#endregion
#region build jsfile
string content = "var tinyMCEImageList = new Array(";
foreach (var item in fileList)
{
content += "[\"" + item + "\", \"/Content/img/" + item + "\"]";
if (item != fileList.Last())
content += ",";
}
content += ");";
#endregion
#region create file
StreamWriter sw = new StreamWriter(jsPath, false);
sw.Write(content);
sw.Close();
#endregion
}
First declare the path for the directory where the images is, and also the path of the jsfile. Then create a list that contains the filenames and populate it(with populateList function).
Then create a string to build the jsfile.
After that create the file in you server.
You only need to do one more thing, create the populateList function.
PopulateList function
public List<string> populateList(string path, params string[] extensions)
{
List<string> list = new List<string>();
FileInfo fi = new FileInfo(path);
DirectoryInfo di = fi.Directory;
FileSystemInfo[] fsi = di.GetFiles();
foreach (FileSystemInfo info in fsi)
foreach (var ext in extensions)
if (info.Extension == ext)
list.Add(info.Name);
return list;
}
This function requires the path to the directory and file extensions.
If you want a specific list, just change this function.
One more thing, don't forget to change the value of external_image_list_url
tinyMCE.init({
...
external_image_list_url: "/Scripts/image_list.js"
});

Related

Google script spreadsheet - I need to run one script from multiple buttons but with different parameters

I have two buttons (Button1 and Button2) and one function: MyFunction(number). And I either need to pass a parameter to the function or find out what button the function was started from. Is it possible?
function MakePDF(number) {
var ui = SpreadsheetApp.getUi();
//Get Active Spreadsheet
var spreadSheet=SpreadsheetApp.getActiveSpreadsheet();
spreadSheet.getRange('B2').setValue(number); //HERE I NEED TO GET THE SPECIFIC NUMBER FROM 1 TO 100
//Get Sheet to print of the spreadsheets
var sheets=spreadSheet.getSheets();
var Faktura = spreadSheet.getSheetByName("Invoice");
var sheetID = Faktura.getSheetId();
//Export URL with Parameters
var spreadSheetId = spreadSheet.getId();
var URL = "https://docs.google.com/spreadsheets/d/"+spreadSheetId+"/export"+
"?format=pdf&"+
"size=7&"+
"fzr=false&"+
"portrait=true&"+
"fitw=true&"+
"gridlines=false&"+
"printtitle=false&"+
"sheetnames=false&"+
"pagenum=UNDEFINED&"+
"attachment=true&"+
"gid="+sheetID;
//the HTTP method for the request: get and headers : authorization : Bearer tokens to access OAuth 2.0-protected resources
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
//Return the data inside this object as a blob.
var response=UrlFetchApp.fetch(URL,params).getBlob();
//To set name of file
var VS = listOvladani.getRange('B6').getValue();
var firma = listOvladani.getRange('B5').getValue();
firma = removeDiak(firma);
firma = firma.toString().replace(/ /g, '-');
firma = firma.toString().replace(/\./g,'');
firma = firma.toString().replace(/,/g,'');
var namePDF = VS + "_" + firma + "_Autonapul.pdf";
// Load it to specific directory
var dir = DriveApp.getFoldersByName("Rucnifaktury").next();
var pdfFile = dir.createFile(response).setName(namePDF);
// Display a modal dialog box with custom HtmlService content.
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + spreadSheet.getName() + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful');
//Email it
/* MailApp.sendEmail('trnka#trnka.cz', 'Pokus', 'Nějaký text', {
attachments: [{
fileName: "Faktura_pokusna" + ".pdf",
content: response.getBytes(),
mimeType: "application/pdf"
}]
});
*/
}
More details More details More details More details More details More details More details More details More details More details More details More details
You can do it in a different way:
Replace buttons through checkboxes and bind to your script an onEdit(e) trigger which will automatically fire the script on each edit.
You can implement a statement to verify either the edited column was your checkbox column and if so - which checkbox has been checked.
Sample:
function onEdit(e) {
if(e.range.getColumn()==2&&e.range.getValue()==true){
Logger.log(e.range.getA1Notation());
}
}
References:
Event objects
getValue()
getColumn
A1 notation
You can use two more functions who just call the main function with a different parameter, so button 1 calls pressButton1 and button 2 calls pressButton2.
function MakePDF(number) {
//do stuff
}
function pressButton1(){
MakePDF(1);
}
function pressButton2(){
MakePDF(2);
}
This is the easiest way to handle the situation.

Jsoup Modify Links

I am, very new to spring and jsoup... I am using jsoup to parse an html file and copy some text inside a div tag and displaying it on my page. Now i am trying to modify the links and add exit.do to log the users out of the server. I have tried many different approach and my links dont work :( has anyone dealt with this link update before? any help is appriciated.
here is my code.
Thanks a lot.
Lola
modelMap = referenceData( request, modelMap);
modelMap.put("externalUrl", externalUrlMap.get( request.getServletPath() ));
modelMap.put("elementId", elementIdMap.get( request.getServletPath() ));
/** Pass the url map to a string */
String url = (String) externalUrlMap.get( request.getServletPath() );
/** Pass the div map to a string */
String eleId = (String) elementIdMap.get( request.getServletPath() );
/** Retrieve and parse the document using Jsoup*/
//URL externalUrl = new URL(url);
//Document document = Jsoup.parse(externalUrl, 10000);
File internalFile = new File(url);
Document document = Jsoup.parse(internalFile, "UTF-8");
/** Clean the document to prevent XSS only include tags and style below */
//document = new Cleaner(Whitelist.basic().addTags("div", "em", "h1", "h2").addAttributes("div","class", "style")).clean(document);
/** Select privactText tags from the id */
Element divContent = document.select(eleId).first();
/** Returned the text inside the div tag */
String parsedExternalContent = divContent.html();
/** Get all links inside div tag */
Elements links = divContent.select("a[href]");
String exitUrl = "/exit?logout=true&uri=";
/** Loop through the links and if the links are relative path add the exit.do to the link */
for (Element link : links) {
if (!link.attr("href").toLowerCase().startsWith("http://")) {
String urltext = link.attr("href");
String exitText = "/exit?logout=true&uri=";
...
}
}
modelMap.addAttribute("parsedExternalContent", parsedExternalContent);
return new ModelAndView ("externalParserContent", modelMap);
This is the way i did it when i needed to re-write an original string with "encoded" url:
Document doc = getHtmlDocumentFromString(htmlOnly);
Elements links = doc.select("a[href]");
/**
* since we would want to track link index per click - iterate links in the old fashion way (Elements is a List<Element>)
*/
for(int linkIndexTopToBottom = 0; linkIndexTopToBottom < links.size(); linkIndexTopToBottom++){
try{
Element link = links.get(linkIndexTopToBottom);
if (!UriUtils.isValidUrl(link.attr("href")))
continue;
...
link.attr("href",<NEW URL>);
}catch (MalformedURLException exception){
log.debug("Provided URL was not valid: " + links.get(linkIndexTopToBottom).attr("abs:href") + ", skipping link re-write");
}
}
return doc;
As you can see you need to set the attribute like:
link.attr("href", <NEW URL>);
since that part was missing from your post, i were not sure whether you do it or not
EDIT
The appending would be exactly the same idea:
link.attr("href", link.attr("href") + "<what you need to append with>");
The bottom line is you need to set href attribute to a new value
Example from the jSoup cook book

Uploading images with redactor to MVC

This might be a bit too specific for here and I may need to contact redactor support but i've seen other questions about redactor here so i figured i'd give it a shot ...
Ok ...
So i'm trying to get get image uploading to work following the example here ...
http://imperavi.com/redactor/docs/images/
My client side code ...
$("textarea").redactor({
focus: true,
imageUpload: '/MyController/UploadImage'
});
My MVC controller action looks like this ...
public JsonResult UploadImage(object image)
{
// Do something with whatever that was i got from redactor
var result = new { filelink = "" };
return Json(result);
}
The problem is ... what did redactor actually give me?
Was it the whole file? a chunk? i can't seem to tell because the object has no type information at all and the raw post information seems way too little to actually be a whole image file.
Has anyone had any experience with this / actually done it before?
I don't really want to setup php on my server for this 1 function.
EDIT:
Ok a bit more digging reveals that if i pull the underlying Request object it has a files property which apparently contains my posted image file.
I think i might be able to figure it out from here.
Where I get a code block in place i'll post it as an answer.
You are receiving a HttpPostedFileBase object. Here is my implementation:
jQuery:
$('#blog-post').redactor(
{
imageUpload: '/blog/images/',
imageGetJson: '/images/locations/blogs/'
});
Then in the controller:
public ActionResult Images(HttpPostedFileBase file)
{
// Verify that the user selected a file
if( file != null && file.ContentLength > 0 )
{
// extract only the fielname
var fileName = Path.GetFileName( file.FileName );
// store the file
var path = Path.Combine( ImageLocation.BlogPicturePath, fileName );
file.SaveAs( path );
}
return Json( new { filelink = ImageLocation.BlogPictureUrl + "/" + file.FileName } );
}
ok um ... i think im there ...
This needs a bit of cleaning up and I don't expect you guys to understand what goes on under the bonnet of my custom DMS code but just assume it takes the stream and returns a FileInfo object and in theory this should work for you too ...
public ActionResult Upload()
{
// this object is specific to my system but all it does is
// stream the file to a path on the server (code not needed for this Q)
var dmsService = _kernel.Get<IDMSFileSystemService>();
List<FileInfo> savedFiles = new List<FileInfo>();
for (int i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[i];
using (file.InputStream)
{
savedFiles.Add(dmsService.AddFromStream(file.InputStream, file.FileName);
}
}
var result = savedFiles.Select(f => new { filelink = f.Path}).ToArray();
return Json(result);
}
Suprisingly simple right ... :)

unable to get multiple entries in SelectEntries of DotNetZip

I'm trying to use DotNetZipLib-DevKit-v1.9 in my MVC3 Project to extract the files to a specific folder.
What i want is -- How to add multiple entries in zip.SelectEntries method.
Here is my code in controller action:
public ActionResult ExtractZip(string fileName, HttpPostedFileBase fileData)
{
string zipToUnpack = #"C:\Users\Public\Pictures\Sample Pictures\images.zip";
string unpackDirectory = System.IO.Path.GetTempPath();
using (ZipFile zip1 = ZipFile.Read(zipToUnpack))
{
// here, we extract every entry, but we could extract conditionally
// based on entry name, size, date, checkbox status, etc.
var collections = zip1.SelectEntries("name=*.jpg;*.jpeg;*.png;*.gif;");//This shows `0` items in collections
foreach (var item in collections)
{
item.Extract(unpackDirectory, ExtractExistingFileAction.OverwriteSilently);
}
}
return Json(true);
}
In this line var collections = zip1.SelectEntries("name=*.jpg;*.jpeg;*.png;*.gif;"); if i specify only single extension ,it works fine
ex:
var collections = zip1.SelectEntries("name=*.gif"); this works good
I've also seen SelectEntries method here, but it doesn't help though
How to add multiple entries ?
Finally i could answer my own question.
Inorder to select multiple entries we need to use OR and to select multiple entries use the following code:
var collections = zip1.SelectEntries("(name=*.jpg) OR (name=*.jpeg) OR (name=*.png) OR (name=*.gif)");
foreach (var item in collections)
{
item.Extract(unpackDirectory, ExtractExistingFileAction.OverwriteSilently);
}

Using MVC3 AJAX call to ActionResults fails when returning a File

I have an action result that returns a created File object (simplified for display!):
public ActionResult Create(int recID, int templateID)
{
//Get dbRecord from recID
DBRecord dbRecord = db.dbRecord.Find(recID);
//Get Template from templateID
Template template = db.Templates.Find(templateID);
if (template == null) throw new FileLoadException(string.Format("No database record found for template reference {0}",templateID));
//set fileOutput details
WordFile fileOutput = new WordFile(dbRecord, Server.MapPath("~/Documents/"),template);
//Create XML object for Template
XmlDocument xDoc = new XmlDocument();
//Save resulting document
xDoc.InnerXml = mergeData(template,dbRecord);
xDoc.Save(fileOutput.fullName);
if (!System.IO.File.Exists(fileOutput.fullName)) throw new FileNotFoundException(string.Format("File {0} could not be created", fileOutput.fileName));
//Return saved document
return File(fileOutput.fullName, "application/doc", fileOutput.fileName);
}
If I call this via an HTML RouteLink
<%: Html.RouteLink("Generate via HTML
, "GenerateDocument"
, new RouteValueDictionary(
new {
controller = "Template"
, action = "Create"
, recID = 1
,templateID = 1
}
)
)%>
Edit 1: It works fine, the document is generated and the user is prompted to open, save, etc. However, if I call it via an AJAX RouteLink, the code steps through, the document is created on the server, but the user is not prompted to open or save.
<%: Ajax.RouteLink("Generate via AJAX"
, "GenerateDocument"
, new RouteValueDictionary(
new {
controller = "Template"
, action = "Create"
, recID = 1
, templateID = 1 }
)
, new AjaxOptions
{
HttpMethod="POST"
, LoadingElementId="Refresh"
})%>
Is there an inherent restriction that prevents AJAX returning a file type or have I missed the right search combination to find an obvious answer?
I'm not sure I understand what you're talking about. Are you trying to return the file contents to a javascript variable? That is the only thing I can imagine an "AJAX RouteLink" would be good for. If you want it to prompt the user to open or save, use a normal link. If you're trying to embed the file in the page, don't return the file, return the html that you would use to do the embedding.

Resources