CTRL+V unformatted on Tinymce - tinymce

I am trying to copy html text and paste it into an unformatted way in TinyMCE by simply using CTRL + C, CTRL + V.
I have had a hard time to do this as TinyMCE constantly tries to keep the initial formatting. I am using Rails.
Would you know any work around this?

You may configure tinymce to strip all unwanted tags when pasting.
To do this use the tinymce config param paste_preprocess:
paste_preprocess : function(pl, o) {
o.content = window.strip_tags( o.content,'<p><div><ul><ol><li><br>' );
},
with the function strip_tags as follows:
// Strips HTML and PHP tags from a string
// returns 1: 'Kevin <b>van</b> <i>Zonneveld</i>'
// example 2: strip_tags('<p>Kevin <img src="someimage.png" onmouseover="someFunction()">van <i>Zonneveld</i></p>', '<p>');
// returns 2: '<p>Kevin van Zonneveld</p>'
// example 3: strip_tags("<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>", "<a>");
// returns 3: '<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>'
// example 4: strip_tags('1 < 5 5 > 1');
// returns 4: '1 < 5 5 > 1'
function strip_tags (str, allowed_tags)
{
var key = '', allowed = false;
var matches = []; var allowed_array = [];
var allowed_tag = '';
var i = 0;
var k = '';
var html = '';
var replacer = function (search, replace, str) {
return str.split(search).join(replace);
};
// Build allowes tags associative array
if (allowed_tags) {
allowed_array = allowed_tags.match(/([a-zA-Z0-9]+)/gi);
}
str += '';
// Match tags
matches = str.match(/(<\/?[\S][^>]*>)/gi);
// Go through all HTML tags
for (key in matches) {
if (isNaN(key)) {
// IE7 Hack
continue;
}
// Save HTML tag
html = matches[key].toString();
// Is tag not in allowed list? Remove from str!
allowed = false;
// Go through all allowed tags
for (k in allowed_array) { // Init
allowed_tag = allowed_array[k];
i = -1;
if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+'>');}
if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+' ');}
if (i != 0) { i = html.toLowerCase().indexOf('</'+allowed_tag) ;}
// Determine
if (i == 0) { allowed = true;
break;
}
}
if (!allowed) {
str = replacer(html, "", str); // Custom replace. No regexing
}
}
return str;
}
You may want to have a closer look at this SO-Thread too: TinyMCE Paste As Plain Text

Related

EA - Table template for single element manipulation

