Dynamic Templates for CKEditor - javascript

I've got CKEditor embedded on a UserControl in our web application. All works fine with loading the default templates for CKEditor, on my local machine and our server.
I'm fetching templates from a database table, transforming the results to the appropriate JSON format and then writing that to a javascript file to add to CKEDITOR.template_files.
An example of the js content I'm generating in the js file:
CKEDITOR.addTemplates('templateskey',{imagesPath:'',templates:[{title:'LCH - Complaint', image:'', description:'Message Template - Complaints', html:'HtmlContent'}]});
Now my problem is that on our server my dynamically created js file seems to get blocked since it's supposed to load over HTTPS. Either this or my file can't be found.
[blocked] The page at 'https://...' was loaded over HTTPS, but ran
insecure content from 'http://...' (page not found url): this content
should also be loaded over HTTPS.
After this CKEDITOR.config tries to load the "templatesKey" template and fails to do so with:
Uncaught TypeError: Cannot read property 'imagesPath' of undefined
I've downloaded the ASP.Net version of CKEditor and included the project in my solution. I'm setting myCKEditor.TemplatesFiles and myCKEditor.Templates in the code behind:
myCKEditor.TemplatesFiles = "['" + relativePath + "']";
myCKEditor.Templates = "templateskey";
Is the problem that I'm generating the js file dynamically? Or is the problem that the templates plugin is loading content over HTTP rather than HTTPS? Is there a better way to dynamically add templates to CKEditor?

So talking to my friend that has expertise in SSH and HTTPS. This might be a limitation on HTTPS since I'm generating content dynamically it sees the content as a possible threat and unsecure.
CkEditor - Template loaded from AJAX is a good solution to the problem.
If you're working with ASP .Net you can build a Handler. Call the handler with ajax and pass JSON back.
e.g. The handler:
//Implement IRequiresSessionState is you want anything from the session state
public class TemplateHandler : IHttpHandler, IRequiresSessionState
{
/// <summary>
/// You will need to configure this handler in the Web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
#region IHttpHandler Members
public bool IsReusable
{
// Return false in case your Managed Handler cannot be reused for another request.
// Usually this would be false in case you have some state information preserved per request.
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
try
{
//write your handler implementation here.
string ID = Convert.ToString(context.Session["ID"]);
DataSet dsTemplates = ExecuteStoredProc("uspTemplateRead");
if (!dsTemplates.ContainsData())
return;
List<Template> templates = new List<Template>();
foreach (DataRow row in dsTemplates.Tables[0].Rows)
{
Template template = new Template();
template.Title = row["Title"].ToString();
template.Image = "template.gif";
template.Description = row["Descr"].ToString();
template.Html = row["Temp"].ToString();
templates.Add(template);
}
byte[] b;
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(List<Template>));
using (MemoryStream stream = new MemoryStream())
{
jsonSerializer.WriteObject(stream, templates);
b = stream.ToArray();
}
context.Response.Clear();
context.Response.ContentType = "application/json";
context.Response.AddHeader("Content-Length", b.Length.ToString());
context.Response.BinaryWrite(b);
context.Response.Flush();
}
catch (Exception ex)
{
throw ex;
}
}
}
And then the Ajax call:
CKEDITOR.on("instanceReady", function () {
try {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function () {
var json;
if (this.responseText == "")
json = "";
else
json = JSON.parse(this.responseText);
var template = {
imagesPath: CKEDITOR.getUrl(CKEDITOR.plugins.getPath("templates") + "templates/images/"),
templates: json
};
CKEDITOR.addTemplates('myTemplates', template);
};
httpRequest.open('GET', '/handlers/templatehandler.ashx');
httpRequest.send();
} catch (ex) {
console.log(ex);
}
});

Related

Where do I have to define connectors in Alfresco? Can I use them from a ".bpmn" file?

