How to highlight friends name in Facebook status update box (textarea)? - facebook

In Facebook status update box, when I type # and start typing and choose a name, say Steven Gerrard, from the friends list suggested by fb, my friend's name is highlighted in the textarea like this
I checked with Firebug and there's only
a div.highlighter which contains sort of formated text (Steven Gerrard is within b tags)
a textarea inside a div.uiTypeahead. Nothing interesting i could find
and a hidden input, that contains the actual text that will be posted: #[100001915747xxx:Steven Gerrard] is awesome
What is the secret trick behind this? Normal rich text editors like ckeditor usually have an iframe to display the text and an actual textarea to keep the original content. But in this case, I do not see anything. Someone please shed some lights?
I would like to make something like this but have no clue where to begin. Also, if I would like to display a small thumb next to my friend's name, is it possible at all?

Here is how it works:
You superpose the textarea (in front) and a div (behind) that will have the same size, and the same font size.
The textarea must have a transparent background, so we can see its text, but also see the div behind it.
The div behind it will have a white text and white background, so the text it contains will be transparent.
You set a hook on the textarea's keyup, and you process the text it contains as HTML: replace the line breaks by <br/>, replace the double spaces by , and also replace all the words that you want to highlight by a version surrounded by <span style="background-color: #D8DFEA;"></span>.
Since you can see the highlight div behind the textarea, and that the text the highlight div contains is perfectly aligned with the text in the textarea, and that the <span> is visible, you will have the illusion that the text in the textarea is highlighted.
I've written a quick example based on jquery so you can try it yourself, without too much code to analyze.
Here is a sample code you can just copy-paste-save and try:
This sample code will highlight a defined set of word, here: "hello" and "world".
I'll let you adapt it the way you want.
<html>
<head>
<title></title>
<!-- Load jQuery -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<!-- The javascript xontaining the plugin and the code to init the plugin -->
<script type="text/javascript">
$(function() {
// let's init the plugin, that we called "highlight".
// We will highlight the words "hello" and "world",
// and set the input area to a widht and height of 500 and 250 respectively.
$("#container").highlight({
words: ["hello","world"],
width: 500,
height: 250
});
});
// the plugin that would do the trick
(function($){
$.fn.extend({
highlight: function() {
// the main class
var pluginClass = function() {};
// init the class
// Bootloader
pluginClass.prototype.__init = function (element) {
try {
this.element = element;
} catch (err) {
this.error(err);
}
};
// centralized error handler
pluginClass.prototype.error = function (e) {
// manage error and exceptions here
//console.info("error!",e);
};
// Centralized routing function
pluginClass.prototype.execute = function (fn, options) {
try {
options = $.extend({},options);
if (typeof(this[fn]) == "function") {
var output = this[fn].apply(this, [options]);
} else {
this.error("undefined_function");
}
} catch (err) {
this.error(err);
}
};
// **********************
// Plugin Class starts here
// **********************
// init the component
pluginClass.prototype.init = function (options) {
try {
// the element's reference ( $("#container") ) is stored into "this.element"
var scope = this;
this.options = options;
// just find the different elements we'll need
this.highlighterContainer = this.element.find('#highlighterContainer');
this.inputContainer = this.element.find('#inputContainer');
this.textarea = this.inputContainer.find('textarea');
this.highlighter = this.highlighterContainer.find('#highlighter');
// apply the css
this.element.css('position','relative');
// place both the highlight container and the textarea container
// on the same coordonate to superpose them.
this.highlighterContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '1px dashed #ff0000',
'width': this.options.width,
'height': this.options.height,
'cursor': 'text'
});
this.inputContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '1px solid #000000'
});
// now let's make sure the highlit div and the textarea will superpose,
// by applying the same font size and stuffs.
// the highlighter must have a white text so it will be invisible
this.highlighter.css({
'padding': '7px',
'color': '#eeeeee',
'background-color': '#ffffff',
'margin': '0px',
'font-size': '11px',
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif'
});
// the textarea must have a transparent background so we can see the highlight div behind it
this.textarea.css({
'background-color': 'transparent',
'padding': '5px',
'margin': '0px',
'font-size': '11px',
'width': this.options.width,
'height': this.options.height,
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif'
});
// apply the hooks
this.highlighterContainer.bind('click', function() {
scope.textarea.focus();
});
this.textarea.bind('keyup', function() {
// when we type in the textarea,
// we want the text to be processed and re-injected into the div behind it.
scope.applyText($(this).val());
});
} catch (err) {
this.error(err);
}
return true;
};
pluginClass.prototype.applyText = function (text) {
try {
var scope = this;
// parse the text:
// replace all the line braks by <br/>, and all the double spaces by the html version
text = this.replaceAll(text,'\n','<br/>');
text = this.replaceAll(text,' ',' ');
// replace the words by a highlighted version of the words
for (var i=0;i<this.options.words.length;i++) {
text = this.replaceAll(text,this.options.words[i],'<span style="background-color: #D8DFEA;">'+this.options.words[i]+'</span>');
}
// re-inject the processed text into the div
this.highlighter.html(text);
} catch (err) {
this.error(err);
}
return true;
};
// "replace all" function
pluginClass.prototype.replaceAll = function(txt, replace, with_this) {
return txt.replace(new RegExp(replace, 'g'),with_this);
}
// don't worry about this part, it's just the required code for the plugin to hadle the methods and stuffs. Not relevant here.
//**********************
// process
var fn;
var options;
if (arguments.length == 0) {
fn = "init";
options = {};
} else if (arguments.length == 1 && typeof(arguments[0]) == 'object') {
fn = "init";
options = $.extend({},arguments[0]);
} else {
fn = arguments[0];
options = $.extend({},arguments[1]);
}
$.each(this, function(idx, item) {
// if the component is not yet existing, create it.
if ($(item).data('highlightPlugin') == null) {
$(item).data('highlightPlugin', new pluginClass());
$(item).data('highlightPlugin').__init($(item));
}
$(item).data('highlightPlugin').execute(fn, options);
});
return this;
}
});
})(jQuery);
</script>
</head>
<body>
<div id="container">
<div id="highlighterContainer">
<div id="highlighter">
</div>
</div>
<div id="inputContainer">
<textarea cols="30" rows="10">
</textarea>
</div>
</div>
</body>
</html>
Let me know if you have any question or if you need help with this code.