I'm trying to design a template that generates a document based on the following Diagram.
For each System (1 or 2) there is a Chapter, which will be further populated with subchapters for every "Element type C".
Example of chapter structure
The template I'm using is this one:
And it calls a table:
While scripting the fragment of this, for each element type C, I'm checking the connection type ( connection Y) to see if the element is related and can be added to the bottom half of the table. If so, the ID of element Type B is added to an XML structure.
The code I'm using is the following:
function arrange_data_in_xml(objectid) {
//Get the repository type
var repotype = Repository.RepositoryType();
//Create the xml structure
var xmlDOM = new COMObject("MSXML2.DOMDocument.6.0");
xmlDOM.validateOnParse = false;
xmlDOM.async = false;
var node = xmlDOM.createProcessingInstruction("xml", "version='1.0' encoding='ISO-8859-1'");
xmlDOM.appendChild(node);
var xmlRoot = xmlDOM.createElement("EADATA");
xmlDOM.appendChild(xmlRoot);
var xmlDataSet = xmlDOM.createElement("Dataset_0");
xmlRoot.appendChild(xmlDataSet);
var xmlData = xmlDOM.createElement("Data");
xmlDataSet.appendChild(xmlData);
var part1A = Repository.GetElementSet(sqlquery, 2);
//Session.Output(part1A.Count)
//This cycle will iterate over each Element Type B
for (var i = 0; i < part1A.Count; i++) {
var ElementTypeBrow = ""
var countElementTypeB = 0;
Session.Output("DEBUG 0 " + part1A.GetAt(i).ElementID + " -- " + part1A.GetAt(i).Name + " -- " + objectid)
var xmlRow = xmlDOM.createElement("Row");
xmlData.appendChild(xmlRow);
var xmlName = xmlDOM.createElement("Object_ID");
xmlName.text = part1A.GetAt(i).ElementID;
xmlRow.appendChild(xmlName);
var xmlName = xmlDOM.createElement("ElementTypeCName");
xmlName.text = part1A.GetAt(i).Name;
xmlRow.appendChild(xmlName);
for (var k = 0; k < part1A.GetAt(i).TaggedValues.Count; k++) {
var tv = part1A.GetAt(i).TaggedValues.GetAt(k);
if (tv.Name == 'Proprety X') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue1");
xmlName.text = tv.Value;
xmlRow.appendChild(xmlName);
} else if (tv.Name == 'Proprety Y') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue2");
xmlName.text = tv.Value;
xmlRow.appendChild(xmlName);
}
}
for (var j = 0; j < part1A.GetAt(i).Connectors.Count; j++) {
var connector = part1A.GetAt(i).Connectors.GetAt(j);
if (connector.Stereotype == 'Connection type Z') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue3");
xmlName.text = Repository.GetElementByID(connector.SupplierID).Name;
xmlRow.appendChild(xmlName);
} else if (connector.Stereotype == 'Connection type Y') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue4");
xmlName.text = Repository.GetElementByID(connector.ClientID).Name;
xmlRow.appendChild(xmlName);
} else if (connector.Stereotype == 'Connection type X'') {
var ElementTypeB = Repository.GetElementByID(connector.SupplierID)
//Check if the ElementTypeB is connected to the current interface
if (check_interface(ElementTypeB.ElementID) == objectid) {
//Session.Output("DEBUG 1 " + part1A.GetAt(i).Name + " - " + ElementTypeB.Name)
var ElementTypeBalias = ""
if (ElementTypeB.Alias != "") {ElementTypeBalias = " (" + ElementTypeB.Alias + ")"}
ElementTypeBrow = ElementTypeB.Name + ElementTypeBalias + " \n" + ElementTypeBrow
countElementTypeB = countElementTypeB + 1
}
}
}
//Session.Output("DEBUG 1 " +ElementTypeBrow + " - " + countElementTypeBs + " - " + ElementTypeB.Name)
var xmlName = xmlDOM.createElement("ApplicableElementTypeB-Hyperlink");
if (countElementTypeBs > 1) {
xmlName.text = ElementTypeBrow.trimStart();
} else {
xmlName.text = ElementTypeB.ElementGUID+ElementTypeBrow;
}
xmlRow.appendChild(xmlName);
}
return xmlDOM.xml;
}
The problem that I'm having now is the result list of elements is taken as one, ie all of the elements of the bottom half of the table are as one.
Is there a way to manipulate each element individually (for example create a hyperlink for each entry)?
I've tried to rearrange the XML stucture. But the problem remains.
Fragments like this expect there contents in the form of a table, with rows and columns.
Currently you are only returning a single row, but somehow you would like to split the different values for ElementTypeBName-Hyperlink into different rows.
I think you have two possibilities here:
Return each ElementTypeBName-Hyperlink element with a different name e.g. ElementTypeBName-Hyperlink1, ElementTypeBName-Hyperlink2,... and then use each of those in your table template.
Downside of this approach is that it isn't flexible at all, and only useful if you have more or less the same number of ElementB names.
Split your template into two templates. One template for the upper part, and one for the lower part.
Another observation is that you are taking the complicated (and slow) route. For requirements like this, it's much easier to create an SQL template instead of a script template.

Word JS APIs: extending a Range