Good afternoon! I am trying to communicate from Alfresco to a RESTful ws from a workflow. Somebody told me that it will be a good idea to use connector to acomplish that. I am creating a wf in ACS as a .bpmn file, so 3 questions:
In what file do I have to define the connector?, I want to do the same as this js script:
var url = "https://google.com";
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log(xhr.status);
console.log(xhr.responseText);
}};
xhr.send();
Can I use the connector directly from the .bpmn file? Could you give me an example on how to use it?
Could you give me an example to make a GET and a POST call?
Thanks in advance!
Connectors are part of the web script framework. There is a web script framework in the Alfresco Share tier and there is a web script framework in the repository tier.
In web scripts, you use the "remote" object to make connections to remote RESTful end points. For example, the code to fetch some project information from an API via its project ID might look like this:
var connector = remote.connect("someapp");
var resp = connector.get("/someapp/projects/" + projectId);
if (resp.status == 200) {
obj = JSON.parse(resp);
model.result = obj;
model.startDateFormatted = getFormattedDate(model.result.StartDate);
model.endDateFormatted = getFormattedDate(model.result.EndDate);
}
So where is that "someapp" connector defined? You can put it in an Alfresco config file such as the share custom config. In an Alfresco SDK based project that file lives in the share module under ./src/main/resources/META-INF/share-config-custom.xml:
<config evaluator="string-compare" condition="Remote">
<remote>
<endpoint>
<id>someapp</id>
<name>Some Remote App</name>
<connector-id>http</connector-id>
<endpoint-url>https://someapp.example.org</endpoint-url>
</endpoint>
</remote>
</config>
The challenge for you is that you are running in an Activiti workflow, not a web script. And, aside from that, the remote object is disabled on the repo tier, which is also where you are running. It can be re-enabled, but I don't have those steps handy and it doesn't help you anyway.
So, rather than use any of the above, my advice is to use a Java delegate in your workflow. From the Java delegate you can do anything you want, including leveraging something like the Apache HTTP Client to make a connection to the API you need to call.
You might have a delegate class like:
public class RemoteApiInvocationDelegate implements JavaDelegate {
private Logger logger = LoggerFactory.getLogger(RemoteApiInvocationDelegate.class);
public void execute(DelegateExecution execution) throws Exception {
HttpClient httpClient = Utils.noCertClient();
HttpGet httpGet = new HttpGet("http://someapp.example.org/someapp/projects/12345");
HttpResponse response = httpClient.execute(httpGet);
int status = response.getStatusLine().getStatusCode();
logger.info("Response Status Code: " + status);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line;
StringBuilder sb = new StringBuilder();
while ((line = rd.readLine()) != null) {
sb.append(line);
}
logger.info(sb.toString());
}
}
What you do with the response, like parse it, extract some data, and set it on a process variable, for example, is up to you.
Jeff answer is the most complete. However these are some interesting videos about Java Delegates:
https://www.youtube.com/watch?v=phju1Lru7kI&list=PLOW8iKnFZkm_Eq8MPilFin-lwbCg5J15U&index=1&t=3s
https://www.youtube.com/watch?v=eOL_OKMylfw&list=PLOW8iKnFZkm_Eq8MPilFin-lwbCg5J15U&index=2&t=221s
And this post too:
https://www.armedia.com.mk/spring-managed-alfresco-custom-activiti-java-delegates/

Why in ASP.NET MVC I get JSON instead of FileDownload?