After reviewing the way of Facebook do this, I see that the text shown on the screen is:
<span class="highlighterContent"><b>Ws Dev</b> is good</span>
That span is put in a table (with lots of div container), which is style accordingly.
So I think this is the process:
When you type in the box, Facebook does have a textarea that capture what you type, but use javascript to show the typed HTML content in a table.
When you submit, the formatted content in a hidden input (that you already spot in the question) get submitted. It's like "#[100001915747xxx:Steven Gerrard] is awesome".
When the formatted message submit, it is saved to the database. Everytime the page get loaded, from the saved message the HTML is composed and return.
To get the similar effect, you can use any jQuery autocomplete plugin.

Related

Convert Excel form window to Google Sheets window

As you've probably found, there appears to be no equivalent way to add the following Excel form and associated VBA code to Google Sheets or Scripts or Forms:
Is there some add-in that can be used to pop up this image and its controls? This has to be used many times in an accounting sheet to categorize expenditures at tax time.
It may not look exactly the same but I was able to construct a custom dialog in a short period of time to show how HTML service can be used to produce similar results.
First I construct an HTML template that contains the 2 combo boxes with multiple lines.
HTML_Test.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('CSS_Test'); ?>
</head>
<body>
<div id="left">
<label for="expenseCategory">Expense Category</label><br>
<select id="expenseCategory" size="10">
</select>
</div>
<div id="middle">
<label for="expenseSubCategory">Expense Sub Category</label><br>
<select id="expenseSubCategory" size="10">
</select>
</div>
<?!= include('JS_Test'); ?>
</body>
</html>
Then a CSS file to contain all my element formatting.
CSS_Test.html
<style>
#expenseCategory {
width: 90%;
}
#expenseSubCategory {
width: 90%;
}
#left {
width: 25%;
float: left;
}
#middle {
width: 50%;
float: left;
}
</style>
And a javascript file for client side javascript. I've simply hard coded some data to show how the select elements are filled in but this could just as easily be done using template scripting, or google.script.run
<script>
var expenses = [["A","1","2","3"],
["B","4","5"],
["C","6","7","8","9","10"]
];
function expenseCategoryOnClick() {
try {
let expenseCategory = document.getElementById('expenseSubCategory');
expenseCategory.options.length = 0;
expenses[this.selectedIndex].forEach( (expense,index) => {
if( index > 0 ) {
let option = document.createElement("option");
let text = document.createTextNode(expense);
option.appendChild(text);
expenseCategory.appendChild(option);
}
}
);
}
catch(err) {
alert("Error in expenseCategoryOnClick: "+err)
}
}
(function () {
// load first expense
let expenseCategory = document.getElementById('expenseCategory');
expenseCategory.addEventListener("click",expenseCategoryOnClick);
expenses.forEach( expense => {
let option = document.createElement("option");
let text = document.createTextNode(expense[0]);
option.appendChild(text);
expenseCategory.appendChild(option);
}
);
expenseCategory = document.getElementById('expenseSubCategory');
expenses[0].forEach( (expense,index) => {
if( index > 0 ) {
let option = document.createElement("option");
let text = document.createTextNode(expense);
option.appendChild(text);
expenseCategory.appendChild(option);
}
}
);
}
)();
</script>
Then there is the server side code bound to a spreadsheet.
Code.gs
function onOpen(e) {
var menu = SpreadsheetApp.getUi().createMenu("Test");
menu.addItem("Show Test","showTest");
menu.addToUi();
}
// include(filename) required to include html files in the template
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
function showTest() {
var html = HtmlService.createTemplateFromFile("HTML_Test");
html = html.evaluate();
html.setWidth(800);
SpreadsheetApp.getUi().showModalDialog(html,"Test");
}
The dialog looks like this. Many more html elements can be added as needed. This just shows the basics. This may be more difficult than an wysiwig html editor but I find I have better control of the appearance and function of my pages this way. Notice I clicked "C" and the sub category is filled in automatically.

