As you must know that Galleon forum using Markitup editor to create HTML formatted posts. Markitup is a jQuery based easily configurable markup editor. It has "link to image" functionality which used to add URL of a image to show that image in the post. But it doesn't have facility to upload a file to server or browse a file which is already uploaded by that user. I thought, it is good idea to create a plug-in to do the same.
UI mockup for the file upload is
Once the user uploaded a file or click on browse button in markitup menu bar, a popup browse div will showed to the user to select their uploaded image. I made browse window as draggable using jQuery UI. Browse uploaded files interface,
We will see the step by step code changes to implement this. First we need to add new menu bar items. We can configure menu bar items in set.js file located in markitup\sets\default folder. You can change the icons in style.css in the same folder. Here modified version of set.js & style.css
{name:'Link to Photo Image', key:'P', replaceWith:'[img][![Url]!][/img]'},
// Added by CF Mitrah
{name:'Upload', key:'M',beforeInsert:function(markItUp){InlineUpload.display(markItUp,true)}},
{name:'Browse', key:'F',beforeInsert:function(markItUp){InlineUpload.display(markItUp,false)}},
// Added by CF Mitrah
{name:'Link', key:'L', openWith:'[url=[![Url]!]]', closeWith:'[/url]', placeHolder:'Your text to link here...'},
InlineUpload javascript class will take care of file upload ajax call & browse uploaded images. InlineUpload.js content is,
var upload = false;
var InlineUpload =
{
dialog: null,
block: '',
offset: {},
options: {
container_class: 'markItUpInlineUpload',
form_id: 'inline_upload_form',
action: 'imgUploader.cfm',
inputs: {
file: { label: 'File', id: 'inline_upload_file1', name: 'inline_upload_file1' }
},
submit: { id: 'inline_upload_submit', value: 'upload' },
close: 'inline_upload_close',
iframe: 'inline_upload_iframe'
},
display: function(hash,uploadOption)
{
if(uploadOption){
if( ! $('.markItUpInlineUpload').length)
{
var self = this;
/* Find position of toolbar. The dialog will inserted into the DOM elsewhere
* but has position: absolute. This is to avoid nesting the upload form inside
* the original. The dialog's offset from the toolbar position is adjusted in
* the stylesheet with the margin rule.
*/
this.offset = $(hash.textarea).prev('.markItUpHeader').offset();
/* We want to build this fresh each time to avoid ID conflicts in case of
* multiple editors. This also means the form elements don't need to be
* cleared out.
*/
this.dialog = $([
' ',
].join(''))
.appendTo(document.body)
.hide()
.css('top', this.offset.top)
.css('left', this.offset.left);
//init submit button
$('#'+this.options.submit.id).click(function()
{
if($('#inline_upload_file1').val() == ''){
alert('Please select a file to upload');
return false;
}
upload = true;
$('#'+self.options.form_id).submit().fadeTo('fast', 0.2);
});
// init cancel button
$('#'+this.options.close).click(this.cleanUp);
// form response will be sent to the iframe
$('#'+this.options.iframe).bind('load', function()
{
var result = document.getElementById(''+self.options.iframe)
.contentWindow.document.body.innerHTML;
if(upload){
$('#resultContainer').html(result);
$(".module .products a").click(function() {
src = $(this).attr("href");
alt = $(this).attr("title");
//$.markItUp( {replaceWith:'' });
$.markItUp( {replaceWith:'[img]'+src+'[/img]' });
$("#linkPlugin").fadeOut().css("zIndex", 11);
return false;
});
InlineUpload.dialog.fadeOut().remove();
$("#linkPlugin").fadeIn().css('top', self.offset.top-80).css('left', self.offset.left+460).css("zIndex", 11);
upload = false;
}
});
// Finally, display the dialog
this.dialog.fadeIn('slow');
}
}else{
this.offset = $(hash.textarea).prev('.markItUpHeader').offset();
$('#resultContainer').load('imgUploader.cfm','',function() {
$(".module .products a").click(function() {
src = $(this).attr("href");
alt = $(this).attr("title");
//$.markItUp( {replaceWith:'' });
$.markItUp( {replaceWith:'[img]'+src+'[/img]' });
$("#linkPlugin").fadeOut().css("zIndex", 11);
return false;
});
});
$("#linkPlugin").fadeIn().css('top', this.offset.top-80).css('left', this.offset.left+460).css("zIndex", 11);
}
},
cleanUp: function()
{
InlineUpload.dialog.fadeOut().remove();
}
};
For draggable functionality of browse window, we need following jQuery files jquery.dimensions.js, ui.draggable.ext.js, ui.draggable.js, ui.mouse.js. I added all this jQuery UI related JS files as well as InlineUpload.js in pagetemplates/common_header.cfm page.
<script src="/blog/markitup/jquery.pack.js" type="text/javascript"></script>
<script src="/blog/markitup/jquery.dimensions.js" type="text/javascript"></script>
<script src="/blog/markitup/ui.mouse.js" type="text/javascript"></script>
<script src="/blog/markitup/ui.draggable.js" type="text/javascript"></script>
<script src="/blog/markitup/ui.draggable.ext.js" type="text/javascript"></script>
<script src="/blog/markitup/jquery.markitup.js" type="text/javascript"></script>
<script src="/blog/markitup/InlineUpload.js" type="text/javascript"></script>
<script src="/blog/markitup/sets/default/set.js" type="text/javascript"></script>
I also modified the document ready function to support our functionalities.
<script>
$(document).ready(function() {
$('##markitup').markItUp(mySettings);
// make modules draggable
dragProp = { handle:".handle", zIndex:100, opacity:0.9, scroll:1 };
$('##linkPlugin').hide().draggable( dragProp );
$('.close').click(function() {
$(this).parent().parent().hide();
return false;
});
$('.handle').click(function() {
return false;
});
// use markItUp! features when clicking on "add to editor" link in a module
$(".module .products a").click(function() {
src = $(this).attr("href");
alt = $(this).attr("title");
$.markItUp( {replaceWith:'' });
return false;
});
});
</script>
I have added new container div in that page. Once the user click on the browse button, this div will populate using ajax call.
<div id="linkPlugin">
<div class="toolbar">
<a href="##" class="handle">Move</a>
<a href="##" class="close">Close</a>
</div>
<div id="resultContainer" class="module"> </div>
</div>
ImgUploader.cfm is responsible for server side file upload & directory read operation for user's folder.It is a POC, So my CF code is not 100% optimized as well as I didn't coded for MIME/File upload security issue. It is a simple upload & Directory listing functionality, so please optimize yourself
<cfsilent>
<cfset uName = getAuthUser()>
<cfif uName neq ''>
<cfset userid = application.user.getUserID(getAuthUser())>
<cfset userDir = ExpandPath( './userfiles/#uName#' )>
<cfset userWebDir = "userfiles/#uName#">
<cfif not DirectoryExists(userDir)>
<cfdirectory action="create" mode="777" directory="#userDir#">
</cfif>
<cfif isDefined("form.fieldnames")>
<cfloop index="strFileIndex" from="1" to="#listlen(form.FIELDNAMES)#" step="1">
<cfset strField = "inline_upload_file#strFileIndex#" />
<cfif ( StructKeyExists( FORM, strField ) AND Len( FORM[ strField ] ) )>
<cffile action="upload" filefield="#strField#" destination="#userDir#" nameconflict="makeunique" result="upRes" />
</cfif>
</cfloop>
</cfif>
<cfdirectory action="list" name="qFiles" directory="#userDir#">
</cfif>
</cfsilent>
<cfif uName eq ''><h3>Login error</h3><div><br />Please login again<br /><br /></div><cfabort></cfif>
<h3>Pictures</h3>
<div style="display: block;" class="products slide">
<table width="100%" border="0" cellpadding="2" cellspacing="0">
<tbody>
<cfoutput query="qFiles">
<cfif qFiles.currentrow eq 0><tr></cfif>
<td scope="col" width="50">
<a href="#application.settings.rootURL#/#userWebDir#/#name#" title="#left(name,len(name)-4)#">
<img src="#userWebDir#/#name#" alt="Product 1" width="50" border="0" height="50">
</a>
</td>
<cfif qFiles.currentrow mod 4 eq 0 and qFiles.currentrow neq 0></tr><tr></tr></cfif>
</cfoutput>
</tbody></table>
</div>
You can download all modified files here
Nov 14, 2010 at 10:31 AM Hi,
this plugin for markItUp is great!
I'm going to use it in my new content management system.
regards
René
Jan 11, 2011 at 7:59 PM When user clicks upload icon i want that link to open in a new window. How can I add static url to the set.js.
Jan 13, 2011 at 1:20 AM In set.js, instead of calling InlineUpload.display function, you should wrote your own JS function which will open pop-up window. Then call that JS function in the beforeInsert event of upload icon.
{name:'Upload', key:'M',beforeInsert:function(markItUp){CallYourJSFunctionWhichOpenPop-UpWindow()}}
Apr 15, 2011 at 3:00 AM i do it just as you said,but it doesn't work, i use php develop, what is the problem ,can you help me ?
Apr 15, 2011 at 3:13 AM what is the problem you are facing? contact me through email.
May 2, 2011 at 2:05 AM yes ,it is php code, it invoke php code thorough ajax call, it make errors from javascript code ,can you help me?i hava sent a email to your mailbox.thanks
May 3, 2011 at 7:24 AM Hi
I have a linux/php5 server, what modification can i do in ImgUploader.cfm to work with my server ?
May 4, 2011 at 6:18 AM Markitup image upload plugin will submit all form fields to action page (in your case it is a PHP file) using post method. Please change action file handler name in to your php file in InlineUpload.js. Something like action: 'imgUploader.php'. And then do file upload operation in your PHP code. Sorry I don't have idea in PHP coding to provide you sample on that.
May 5, 2011 at 8:06 AM i need a sample of php code for upload image