I want to make ability to download attachments from my site, (I need to make it runs in IE)
so in html I have:
<a href="api/attachments/DownloaAttachment?id={{attachment.Id}}" target="_blank">
Download Image
</a>
<!-- {{attachment.Id}} - it's because I use AngularJS :) -->
in controller:
[HttpGet]
public FileContentResult DownloaAttachment(int id)
{
var att = GetAttachmentById(id);
byte[] fileBytes = att.Content.Content;
var response = new FileContentResult(fileBytes, MediaTypeNames.Application.Octet);
response.FileDownloadName = att.FileName;
return response;
}
but when I click on "Download Image" - I have a new window and responce from controller as json, like:
{"FileContents":"/9j/4.. some bytes..ZK9k=","ContentType":"application/octet-stream","FileDownloadName":"Cover.jpg"}
But I don't need that JSON, I need to be able to download attach as file to user's computer.
How can I make it as simple file download? What am I do wrong?
Try changing this line:
var response = new FileContentResult(fileBytes, MediaTypeNames.Application.Octet);
to:
var response = new FileContentResult(fileBytes, "image/jpeg");
Hope you have tried - Returning binary file from controller in ASP.NET Web API.
It says return HttpResponseMessage and set Content of response = file content and set header content type.
Also, i would suggest to look into this - Download file from an ASP.NET Web API method using AngularJS.
It says, you also need to set Content.Headers.ContentDisposition and Content.Headers.ContentDisposition.FileName .
Hope this works.
[HttpGet]
public HttpResponseMessage DownloaAttachment(int id)
{
var att = GetAttachmentById(id);
byte[] fileBytes = att.Content.Content;
var response = new FileContentResult(fileBytes, MediaTypeNames.Application.Octet);
response.FileDownloadName = att.FileName;
return Request.CreateResponse(HttpStatusCode.OK, response, new MediaTypeHeaderValue("image/*"));
}
or if you have file extension pass on that instead of * in (image/*).
refer: MSDN

Flex hack for authenticated file upload

Does anyone know the file upload hack for Flex, which will allow files to be uploaded to authenticated web services via multipart form post? In this bug report from the Adobe site, a user reports:
Flash isn't cross-browser compatible if this feature only works via
Javascript hacks
So far, I've been unable to craft such a hack. I'm unsure what to do next. Here's what I've tried so far (all have been unsuccessful or impossible)
Set cookies on url
Pass cookies to Flex URLRequest
Create hidden html form in javascript to post file
Ultimately this is what worked for me. I modified my web service to accept a stream of bytes instead of a multipart file. Then, I used URLLoader to upload the bytes to the service.
private var fileReference:FileReference;
public function loadFile()
{
fileReference.addEventListener(Event.COMPLETE, fileLoaded);
fileReference.load();
}
private function fileLoaded(evt:Event):void{
fileReference.removeEventListener(Event.COMPLETE, fileLoaded);
startUpload();
}
public function startUpload():void {
var xml:String = // xml to post along with the file ;
var url:String = // url to the web service
var bytes:ByteArray = new ByteArray();
bytes.writeUTFBytes(fileReference.name);
bytes.writeUTFBytes(xml);
bytes.writeBytes(fileReference.data);
bytes.position = 0;
var urlLoader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(url);
request.data = bytes;
request.method = URLRequestMethod.POST
request.contentType = "application/octet-stream";
urlLoader.addEventListener(Event.COMPLETE, uploadComplete);
urlLoader.addEventListener(flash.events.IOErrorEvent.IO_ERROR, uploadError);
urlLoader.load(request);
}
private function uploadComplete(e:Event):void {
// handle success
}
private function uploadError(e:Event):void {
// handle failure
}

Load file after page is complete without redirecting

I am trying to do pretty much the same, as is for example on Sourceforge. After a user creates some data, I generate a file and I want it to be offered to him after a page load. However, I know almost nothing about javascript and simple copy-paste of
<script type="text/javascript">
var download_url = "http://downloads.sourceforge.net/sourceforge/itextsharp/itextsharp-4.1.2-dll.zip?use_mirror=dfn";
function downloadURL() {
if (download_url.length != 0 && !jQuery.browser.msie) {
window.location.href = download_url;
}
}
jQuery(window).load(downloadURL);
</script>
is not enough. It is important for the user to download the file, so how to do that?
A question related to the previous is - where to store the file i created? Once while using the asp.net development server and then on the real IIS server? And how should this address look? When I tried
setTimeout("window.location.href='file://localhost/C:/Downloads/file.pdf'", 2000);
I was getting nothing, with HTTP an error of unknown address.
See Haack's DownloadResult example. It explains (I think) exactly what you're truing to do. Except you would provide the timeout call with your download action url.
you're asking the user's browser to look for a file on their own computer... that you're trying to save there.
you could use something like:
window.location.href='http://www.yourServer.com/generatePDF.asp?whatever=whatever'
where http://www.yourServer.com/generatePDF.asp?whatever=whatever is what is generating the pdf file for the user
On the server, you have to set the content disposition in the response header to "Attachment" as described in these answers.
If you do that, the download will not affect the page that is currently displayed in the browser. So, if you initiate a request in Javascript that gets an attachment, the browser will leave the page alone, and the user will see a message box with the Open/Save/Cancel question.
You can create your own PdfResult which extends ActionResult like this:
public class PdfResult : ActionResult
{
public byte[] Content { get; set; }
public string FileName { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.AddHeader("content-disposition", "attachment; filename=" + this.FileName);
response.AddHeader("content-length", this.Content.Length.ToString());
response.ContentType = "application/pdf";
using (MemoryStream memoryStream = new MemoryStream(this.Content))
{
memoryStream.WriteTo(response.OutputStream);
}
response.End();
}
Then in your action you can simply return the file as follows:
public ActionResult Pdf(string param1...)
{
var content = GeneratePdf(); //etc
var fileName = AssignFileName();
return new PdfResult { Content = content, FileName = fileName + ".pdf" };
}
A couple of different things. First, since you are using MVC, create an action that actually generates the file and returns it as a FileResult. The file can be an actual file on the server, but it can also be generated dynamically -- say in a MemoryStream -- and the FileResult created from that. Set the content to application/octet-stream or the actual file type if it's not one that will render in the browser via a plugin. Second, don't generate the file in the action that renders the page, but rather call the action that generates the FileResult from that page using the technique you've referenced (though it looks like they are doing something different for IE). If the MIME type is not one that can be rendered it will be downloaded.
public ActionResult GenerateFile( string value, int other )
{
MemoryStream file = new MemoryStream();
...
return File( file, "application/octet-stream" );
}

How can I get an ASP.NET Session variable into a javascript file?

I am refactoring a legacy web app. This app has a is using the onload event inside the body tag (On the Master page) to run this javascript script. Note this script tag is after the form element in the doc. I know the syntax looks hideous (or Visual Studio at least tells it is by the squiggles), but I'll be darned, the thing DOES indeed work.
function DisplayPDF()
{
var strPDF
strPDF = "<%=SESSION("PDF")%>";
if (strPDF.length != 0)
{
window.open(strPDF);
<%Session("PDF") = ""%>
}
}
My question is I'm trying to develop a more elegant solution. I have ASP.NET ajax and jQuery both available to me. I wrote a tiny asp.net ajax component that I want to use to handle this.
Type.registerNamespace("ck");
ck.pdfOpener = function() {
ck.pdfOpener.initializeBase(this);
}
ck.pdfOpener.prototype = {
initialize: function() {
ck.pdfOpener.callBaseMethod(this, 'initialize');
},
dispose: function() {
ck.pdfOpener.callBaseMethod(this, 'dispose');
},
openPDF: function(){
//HOW CAN I RETRIEVE A SESSION VARIABLE HERE???
}
}
ck.ClientControl.registerClass('ck.pdfOpener', Sys.Component);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Can/Should I be doing it this way? Or should I create a WebService that returns said variable. Thanks for any advice.
Cheers,
~ck in San Diego
Use the Page.ClientScript.RegisterClientScriptBlock(typeof(YOURPAGECLASS), "KEY", "ACTUALJSCODE"); in your code behind (i.e. the Page_Load event handler)
Alternatlively, you could send the PDF file directly from the asp.net page instead of within the client script.
string pdfFile = Session("PDF");
if (!string.IsNullOrEmpty(pdfFile))
{
Session.Remove("PDF");
Response.ContentType = "application/pdf";
FileInfo fi = new FileInfo(pdfFile);
Response.AddHeader("Content-Disposition", "attachment; filename=\"" + Path.GetFileName(pdfFile) + "\"");
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.WriteFile(pdfFile);
Response.Flush();
return;
}
A simple way to do this would be as you said simply make an Ajax call to a page method, MVC action, HttpHandler or web service that returns the required value from the session. The bigger question here is why you are storing the path to a PDF file in your session state?

Categories

Resources