How to save and display uploaded image via tinymce editor in MOODLE 2.9 - tinymce

Save and display tinymce content in Moodle.
I have a block that save question and answer in db.
I use tinymce editor for this, so that user can enter text and image.
My editor form is:
.....
$editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'noclean'=>true, 'context'=>$context);
$mform->addElement('editor', 'title_editor', 'Questions', null, $editoroptions);
$mform->addRule('title_editor', null, 'required', null, 'client');
$mform->setType('title_editor', PARAM_RAW);
.....
I submit the form and save the data(text+image) from tinymce in db
......
if($data = $sample_form->get_data()) {
if ($draftitemid = file_get_submitted_draft_itemid('title_editor')) {
$data->title_editor['text'] = file_save_draft_area_files($draftitemid, $contextid, 'block_sample', questiontext, array('subdirs' => true, 'maxfiles' => 5),$data->title_editor['text']);
}
//insert to database
$inserRecord = new stdClass();
$inserRecord->suggestion = $sgid;
$inserRecord->questiontext = $data->title_editor['text'];
$inserRecord->answertext = $data->answer['text'];
$insertRes = add_question_desc($inserRecord);
......
In db the data(here question and answer) saved. The question data is looks like:
<p>What color is this?</p>
<p><img src="##PLUGINFILE##/sample_image.png" width="309" height="212" alt="green" /></p>
Is this complete to save the data? Where did the uploaded file saved. How I retreive/display the uploaded file.
I use:
$qn = file_rewrite_pluginfile_urls($qnDetails[$qnid]->questiontext, "pluginfile.php", $context->id, "block_sample", 'questiontext', $qnid);
echo $qn;
The above code only display the text and image is not displaying.
I inspect the broken image field and it is:
<img src="http://localhost/moodle/pluginfile.php/24/block_sample/questiontext/12/mc4.png" width="309" height="212" alt="mc4.png">

To manipulate files in an editor you must use the following methods:
Prior to displaying the form: file_prepare_standard_editor()
When saving the form: file_postupdate_standard_editor()
When displaying the content: file_rewrite_pluginfile_urls() followed by format_text()
You can find an example of this in cohort/edit.php and cohort/index.php.
Once that is done, you need to implement the function _pluginfile which Moodle core will call to get the file. The _pluginfile functions are required so that your plugin can check whether or not the user can access the file. You can find default implementations in filelib.php file_pluginfile() and in various lib.php <component_name>_pluginfile().

Related

How to display an image uploaded with input type="file" as a src attribute

I tried creating an input which allows users to display images they uploaded as an html img. All of this needs to happen on 'submit'.
My js code for input (which is inside a form) looks like this:
const imageInput = document.createElement('input');
imageInput.type = 'file';
imageInput.accept = ".png, .jpg, .jpeg";
and this is how I'd like to output my image
const displayImg = (e) => {
e.preventDefault();
const questionImg = document.createElement('img');
questionImg.src = imageInput.value;
}
image.addEventListener('submit', displayImg);
It obviously doesn't work since imageInput.value looks something like this C:\fakepath\pizza.jpg
Then how can I set the uploaded file as the source of an image.
I found some helpful code on youtube that I tried that manages to output the uploaded img as div's background-image https://codepen.io/codefoxx/pen/QWvqMya but it stops working once I try to output it as the src or add form, submit button and change the event listener to "submit".

Tinymce filenaming causes images to be overwritten when saved

Using TinyMce editor on a PHP-project for creating worklogs. The user can take a screenshot (ex greenshot, snipping tool) and paste this into the Tinymce editor. Tinymce will name the screenshot mceclip0.png (pic1), mceclip1.png (pic2) etc. The user saves the worklog and the images is uploaded to a folder on webserver with those names. So far so good.
When the user want to edit this worklog later and paste in a new image he/she forgot to add, this image will be name... mceclip0.png (pic3). If the user then saves this, oh oh, the first image from the first initial creating of the worklog will be overwritten. So pic1 will now look the same as pic3.
Here is when the first two pictures are added:
And then the user wants to add a third picture, this happens:
Below is the code that is used and from Tinymce. I've tried to change parameters according to documentation with no luck. Some say this is solved by
images_reuse_filename: true
But this is not the case for me. If I take a snipping tool of something and save it to disk it will be named "screenshot.png". In the Tinymce editor it changes to mceclip0.png anyways.
I was thinking I want to append date and time to the "mceclip.png" name, but I can't figure out how to do so. Would this be a solution?
Thanks in advance!
tinymce.init({
selector: 'textarea',
height: 600,
plugins: 'image code paste',
paste_data_images: true,
image_file_types: 'jpg,webp,png',
toolbar: 'undo redo | link image | code',
automatic_uploads: true,
images_upload_url: 'fileUpload.php',
images_reuse_filename: true,
images_upload_handler: function (blobInfo, success, failure) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', 'fileUpload');
xhr.onload = function () {
var json;
if (xhr.status !== 200) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
}
});
Seems like there is no way of changing the filename since it is a blob and set in clipboard.js in the TinyMce-plugin if I understand this correctly. Meaning the only way this is solvable (as far as I can see) is to change this serverside. I created then just a concatenation of unix timestamp and the filename to make it unique.
Now the user can go back and edit the worklogs, adding screenshots without overwriting existing screenshots.

Tinymce - How can I specify a directory on my server to use when I insert an image?

This works fine if I was to implement uploading an image via tinymce etc, which I'm really not interested in doing.
I already have hundreds of images uploaded from another part of the website that I'd like to insert into pages being edited and created with tinymce v5.
But how can I indicate in the Insert/Edit dialog box to show just the contents of one directory on the server?
I had a hack from vers 3 something I think it was that I can't locate, and it being so ancient I'm sure it's pretty useless, it didn't even support Safari, so it had to be 10+ years old.
Can't find anything in tinymce docs about indicating a directory to use with insert image.
Some custom javascript to include somewhere???
My basic starter tinymce code:
<script>
tinymce.init({
selector: '#editor',
plugins: 'image code',
toolbar: 'undo redo | link image | code',
/* enable title field in the Image dialog*/
image_title: true,
/* enable automatic uploads of images represented by blob or data URIs*/
automatic_uploads: true,
/*
URL of our upload handler (for more details check: https://www.tiny.cloud/docs/configure/file-
image-upload/#images_upload_url)
images_upload_url: 'postAcceptor.php',
here we add custom filepicker only to Image dialog
*/
file_picker_types: 'image',
/* and here's our custom image picker*/
file_picker_callback: function (cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
/*
Note: In modern browsers input[type="file"] is functional without
even adding it to the DOM, but that might not be the case in some older
or quirky browsers like IE, so you might want to add it to the DOM
just in case, and visually hide it. And do not forget do remove it
once you do not need it anymore.
*/
input.onchange = function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function () {
/*
Note: Now we need to register the blob in TinyMCEs image blob
registry. In the next release this part hopefully won't be
necessary, as we are looking to handle it internally.
*/
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var base64 = reader.result.split(',')[1];
var blobInfo = blobCache.create(id, file, base64);
blobCache.add(blobInfo);
/* call the callback and populate the Title field with the file name */
cb(blobInfo.blobUri(), { title: file.name });
};
reader.readAsDataURL(file);
};
input.click();
},
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
});
</strict>
There are several ways to do so:
MoxieManager plugin. Here is the demo. However, it's a premium feature.
Depends on the number of images you have on the server. If there aren't many, you can try to use the image_list option of the Image plugin. It will load the editor with a predefined set of images.
Implement the custom file picker with the file_picker_callback option.

