Solved

JavaScript cleanup pasted content during onpaste of DIV

Posted on 2008-10-26
13
2,930 Views
Last Modified: 2010-04-21
How do I get the text which is about to be pasted from the clipboard during the onpaste event which occurs when the user pastes text into the contentEditable DIV?

This needs to be a cross-browser solution.

The onpaste event is not fired in all browsers by default, but I found a website which describes how to get the onpaste event to fire across all major browsers (http://www.actsascommunity.com/snippets/6).
<html>

<head>

	<title>Demo</title>

	<script type="text/javascript" src="prototype.js"></script>

	<script type="text/javascript">

		// Following three methods taken from: http://www.actsascommunity.com/snippets/6

		// Verified: 5:25 PM 26/10/2008

		function checkForPaste(event) {

			var e = event.element();

			if ((e.previousValue && e.value.length > e.previousValue.length + 1) || (!e.previousValue && e.value.length > 1)) { 

				if (e.onpaste)

					e.onpaste(e)

				else if (e.readAttribute("onpaste"))

					eval(e.readAttribute("onpaste"));

			}

			e.previousValue = e.value;

		}

		function firefoxOnPaste() {

			$$('div').each(function(e) { 

				if (e.contentEditable)

					if (e.onpaste || e.readAttribute("onpaste"))

						Event.observe(e,'input',checkForPaste);

			});

		}

		if (Prototype.Browser.Gecko) {

			document.observe('dom:loaded', firefoxOnPaste);

		}
 

		function editor_onPaste(event) {

			// This method is fired to handle the editor paste event.

			// Method is fired in IE, FF, Chrome, and Safari upon pasting into the editable DIV.
 

			//// Alert to verify that event is being fired.

			//alert('pasted');
 

			// QUESTION: How do I get the text which is about to be pasted from

			// the clipboard? This needs to be cross-browser solution.

//			var pasteText = ???
 

			// I actually have the following two points working already.
 

			// 1. Here is where I will process and cleanup the pasted text.

			// 2. And here is where I will insert it into the DIV at the caret position.

		}

	</script>

</head>

<body>

	<div style="min-height: 300px; border: solid 1px gray; padding: 6px" contentEditable="true" onpaste="editor_onPaste(event || window.event)">

	</div>

</body>

</html>

Open in new window

0
Comment
Question by:numberkruncher
  • 7
  • 6
13 Comments
 
LVL 16

Expert Comment

by:sh0e
Comment Utility
So, what this code does is check if the length of the text has changed more than 1 character.
All you have to do is use e.value.substring(e.previousValue.length);
0
 
LVL 16

Expert Comment

by:sh0e
Comment Utility
I also want to mention that most of the methods, including this one, are outdated since onpaste is implemented in FF3, and oninput no longer fires when you paste.  Also, FF3 doesn't give you access to clipboard data.
0
 
LVL 13

Author Comment

by:numberkruncher
Comment Utility
The user might not necessarily be entering text at the end of the DIV element. So instead of getting a sub-string from the end of the input field, I would need to get it using the selection range instead. How reliable would you suggest that this approach would be?

That's interesting, I didn't realise that second point.

I will have to read up on the new FF3 events on the Mozilla documentation website. Is there an event which fires no matter how the DIV content is changed? Like 'onchange' at a guess?

I am basically trying to constrain the types of content that can be contained within the editable field. It would be fantastic if it were possible to create a single solution which also covered dragged and dropped content....this might be asking too much of JavaScript I fear.

Obviously I am not 100% reliant on valid data being transmitted by the client because the server does validate upon receipt. At the moment I am just concerned about maintaining an accurate representation for the user.
0
 
LVL 16

Accepted Solution

by:
sh0e earned 500 total points
Comment Utility
I remember doing something like this already for another question.  The solution ended up being using selections.  A little quirky and not entirely reliable, but it works.  And besides, none of the implementations of fake onpaste are reliable.  The one above is actually really easily tricked.

Anyhow, you use selectionStart and selectionEnd.  Then check how much has been pasted and grab the substring.
0
 
LVL 13

Author Comment

by:numberkruncher
Comment Utility
In what situations is the above tricked?

Yes I agree, I think the selectionStart and selectionEnd approach may be the way to go.

I just had a random thought, I seem to remember that Flash can copy to the clipboard. If it is possible, would you recommend this approach? The only problem I see is overriding the "Paste" command from the Edit and Context Menus of each web browser.
0
 
LVL 16

Expert Comment

by:sh0e
Comment Utility
I forget exactly, but what I do remember is that one character pastes don't behave correctly, and that copying and pasting over selections doesn't always behave correctly.  I think it's if they're the same size?

The Flash idea is interesting.  I don't see why it wouldn't work.  If I get time I'll surely give it a go (have to go and reinstall Flash).  Tell me how you progress if you try it.

Actually, if you don't mind, would you be willing to make a Flash that handles clipboard reading/writing and provides a JavaScript API?  Then I can implement it quickly.  Post it here:
http://www.experts-exchange.com/Software/Photos_Graphics/Web_Graphics/Macromedia_Flash/ActionScript/Q_23849403.html
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 16

Expert Comment

by:sh0e
Comment Utility
I hate to be the bringer of bad news, but due to a recent exploit, clipboard manipulation will require user interaction in a Flash 10 update.  Bummer.
0
 
LVL 13

Author Comment

by:numberkruncher
Comment Utility
Yeah sure sh0e, I will give that a go today. I am away for most of the day, but I will do it this evening and upload it to your site.

That might be a problem, I was going to have the flash control hidden, I hope that the user interaction is by way of a HTML confirm style window as opposed to an internal flash message box.
0
 
LVL 16

Expert Comment

by:sh0e
Comment Utility
Unfortunately,

http://www.adobe.com/devnet/flashplayer/articles/fplayer10_security_changes_02.html#head31
"What do I need to do?

Any existing content that sets data on the system Clipboard using the System.setClipboard() method outside of an event triggered by user interaction will need to be updated. Setting the Clipboard will now have to be invoked through a button, keyboard shortcut, or some other event initiated by the user. "
0
 
LVL 13

Author Comment

by:numberkruncher
Comment Utility
For me, a popup message box wouldn't be too bad. When I was trying to implement the flash file I came across a bigger problem.

Flash provides 'System.setClipboard' but for security reasons there is no way to access the clipboard. I am going to take a look into a Java applet to see if it is possible there; otherwise I will just have to go with the less perfect HTML solution. If I do manage to get it working in the form of a Java applet, I will post the source here.

Quoted from: http://www.cgdou.net/flash/as3reference/flash/system/System.html
-------------------------------------
Note: Because of security concerns, it is not possible to read the contents of the system Clipboard. In other words, there is no corresponding System.getClipboard() method.
0
 
LVL 13

Author Closing Comment

by:numberkruncher
Comment Utility
Thanks for your input, it has been fantastic!
0
 
LVL 13

Author Comment

by:numberkruncher
Comment Utility
With the help of n_sachin1 on this website, I have created a Java applet which exposes a JavaScript interface to get the contents of the clipboard.

I have attached a ZIP file of the JCreator applet project.

The only problem with this solution is that you get an "Untrusted Certificate" warning message each time you load the applet. If I can work out a way to get rid of this, then there will be no user interruptions when accessing the clipboard contents.
0
 
LVL 13

Author Comment

by:numberkruncher
Comment Utility
Sorry, EE refused to add the ZIP file.

I have listed the files in the code snippet box below:

htmlEditor.java
htmlEditor.xml (ANT Script)
htmlEditor.html (HTML test page)
htmlEditor.java

===============

package numberkruncher;
 

import java.applet.*;

import java.io.*;

import javax.swing.event.*;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import javax.swing.text.html.*;

import javax.swing.text.*;

import java.net.*;

import java.awt.datatransfer.*;
 

public class htmlEditor extends JApplet {

	public htmlEditor() {

	}
 

	public void init() {

	}

	

	public String doSomething2() {

		return "Hello World!";

	}
 

	public String doSomething() {

		String result = "";

			

	    result = (String)java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {

			public Object run() {

				String result = "";

				

				Clipboard clipboard = getToolkit().getSystemClipboard();

				Transferable clipboardContent = clipboard.getContents(this);

				if (clipboardContent != null && clipboardContent.isDataFlavorSupported(DataFlavor.stringFlavor))

				{

					try

					{

						result = (String)clipboardContent.getTransferData(DataFlavor.stringFlavor);

					}

					catch(Exception e)

					{

					}

				}

				return result;

			}

	    });

		

		return result;

	}

}
 
 