While working on answering this question I would really like to have been able to extend a Range by a specific number of characters. In the COM API I would have used Range.MoveEnd(). Is there any equivalent that I didn't find in the JS API?
Background: The question referenced is about finding search terms with more than 255 characters - which is a limit in Word for the desktop. The search fails.
The simple way to go about it would be to search the first 254 characters, then expand the found Range by the remaining number of characters and comparing that Range.Text to the full search term.
Not finding any equivalent for expanding a Range in this manner, I had to resort to:
breaking down the search term into < 255 character pieces
search for each piece one-by-one
determine whether each searched piece was adjacent to the previous
then expand a Range to include the adjacent piece
and repeat until all pieces were found
Thus, my question...
async function basicSearch() {
await Word.run(async (context) => {
let maxNrChars = 254;
let searchterm = "";
let shortSearch = true; //search string < 255 chars
let fullSearchterm = "Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document. Aösdlkvaösd faoweifu aösdlkcj aösdofi "
let searchTermNrChars = fullSearchterm.length;
let nrSearchCycles = Number((searchTermNrChars / maxNrChars).toFixed(0));
let nrRemainingChars = searchTermNrChars - (nrSearchCycles * maxNrChars);
//console.log("Number of characters in search term: " + searchTermNrChars
// + "\nnumber of search cycles required: " + nrSearchCycles
// + "\nremaining number of characters: " + nrRemainingChars);
//numerous ranges are required to extend original found range
let bodyRange = context.document.body.getRange();
bodyRange.load('End');
let completeRange = null;
let resultRange = null;
let extendedRange = null;
let followupRange = null;
let cycleCounter = 0;
let resultText = "";
if (searchTermNrChars > maxNrChars) {
searchterm = fullSearchterm.substring(0, maxNrChars);
cycleCounter++;
shortSearch = false;
}
else { searchterm = fullSearchterm; }
let results = context.document.body.search(searchterm);
results.load({ select: 'font/highlightColor, text' });
await context.sync();
// short search term, highlight...
if (shortSearch) {
for (let i = 0; i < results.items.length; i++) {
results.items[i].font.highlightColor = "yellow";
}
}
else {
//console.log("Long search");
for (let i = 0; i < results.items.length; i++) {
resultRange = results.items[i];
resultRange.load('End');
extendedRange = resultRange.getRange('End').expandTo(bodyRange.getRange('End'));
await context.sync();
//search for the remainder of the long search term
for (let cycle = 1; cycle < nrSearchCycles; cycle++) {
searchterm = fullSearchterm.substring((cycle * maxNrChars), maxNrChars);
//console.log(searchterm + " in cycle " + cycle);
let CycleResults = extendedRange.search(searchterm);
CycleResults.load({ select: 'text, Start, End' });
await context.sync();
followupRange = CycleResults.items[0];
//directly adjacent?
let isAfter = followupRange.compareLocationWith(resultRange);
if (isAfter.value == Word.LocationRelation.adjacentAfter) {
resultRange.expandTo(followupRange);
extendedRange = resultRange.getRange('End').expandTo(bodyRange.getRange('End'));
}
await context.sync();
}
if (nrRemainingChars > 0) {
console.log("In remaining chars");
searchterm = fullSearchterm.substring(searchTermNrChars - nrRemainingChars);
console.log(searchterm);
let xresults = extendedRange.search(searchterm);
xresults.load('end, text');
await context.sync();
let xresult = xresults.items[0];
let isAfter = xresult.compareLocationWith(resultRange);
await context.sync();
console.log(isAfter.value);
if (isAfter.value == Word.LocationRelation.adjacentAfter) {
completeRange = resultRange.expandTo(xresult);
completeRange.load('text');
//completeRange.select();
await context.sync();
resultText = completeRange.text.substring(0, fullSearchterm.length);
console.log("Result" + cycleCounter + ": " + resultText);
}
}
else {
//No remeaining chars
resultRange.load('text');
//resultRange.select();
await context.sync();
resultText = resultRange.text.substring(0, fullSearchterm.length);
completeRange = resultRange;
}
//long search successful?
if (resultText == fullSearchterm) {
completeRange.font.highlightColor = "yellow";
}
else {
console.log("Else! " + resultText + " / " + fullSearchterm);
}
completeRange = null;
}
}
});
That was something we had in the original design, but it was actually removed from the API as it can easily lead to unexpected outcomes (i.e. hidden character inconsistencies, footnotes, etc.), and we could not cover those cases with the resources at hand. We decided to remove it.
That been said I think you can achieve something similar to range.MoveEnd() with Word.js, you just need to define to the end of what ;). One way of doing it is to use the range.expandTo(endRange) method. Again, The interesting thing is how to get the "endRange", so the following example shows how to do it if "end" means the end of the paragraph, probably in your scenario will suffice.
async function run() {
await Word.run(async (context) => {
//assume the range at the end of your 255 characters.
var startRange = context.document.getSelection().getRange("end");
//This one is the range at the end of the paragraph including the selection.
var endRange = context.document.getSelection().paragraphs.getLast().getRange("end");
var deltaRange = startRange.expandTo(endRange);
context.load(deltaRange);
await context.sync();
// this will print the characters after the range all the way to the end of the paragraph.
console.log(deltaRange.text);
});
}
hope this helps or at least sets you up in the right direction.