Upload Images and files with TinyMCE

In my symfony2 project I use TidyMCE in my textareas, to be able to insert news from the backend. News can have images in the content or files links to pdf files to display. I am new to this and I can not upload the images or files, so that I can search the different folders and once selected a copy is made on the server.
I've been looking at a lot of comments, but I'm kind of bundled up. I have seen on the web of tinymceel following code:
Basic Local File Picker
tinymce.init({
selector: '#editor',
plugins: 'image code',
toolbar: 'undo redo | link image | code',
// enable title field in the Image dialog
image_title: true,
// enable automatic uploads of images represented by blob or data URIs
automatic_uploads: true,
// URL of our upload handler (for more details check: https://www.tinymce.com/docs/configure/file-image-upload/#images_upload_url)
images_upload_url: 'postAcceptor.php',
// here we add custom filepicker only to Image dialog
file_picker_types: 'image',
// and here's our custom image picker
file_picker_callback: function(cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
// Note: In modern browsers input[type="file"] is functional without
// even adding it to the DOM, but that might not be the case in some older
// or quirky browsers like IE, so you might want to add it to the DOM
// just in case, and visually hide it. And do not forget do remove it
// once you do not need it anymore.
input.onchange = function() {
var file = this.files[0];
// Note: Now we need to register the blob in TinyMCEs image blob
// registry. In the next release this part hopefully won't be
// necessary, as we are looking to handle it internally.
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var blobInfo = blobCache.create(id, file);
blobCache.add(blobInfo);
// call the callback and populate the Title field with the file name
cb(blobInfo.blobUri(), { title: file.name });
};
input.click();
}
});
PHP Upload Handler
<?php
/*******************************************************
* Only these origins will be allowed to upload images *
******************************************************/
$accepted_origins = array("http://localhost", "http://192.168.1.1", "http://example.com");
/*********************************************
* Change this line to set the upload folder *
*********************************************/
$imageFolder = "images/";
reset ($_FILES);
$temp = current($_FILES);
if (is_uploaded_file($temp['tmp_name'])){
if (isset($_SERVER['HTTP_ORIGIN'])) {
// same-origin requests won't set an origin. If the origin is set, it must be valid.
if (in_array($_SERVER['HTTP_ORIGIN'], $accepted_origins)) {
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
} else {
header("HTTP/1.0 403 Origin Denied");
return;
}
}
/*
If your script needs to receive cookies, set images_upload_credentials : true in
the configuration and enable the following two headers.
*/
// header('Access-Control-Allow-Credentials: true');
// header('P3P: CP="There is no P3P policy."');
// Sanitize input
if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $temp['name'])) {
header("HTTP/1.0 500 Invalid file name.");
return;
}
// Verify extension
if (!in_array(strtolower(pathinfo($temp['name'], PATHINFO_EXTENSION)), array("gif", "jpg", "png"))) {
header("HTTP/1.0 500 Invalid extension.");
return;
}
// Accept upload if there was no origin, or if it is an accepted origin
$filetowrite = $imageFolder . $temp['name'];
move_uploaded_file($temp['tmp_name'], $filetowrite);
// Respond to the successful upload with JSON.
// Use a location key to specify the path to the saved image resource.
// { location : '/your/uploaded/image/file'}
echo json_encode(array('location' => $filetowrite));
} else {
// Notify editor that the upload failed
header("HTTP/1.0 500 Server Error");
}
?>
But I do not quite understand where to put the postAcceptor.php or referred to with {location: '/ your / uploaded / image / file'}.
I'm a little lost, please thank all the possible help
postacceptor is your server side method for accepting the file and uploading it in your server. I am using mvc so I created a custom route "ImageUpload". and I use that instead.
location part is the expected return from your method. this will replace the file location/referrer a.k.a src tag when you use images_reuse_filename = true.
I don't use symphony but according to your code you would put the postAcceptor file in the same directory as form