htmlEditor.xml (ANT Script)

===========================

<?xml version="1.0" encoding="UTF-8"?>

 

<project basedir="." default="all" name="numberkruncher">

	

	<property file="${basedir}/build.properties"/>

	<property name="bin" value="${basedir}/../bin" />

	<property name="src" value="${basedir}/../src" />

	<property name="dist" value="${basedir}/../dist" />

	<property name="app.jar" value="numberkruncher.jar" />

	

	<path id="project.class.path">

		<pathelement location="${bin}" />

	</path>

	

	<target name="clean">

		<delete file="${dist}/${app.jar}" />

		<delete failonerror="false" includeemptydirs="true">

			<fileset dir="${bin}" />

		</delete>

	</target>

	

	<target name="init">

		<mkdir dir="${bin}" />

		<mkdir dir="${dist}" />

	</target>

 

	<target  name="compile" depends="init">

		<javac classpathref="project.class.path" destdir="${bin}">

			<src path="${src}" />

		</javac>

	</target>

	

	<target name="dist"  depends=" compile">

		<jar compress="true" destfile="${dist}/${app.jar}">

			<fileset dir="${bin}">

				<include name="**/*.class" />

			</fileset>

			<manifest>

				<attribute name="Main-Class" value="htmlEditor" />

			</manifest>

		</jar>

		<copy todir="${dist}">

			<fileset dir="${src}">

				<include name="**/*.html" />

			</fileset>

		</copy>

	</target>

	

	<target name="keytoolexec" unless="keystore.exists">

		<mkdir dir="${basedir}/Keystore"/>

		<exec dir="${basedir}" executable="keytool" failonerror="true">

			<arg value="-genkey "/>

			<arg value="-alias" />

			<arg value="numberkruncher"/>

			<arg value="-keystore" />

			<arg value="${basedir}/Keystore/Kruncher.jks"/>	

			<arg value="-keypass" />

			<arg value="n_sachin1"/>

			<arg value="-dname" />

			<arg value="CN=Test CA, OU=NK, O=NK, L=Bangalore, S=KA, C=IN"/>	

			<arg value="-storepass" />

			<arg value="n_sachin1"/>

			<arg value="-validity" />

			<arg value="365"/>

			

		</exec> 

	</target>

	

	<target name="testKeyStore">

		<available property="keystore.exists" file="${basedir}/Keystore/Kruncher.jks" />

	</target>

 

	  <target name="signjar" depends="dist, testKeyStore, keytoolexec">

	  	

	    <echo message="------ Signing JAR files"/>

	     <signjar jar="${dist}/${app.jar}" storepass="n_sachin1" alias="numberkruncher"

	           keystore="${basedir}/Keystore/Kruncher.jks" keypass="n_sachin1" />

	  </target>

 

	

	<target name="all" depends="clean, dist, signjar"/>

</project>
 
 

htmlEditor.html (HTML test page)

================================

<html>

	<head>

		<title>Test Page</title>

		<script type="text/javascript">

			function test() {

				var myApplet = document.getElementById('myApplet');

				if (myApplet)

					alert(myApplet.doSomething());

				else

					alert('Invalid applet!');	

			}

		</script>

	</head>

	<body>

		<center style="border: solid 1px black">

			<applet

				id		= "myApplet"

				code	= "numberkruncher.htmlEditor.class"

				width	= "500"

				height	= "300"

				archive	= "dist/numberkruncher.jar"

				>

			</applet>

		</center>

		<br />

		<input type="button" value="Do Something!" onclick="test()" />

	</body>

</html>

Open in new window

0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now