Javascript First letter uppercase restlower of two lines "."

I want to first letter to be in upper case other in lower. But after ".", it must be upper again..
function firstToUpperCase( str ) {
return str.substr(0, 1).toUpperCase() + str.substr(1);
}
var str = 'prompt("Enter text to convert: ")
var Upcase = firstToUpperCase( str );
document.write(Upcase);
Here's a simplistic answer based on what you provided. It does not take whitespace into account following the period since you didn't mention that in the specs.
function firstToUpperCase(str) {
var parts = str.split(".");
for (i = 0; i < parts.length; i++) {
parts[i] = parts[i].substring(0, 1).toUpperCase() + parts[i].substring(1).toLowerCase();
}
return parts.join(".");
}
If you're trying to deal with sentences, something like this might be a little better, though it does not preserve exact whitespace:
function firstToUpperCase(str) {
var parts = str.split(".");
for (i = 0; i < parts.length; i++) {
sentence = parts[i].trim();
parts[i] = sentence.substring(0, 1).toUpperCase() + sentence.substring(1).toLowerCase();
}
return parts.join(". ");

xpages typeahead autocomplete

i couldnt do aautocopmlete edit box. i want to take names from another database. i wrote my code to typeahead's value list. but it dont work. i am using same server but different database.anybody help me ? here is my code:
//Getting the view containing a document for each of the employees
var searchView:NotesView = session.getDatabase("servername","test/application name.nsf")
.getView("viewname");
// Creating a Lotus Notes search query. Notice the reference to lupkey!
var query = "(FIELD Ad Soyad CONTAINS *" + lupkey +"*)";
// Creating an array to store hits in
var searchOutput:Array = ["å","åå"];
// Doing the actual search
var hits = searchView.FTSearch(query);
var entries = searchView.getAllEntries();
var entry = entries.getFirstEntry();
//Sort the array manually, since Notes doesn't want to sort them alphabetically
for (i=0; i<hits; i++) {
searchOutput.push(entry.getColumnValues()[0]);
entry = entries.getNextEntry();
}
searchOutput.sort();
// Build the resulting output HTML code
var result = "<ul><li><span class='informal'>Suggestions:</span></li></ul>";
var limit = Math.min(hits,20);
for (j=0; j<limit; j++) {
var name = searchOutput[j].toString();
var start = name.indexOfIgnoreCase(lupkey)
var stop = start + lupkey.length;
//Make the matching part of the name bold
name = name.insert("</b>",stop).insert("<b>",start);
result += "<li>" + name + "</li>";
}
result += "</ul>";
return result;
There are plenty of issues with your code:
the query can't return any result since your field has a space in it
Do you really need an FTSearch to return values and not a sorted view?
the typeahead -as the name suggest- presents values that match left to right and not somewhere substring. If you need that you need to roll your own typeahead function using Ajax
The typeahead function doesn't take a parameter, so your lupkey doesn't go anywhere. The function needs to return all values and XPages will do the matching
Instead of copying one by one into an array for sorting, copy the returning Vector() into a TreeSet(). This is one line, sorts it and removes duplicates
To get it working check this example based on dojo, previously asked here. You will need the REST control
i do it like that
var directoryTypeahead = function (searchValue:string) {
// update the following line to point to your real directory
//var directory:NotesDatabase = session.getDatabase(database.getServer(), "names.nsf");
var directory:NotesDatabase = session.getDatabase(database.getServer(), "org/test.nsf");
var allUsers:NotesView = directory.getView("SVFHP2");
var matches = {};
var includeForm = {
Person: true,
Group: true
}
searchValue = searchValue.replace("I","i")
var matchingEntries:NotesViewEntryCollection = allUsers.getAllEntriesByKey(searchValue, false);
var entry:NotesViewEntry = matchingEntries.getFirstEntry();
var resultCount:int = 0;
while (entry != null) {
var matchDoc:NotesDocument = entry.getDocument();
var matchType:string = matchDoc.getItemValueString("Form");
//if (includeForm[matchType]) { // ignore if not person or group
var fullName:string = matchDoc.getItemValue("Name").elementAt(0) + " " + matchDoc.getItemValue("Title").elementAt(0);
if (!(matches[fullName])) { // skip if already stored
resultCount++;
var matchName:NotesName = session.createName(fullName);
matches[fullName] = {
cn: matchName.getCommon(),
photo: matchDoc.getItemValueString("Photo"),
job: matchDoc.getItemValueString("sum"),
email: matchDoc.getItemValueString("email"),
}
}
// }
/*if (resultCount > 15) {
entry = null; // limit the results to first 10 found
}
else {*/
entry = matchingEntries.getNextEntry(entry);
//}
};
}

C sharp delimiter

In a given sentence i want to split into 10 character string. The last word should not be incomplete in the string. Splitting should be done based on space or , or .
For example:
this is ram.he works at mcity.
now the substring of 10 chars is,
this is ra.
but the output should be,
this is.
Last word should not be incomplete
You can use a regular expression that checks that the character after the match is not a word character:
string input = "this is ram.he";
Match match = Regex.Match(input, #"^.{0,10}(?!\w)");
string result;
if (match.Success)
{
result = match.Value;
}
else
{
result = string.Empty;
}
Result:
this is
An alternative approach is to build the string up token by token until adding another token would exceed the character limit:
StringBuilder sb = new StringBuilder();
foreach (Match match in Regex.Matches(input, #"\w+|\W+"))
{
if (sb.Length + match.Value.Length > 10) { break; }
sb.Append(match.Value);
}
string result = sb.ToString();
Not sure if this is the sort of thing you were looking for. Note that this could be done a lot cleaner, but should get you started ... (may want to use StringBuilder instead of String).
char[] delimiterChars = { ',', '.',' ' };
string s = "this is ram.he works at mcity.";
string step1 = s.Substring(0, 10); // Get first 10 chars
string[] step2a = step1.Split(delimiterChars); // Get words
string[] step2b = s.Split(delimiterChars); // Get words
string sFinal = "";
for (int i = 0; i < step2a.Count()-1; i++) // copy count-1 words
{
if (i == 0)
{
sFinal = step2a[i];
}
else
{
sFinal = sFinal + " " + step2a[i];
}
}
// Check if last word is a complete word.
if (step2a[step2a.Count() - 1] == step2b[step2a.Count() - 1])
{
sFinal = sFinal + " " + step2b[step2a.Count() - 1] + ".";
}
else
{
sFinal = sFinal + ".";
}