How to capture a value not through an input field in a form using php and mysql ?

Hello everybody and good day ,
I am making a web application in php and mysql
Iam trying to make a page where a user can create a custom form eg. User can create custom forms so they can type the name of the input, however the place where they type the name of the input i have it formated like this:
<div contenteditable="true">
<span spellcheck="false" id="a">Editable Content</span><em>o!</em>
</div>
so its not an input field .
How can i capture this information in a form , maybee with a hidden input field, a label or with jquery ?
if my question is not clear let me know i will edit ti it as soon as i get a chance .
You can use javascript to collect the text inside the span.
This question is related How do I change the text of a span element in JavaScript
The answers mention document.getElementById("myspan").innerHTML which is the place that text resides. You'll want to change the "myspan" though.
You have to use either a form or send the data with AJAX.
document.getElementById("your-form").onsubmit = function()
{
var spanInput = document.createElement("input");
spanInput.setAttribute("type", "hidden");
spanInput.setAttribute("name", "spanData");
spanInput.setAttribute("value", document.getElementById("a").innerHTML);
this.appendChild(spanInput);
return true;
}
// or
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){} // please change
xhr.open("POST", "your-script.php");
var spanData = document.getElementById("a").innerHTML;
xhr.send("spanData="+encodeURIComponent(spanData));