Drag and Drop into Fabric.js canvas

How can I drop items (like image, or other object from other canvas) into canvas which is managed by fabricjs? I have found many examples how to move items inside canvas but I would like to drag and drop item from outer element into canvas.
Since you asked for an example and I haven't tried it out myself yet, here goes:
Example Fiddle
Markup
<div id="images">
<img draggable="true" src="http://i.imgur.com/8rmMZI3.jpg" width="250" height="250"></img>
<img draggable="true" src="http://i.imgur.com/q9aLMza.png" width="252" height="295"></img>
<img draggable="true" src="http://i.imgur.com/wMU4SFn.jpg" width="238" height="319"></img>
</div>
<div id="canvas-container">
<canvas id="canvas" width="800" height="600"></canvas>
</div>
JS Breakdown
1. Fabric.canvas instance
First we want our canvas, of course:
var canvas = new fabric.Canvas('c');
2. Feature Detection (optional)
Not sure this is necessary, since the fact that you have a canvas makes it very likely that the browser has Drag and Drop as well. Were you to use it, you can do so like this, using Modernizr:
if (Modernizr.draganddrop) {
// Browser supports HTML5 DnD.
// Bind the event listeners for the image elements
// Bind the event listeners for the canvas
} else {
// Replace with a fallback to a library solution.
alert("This browser doesn't support the HTML5 Drag and Drop API.");
}
3. Events
Again, unlike the source article I below, the source and target elements are different (in that articles's example, you just move divs around within the same parent container), so I failed to notice that some of the events are meant for the element being dragged, but most are bound to the element into which you are dropping.
NOTE: I know this is technically a question about Fabric.js, but it's really kind of a question about Drag and Drop in the context of adding objects to a <canvas> with Fabric.js, which is why I'm going a bit more in depth about the DnD stuff now.
For the <img>
dragstart (I added a class here to lower the opacity)
dragend (and removed that class here)
For #canvas-container:
dragenter (added a class to give the canvas container that nifty dotted line)
dragover: Here you can set the event.dataTransfer.dropEffect property to show one of the native cursor types. The default would be 'move' here, but I set it to 'copy' since I don't actually remove the <img> element (in fact in the fiddle you can, for example create several McClures).
dragleave (removed the dotted line here)
drop: The handler for this event creates and adds the fabric.Image object (see the fiddle).
if (Modernizr.draganddrop) {
// Browser supports HTML5 DnD.
// Bind the event listeners for the image elements
var images = document.querySelectorAll('#images img');
[].forEach.call(images, function (img) {
img.addEventListener('dragstart', handleDragStart, false);
img.addEventListener('dragend', handleDragEnd, false);
});
// Bind the event listeners for the canvas
var canvasContainer = document.getElementById('canvas-container');
canvasContainer.addEventListener('dragenter', handleDragEnter, false);
canvasContainer.addEventListener('dragover', handleDragOver, false);
canvasContainer.addEventListener('dragleave', handleDragLeave, false);
canvasContainer.addEventListener('drop', handleDrop, false);
} else {
// Replace with a fallback to a library solution.
alert("This browser doesn't support the HTML5 Drag and Drop API.");
}
Sources:
HTML5 Rocks - Native HTML5 Drag and Drop
Modernizr
Web Platform Docs > DOM > Properties - dropEffect
Web Platform Docs > DOM > Events
dragstart
dragend
dragenter
dragover
dragleave
drop
I had gone through fiddle of #natchiketa, And fixed the problem , just check this fiddle..
http://jsfiddle.net/Ahammadalipk/w8kkc/185/
window.onload = function () {
var canvas = new fabric.Canvas('canvas');
/*
NOTE: the start and end handlers are events for the <img> elements; the rest are bound to
the canvas container.
*/
function handleDragStart(e) {
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
this.classList.add('img_dragging');
}
function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault();
}
e.dataTransfer.dropEffect = 'copy';
return false;
}
function handleDragEnter(e) {
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over');
}
function handleDrop(e) {
if (e.stopPropagation) {
e.stopPropagation(); // stops the browser from redirecting.
}
var img = document.querySelector('#images img.img_dragging');
var newImage = new fabric.Image(img, {
width: img.width,
height: img.height,
// Set the center of the new object based on the event coordinates relative
// to the canvas container.
left: e.layerX,
top: e.layerY
});
newImage.hasControls = newImage.hasBorders = false;
canvas.add(newImage);
return false;
}
function handleDragEnd(e) {
// this/e.target is the source node.
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
}
if (Modernizr.draganddrop) {
var images = document.querySelectorAll('#images img');
[].forEach.call(images, function (img) {
img.addEventListener('dragstart', handleDragStart, false);
img.addEventListener('dragend', handleDragEnd, false);
});
var canvasContainer = document.getElementById("canvas-container");
canvasContainer.addEventListener('dragenter', handleDragEnter, false);
canvasContainer.addEventListener('dragover', handleDragOver, false);
canvasContainer.addEventListener('dragleave', handleDragLeave, false);
canvasContainer.addEventListener('drop', handleDrop, false);
} else {
alert("This browser doesn't support the HTML5 Drag and Drop API.");
}
}
Thanks
Well, the question is quite old^^
I have updateted the fiddle, no it will work in Firefox as well.
Fiddle
function handleDrop(e) {
// this / e.target is current target element.
e.preventDefault(); //I've altert this line for FireFox
As far as I understand, drag and drop is not already provided by fabricjs,
fiddling it will be quite interesting.
Well I m new to javascript and fabricJS but I think this fiddle might help
fiddle
html code
<div class="img_cont">
<img class="img" id="ele1" draggable="true" ondragstart="dragElement(event)" src="https://webkit.org/wp-content/uploads/STP-300x300.png">
<img class="img" id="ele2" draggable="true" ondragstart="dragElement(event)" src="https://webkit.org/wp-content/uploads/ephy-webkit-graphic.png">
<img class="img" id="ele3" draggable="true" ondragstart="dragElement(event)" src="https://res.cloudinary.com/css-tricks/image/upload/w_600,q_auto,f_auto/buysellads/uu/7/112766/1646327381-MC_CSSTricks_Logo_600x600-_1_.png">
<img class="img" id="ele4" draggable="true" ondragstart="dragElement(event)" src="https://miro.medium.com/max/1400/1*9hd_8qR0CMZ8L0pVbFLjDw.png">
</div>
<br>
<div id="canvas_cont" ondragover="allowDrop(event)" ondrop="dropElement(event)">
<canvas id="canvas" width="650" height="350" ></canvas>
</div>
javascript code
// allowDrop function called on ondragover event.
function allowDrop(e) {
e.preventDefault();
}
//dragElement function called on ondrag event.
function dragElement(e) {
e.dataTransfer.setData("id", e.target.id); //transfer the "data" i.e. id of the target dragged.
}
//Initializing fabric canvas on window load event.
var canvas;
window.onload = function(){
canvas = new fabric.Canvas(document.getElementById("canvas"));
}
//dropElement function called on ondrop event.
function dropElement(e) {
e.preventDefault();
var data = e.dataTransfer.getData("id"); //receiving the "data" i.e. id of the target dropped.
var imag = document.getElementById(data); //getting the target image info through its id.
var img = new fabric.Image(imag, { //initializing the fabric image.
left: e.layerX - 80, //positioning the target on exact position of mouse event drop through event.layerX,Y.
top: e.layerY - 40,
});
img.scaleToWidth(imag.width); //scaling the image height and width with target height and width, scaleToWidth, scaleToHeight fabric inbuilt function.
img.scaleToHeight(imag.height);
canvas.add(img);
}
The accepted answer no longer works.
This is for drag and drop from desktop using the dataTransfer interface.
canvas.on('drop', function(event) {
// prevent the file to open in new tab
event.e.stopPropagation();
event.e.stopImmediatePropagation();
event.e.preventDefault();
// Use DataTransfer interface to access the file(s)
if(event.e.dataTransfer.files.length > 0){
var files = event.e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (f.type.match('image.*')) {
// Read the File objects in this FileList.
var reader = new FileReader();
// listener for the onload event
reader.onload = function(evt) {
// put image on canvas
fabric.Image.fromURL(evt.target.result, function(obj) {
obj.scaleToHeight(canvas.height);
obj.set('strokeWidth',0);
canvas.add(obj);
});
};
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
}
});
Resources
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop

Wordpress shortcode preview in tinyMCE

I've written a shortcode and its functioning like it should. Now the hard part:
I would like to show the user a preview already in the tinyMCE editor. Loading CSS in the editor is not a problem for me, but i would love to know if it is possible to already process the shortcode within TinyMCE.
Thanks!
Let the code talk:
I'll put a code to add a visual icon for highlight content word(s) shortcode, and you can then implement any other shortcode you want with the same logic,
class spot_shortcodes {
function spot_shortcodes()
{
add_action('init', array(&$this, 'init'));
}
function init(){
// Enable shortcodes in text widgets
add_filter( 'widget_text', 'do_shortcode' );
// Fix for large posts, http://core.trac.wordpress.org/ticket/8553
#ini_set( 'pcre.backtrack_limit', 500000 );
// init process for button control
add_filter( 'tiny_mce_version', 'my_refresh_mce');
// Add only in Rich Editor mode
if ( get_user_option('rich_editing') == 'true') {
add_filter('mce_buttons_3', array(&$this, 'register_highlight_button'));
}
}
// Add your button plugin js code to tinyMCE
// codex: wp_register_script( $handle, $src, $deps, $ver, $in_footer );
wp_register_script( 'effects-highlight', SPOT_SHORTCODES_URL . '/js/jquery.effects.highlight.js', false ,SPOT_SHORTCODES_URL, true );
function add_youtube_button() {
// Don't bother doing this stuff if the current user lacks permissions
if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') )
return;
// Add only in Rich Editor mode
if ( get_user_option('rich_editing') == 'true') {
add_filter("mce_external_plugins", array(&$this, "add_youtube_tinymce_plugin"));
add_filter('mce_buttons', array(&$this, 'register_highlight_button'));
}
}
// function to register you button to tinyMCE dashboard
function register_highlight_button($buttons) {
array_push($buttons, "|", 'highlight_button');
return $buttons;
}
function add_youtube_tinymce_plugin($plugin_array) {
// your icon image(highlight.png) which will be displayed in the tinyMCE dashboard
$plugin_array['highlight'] = SPOT_TINYMCE_URL . '/icons-lib-custom.js';
return $plugin_array;
}
} // class end
// Finally make an object from your button
$spot_shortcodes = new spot_shortcodes();
Our js code for the highlight button option
make an dot js file put the followin code in it and put it in the tinyMCE plugin directory
// dont forget to change the paths
tinymce.create('tinymce.plugins.highlight', {
// creates control instances based on the control's id.
// our button's id is "highlight_button"
createControl : function(id, controlManageradel) {
if (id == 'highlight_button') {
// creates the button
var button = controlManageradel.createButton('highlight', {
title : 'Add a Hightlight Text', // title of the button
image :spotShortcodes.plugin_folder +"/tinymce/images/highlight.png", // path to the button's image
onclick : function() {
// triggers the thickhighlight
var width = jQuery(window).width(), H = jQuery(window).height(), W = ( 720 < width ) ? 720 : width;
W = W - 80;
H = H - 84;
tb_show( 'Insert text box shortcode', '#TB_inline?width=' + W + '&height=' + H + '&inlineId=highlight-form' );
}
});
return button;
}
return null;
}
});
// registers the plugin. DON'T MISS THIS STEP!!!
tinymce.PluginManager.add('highlight', tinymce.plugins.highlight);
// executes this when the DOM is ready
jQuery(function(){
// creates a form to be displayed everytime the button is clicked
// you should achieve this using AJAX instead of direct html code like this
var form = jQuery('<div id="highlight-form"><table id="highlight-table" class="form-table" style="text-align: left">\
\
\
<tr>\
<th><label class="title" for="highlight-bg">Highlight color</label></th>\
<td><select name="bg" id="highlight-bg">\
<option value="#f02d33">Red</option>\
<option value="#b6bbbd">Grey</option>\
<option value="#3e3c3c">Darkgrey</option>\
<option value="#99cc33">Lightgreen</option>\
<option value="#6c8c2d">Darkgreen</option>\
<option value="#0f5ac6">Blue</option>\
<option value="#3cbcf7">Cyan</option>\
<option value="#9219f8">Purple</option>\
<option value="#fcc016">Yellow</option>\
<option value="#f65e0e">Orange</option>\
</select><br />\
<div class="info"><small>Select box type.</small></div></td>\
</tr>\
<tr>\
<th><label class="title" for="highlight-contet">Conent</label></th>\
<td><textarea rows="7"\ cols="45"name="content" id="highlight-content">hightlight text</textarea>\
<br />\
<div><small>this text displayed in box.</small></div></td>\
</tr>\
</table>\
<p class="submit">\
<input type="button" id="highlight-submit" class="button-primary" value="Insert shortcode" name="submit" style=" margin: 10px 150px 50px; float:left;"/>\
</p>\
</div>');
var table = form.find('table');
form.appendTo('body').hide();
// handles the click event of the submit button
form.find('#highlight-submit').click(function(){
// defines the options and their default values
// again, this is not the most elegant way to do this
// but well, this gets the job done nonetheless
var options = {
'bg' : '#f02d33',
'content' : 'hightlight text',
};
var shortcode = '[highlight ';
for( var index in options) {
var value = table.find('#highlight-' + index).val();
// attaches the attribute to the shortcode only if it's different from the default value
if ( value !== options[index] & index !== 'content')
shortcode += ' ' + index + '="' + value + '"';
}
shortcode += ']'+ value + '[/highlight]'
// inserts the shortcode into the active editor
tinyMCE.activeEditor.execCommand('mceInsertContent', 0, shortcode);
// closes Thickhighlight
tb_remove();
});
});
I hope this help, give me you feedback if you want any more explanation, thanks.

Does codemirror provide Cut, Copy and Paste API?

From http://codemirror.net/doc/manual.html, I only find getRange(),
undo(), redo() etc, and I can't find cut(), copy() and paste API,
and more when I try to run editor.execCommand("cut"), I get the error.
Could you help me? Thanks!
Using clipboard.js, you can define the text() function to grab the value of the CodeMirror's inner document.
Store a reference to the (<textarea>) editor's selector for convenience.
var editorSelector = '#editor' // or '#editor + .CodeMirror';
Instantiate a new ClipBoard object with reference to your button.
new Clipboard('.clip-btn-native', {
text: function(trigger) {
return getCodeMirrorNative(editorSelector).getDoc().getValue();
}
});
Retrieve a CodeMirror Instance via native JavaScript.
function getCodeMirrorNative(target) {
var _target = target;
if (typeof _target === 'string') {
_target = document.querySelector(_target);
}
if (_target === null || !_target.tagName === undefined) {
throw new Error('Element does not reference a CodeMirror instance.');
}
if (_target.className.indexOf('CodeMirror') > -1) {
return _target.CodeMirror;
}
if (_target.tagName === 'TEXTAREA') {
return _target.nextSibling.CodeMirror;
}
return null;
};
Demo
Please see complete; in-depth demo over at JSFiddle.
There are no CodeMirror APIs for cut/copy/paste because browser security restrictions forbid JavaScript from accessing the clipboard programmatically. Paste could be used to steal private data and Cut/Copy can be used as a more elaborate attack vector.
The browser's own native code handles user gestures that access the clipboard (keyboard shortcuts and context menu items), based solely on the currently selected text or focused text field.
This SO thread has a good summary of attempts to work around these restrictions. CodeMirror's approach is the first bullet: it uses a hidden textarea to ensure that user clipboard gestures work, but that still doesn't support programmatic APIs.
But there is a partial workaround: use a small Flash widget (this is the 2nd bullet in the thread above). Flash relaxes the restrictions on Copy/Cut (but not Paste) a bit. It still has to be triggered by some user event, but it could be something like clicking a button in your HTML UI. Wrappers like ZeroClipboard and Clippy make it simple to access to these capabilities without needing to know Flash. You'd need to write a little glue code to pull the appropriate string from CodeMirror when copying, but it shouldn't be too bad.
Add a hidden contenteditable div to your textarea editor wrapper. Contenteditable divs respect new lines and tabs, which we need when copying code.
Here is my CodePen demo
var content = $('.content');
var toCopy = content.find('.copy-this');
// initialize the editor
var editorOptions = {
autoRefresh: true,
firstLineNumber: 1,
lineNumbers: true,
smartIndent: true,
lineWrapping: true,
indentWithTabs: true,
refresh: true,
mode: 'javascript'
};
var editor = CodeMirror.fromTextArea(content.find(".editor")[0], editorOptions);
content[0].editor = editor;
editor.save();
// set editors value from the textarea
var text = content.find('.editor').text();
editor.setValue(text);
// setting with editor.getValue() so that it respects \n and \t
toCopy.text(editor.getValue());
$(document).on('click', '.copy-code', function() {
var content = $(this).closest('.content');
var editor = content[0].editor;
var toCopy = content.find('.copy-this')[0];
var innerText = toCopy.innerText // using innerText here because it preserves newlines
// write the text to the clipboard
navigator.clipboard.writeText(innerText);
});
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.CodeMirror {
height: fit-content !important;
}
.copy-code {
background: #339af0;
width: fit-content;
cursor: pointer;
}
<!-- resources -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.css" />
<script src="https://codemirror.net/lib/codemirror.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.40.0/mode/javascript/javascript.min.js"></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="content">
<!-- button to copy the editor -->
<div class="copy-code" title="copy code">copy</div>
<!-- add contenteditable div as it respects new lines when copying unlike textarea -->
<div class="copy-this" contenteditable style="display: none"></div>
<textarea class="editor" style="display: none;">// here is a comment
// here is another comment
</textarea>
</div>

sort multiple items at once with jquery.ui.sortable

did somebody manage to sort multiple items at once with jquery.ui.sortable?
we are working on a photo managing app.
select multiple items
drag them to a new location.
thanx
I had a similar requirement, but the solution in the accepted answer has a bug. It says something like "insertBefore of null", because it removes the nodes.
And also i tried jQuery multisortable, it stacks the selected items on top of each other when dragging, which is not what i want.
So I rolled out my own implementation and hope it will save others some time.
Fiddle Link.
Source code:
$( "#sortable" ).sortable({
// force the cursor position, or the offset might be wrong
cursorAt: {
left: 50,
top: 45
},
helper: function (event, item) {
// make sure at least one item is selected.
if (!item.hasClass("ui-state-active")) {
item.addClass("ui-state-active").siblings().removeClass("ui-state-active");
}
var $helper = $("<li><ul></ul></li>");
var $selected = item.parent().children(".ui-state-active");
var $cloned = $selected.clone();
$helper.find("ul").append($cloned);
// hide it, don't remove!
$selected.hide();
// save the selected items
item.data("multi-sortable", $cloned);
return $helper;
},
stop: function (event, ui) {
// add the cloned ones
var $cloned = ui.item.data("multi-sortable");
ui.item.removeData("multi-sortable");
// append it
ui.item.after($cloned);
// remove the hidden ones
ui.item.siblings(":hidden").remove();
// remove self, it's duplicated
ui.item.remove();
}
});
There's a jQuery UI plugin for that: https://github.com/shvetsgroup/jquery.multisortable
jsFiddle: http://jsfiddle.net/neochief/KWeMM/
$('ul.sortable').multisortable();
... or just define a 'items' option to your multisortable that way (for example) :
$('table tbody').multisortable({
items: 'tr'
});
you can use shvetsgroup/jquery.multisortable
but it will create problem.. because, that js is designed only for tags...
but customize it to use it, its very simple i'll tell you how????
at first download that .js and use it in your program...
step 1. open the js file...now edit the following lines...
$.fn.multiselectable.defaults = {
click: function(event, elem) {},
mousedown: function(event, elem) {},
selectedClass: 'selected',
items: 'li'
};
the above are lines from 107 to 112....
there you can see "items: 'li'
in that use your tag which you are used to enclose those image like if you are using, or or anything you are using like this
$.fn.multiselectable.defaults = {
click: function(event, elem) {},
mousedown: function(event, elem) {},
selectedClass: 'selected',
items: 'div' // or any tag you want...
};
and 249 to 254
selectedClass: 'selected',
placeholder: 'placeholder',
items: 'li'
};
}(jQuery);
change the line " item:'li' " with your tag like this
selectedClass: 'selected',
placeholder: 'placeholder',
items: 'div' // or anything else
};
}(jQuery);
if you are working on textboxes inside those envelopes.. you have to get rid of these lines too
// If no previous selection found, start selecting from first selected item.
prev = prev.length ? prev : $(parent.find('.' + options.selectedClass)[0]).addClass('multiselectable-previous');
var prevIndex = prev.index();
after that comment line...
add a line code that search textbox or check box or any interaction element inside it...
like this..
// If no previous selection found, start selecting from first selected item.
item.children("input").focus(); // customize this code to get your element focus...
prev = prev.length ? prev : $(parent.find('.' + options.selectedClass)[0]).addClass('multiselectable-previous');
var prevIndex = prev.index();
and also to indicate selected tags or elements... use styles like this
div { margin: 2px 0; cursor: pointer; }
div.selected { background-color: orange }
div.child { margin-left: 20px; }
actually i used div.. instead of that you can use any tag you wish...
hope will help u.... if it is not... read again.. and ask again....
wishes