how to remove formatting from text copied from word document [closed] - cleditor

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
When I copy text from a word document the applied formatting is also copied when I paste that text into cleditor on my webpage, This is our rails application.

cleditor google groups seems to have the answer:
Below is an extension I use to the updateTextArea that includes
filtering of Microsoft word if / endif garbage and normalizing the
tags to a combination of xhtml / html5 friendly ones:
br|b|del|ins|i|li|ol|p|ul
(function($) {
$.cleditor.defaultOptions.docType = "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>";
$.cleditor.defaultOptions.docCSSFile = AkmeWindowUtil.CONTEXT_PATH+"/embed/cleditor/jquery.cleditor.iframe.css";
$.cleditor.defaultOptions.updateTextArea = function(html) { //if (document.forms[0].debugArea) document.forms[0].debugArea.value = html;
// Normalize to xhtml/html5 common standards and only keep allowed tags.
var ary = html.split("<");
var end = -1;
for (var i=0; i<ary.length; i++) {
if (ary[i].lastIndexOf("!--[if ", 7) === 0) { // handle Microsoft <!--[if ... <![endif]-->
ary[i] = "";
var found = false;
for (i++; i<ary.length; i++) {
if (ary[i].lastIndexOf("![endif]-->", 11) === 0) {found = true;}
ary[i] = "";
if (found) break;
}
if (i>=ary.length) break;
}
end = ary[i].indexOf(">");
if (end == -1) continue;
ary[i] = ary[i].substring(0,end).toLowerCase()+ary[i].substring(end);
var search = ["strong>","em>","strike>","u>","br>"];
var replace = ["b>","i>","del>","ins>","br/>"];
for (var j=0; j<search.length; j++) {
var pos = ary[i].lastIndexOf(search[j], search[j].length+1);
if (pos == 0 || (pos == 1 && ary[i].charAt(0) == '/')) {
ary[i] = (pos == 1 ? "/" : "")+ replace[j] +ary[i].substring(search[j].length+pos);
}
}
var spellcheckerRE = /^\/?span[^\/>]*\/?>/m;
var cleanupRE = /^(\/?)(br|b|del|ins|i|li|ol|p|ul)[^a-zA-Z\/>]*[^\/>]*(\/?)>/m;
if (spellcheckerRE.test(ary[i])) {
ary[i] = ary[i].replace(spellcheckerRE, "");
} else if (cleanupRE.test(ary[i])) {
ary[i] = ary[i].replace(cleanupRE, "<$1$2$3>");
ary[i] = ary[i].replace(/^<p>/, "");
ary[i] = ary[i].replace(/^<\/?p\/?>/, "<br/>");
} else {
ary[i] = end+1 < ary[i].length ? ary[i].substring(end+1) : "";
}
ary[i] = ary[i].replace(/ /gm, "");
ary[i] = ary[i].replace(/\n\n/gm, "\n");
}
html = ary.join("");
// Trim leading whitespace.
var trimRE = /^(\s+| |<br\/?>|<p>( )*<\/p>)+/m;
if (trimRE.test(html)) {
html = html.replace(trimRE, "");
}
// Test if there is any actual non-whitespace text content.
var body = document.getElementsByTagName("body")[0];
var div = document.createElement("div");
div.style.display = "none";
body.appendChild(div);
div.innerHTML = html;
var text = div.innerText || div.textContent;
body.removeChild(div);
var trimRE = /\S/m;
if (!trimRE.test(text)) html = "";
return html;
};
})(jQuery);

Related

Google Apps Script run faster

Below I have some code I have running for a spreadsheet. Right now it takes a min or two to run through the script. I was wondering if anyone has any suggestions on how to re-work my code to run a little faster.
What the code does is search on a tab in the sheet called "set up" for check-marked items in a list that I would like included in my "Master Sheet". Then go to my sheet which contains all of the information that I would like copied and pasted over according to what is check marked on my set-up page. Then copy and paste those line items to the master sheet.
function allToMaster(){
var sss = SpreadsheetApp.getActive();
var ssAll = sss.getSheetByName("FF All");
var ssMaster = sss.getSheetByName("FF Master");
var ssSetup = sss.getSheetByName("FF Setup");
ssMaster.clear();
var masterCounter = 2;
ssAll.getRange("P:P").clear();
var sourceRange = ssAll.getRange(1,1,1,15);
sourceRange.copyTo(ssMaster.getRange(1,1));
//get last row of FF All
var lastRowAll = ssAll.getLastRow();
var lastRowMaster = ssMaster.getLastRow();
ssAll.getRange("P2:P" + lastRowAll).setFormula("=index('FF Setup'!B:B,match(B2,'FF Setup'!C:C,0))");
ssMaster.setRowHeightsForced(2, 500, 26);
for (i=2;i<=lastRowAll;i++){
if (ssAll.getRange(i,1).getBackground() == "#a8d08d"){
var sourceRange = ssAll.getRange(i,1,1,15);
sourceRange.copyTo(ssMaster.getRange(masterCounter,1));
masterCounter++;
} else if (ssAll.getRange(i,1).getBackground() == "#e2efd9"){
var sourceRange = ssAll.getRange(i,1,1,15);
sourceRange.copyTo(ssMaster.getRange(masterCounter,1));
masterCounter++;
} else {
if (ssAll.getRange("P" + i).getValue() == true) {
var sourceRange = ssAll.getRange(i,1,1,15);
sourceRange.copyTo(ssMaster.getRange(masterCounter,1));
ssMaster.setRowHeightsForced(masterCounter, 1, 136);
masterCounter++;
}
}
}
ssAll.getRange("P:P").clear();
//Clear Empty Subtitles
var lastRowMaster = ssMaster.getLastRow();
for (i=2;i<=lastRowMaster;i++){
if (ssMaster.getRange(i,1).getBackground() == "#e2efd9"){
if(ssMaster.getRange((i+1),1).getBackground() == "#e2efd9" || ssMaster.getRange((i+1),1).getBackground() == "#a8d08d"){
ssMaster.deleteRow(i);
ssMaster.insertRowAfter(500);
i=i-1;
}
}
}
//Clear Empty Titles
var lastRowMaster = ssMaster.getLastRow();
for (i=2;i<=lastRowMaster;i++){
if (ssMaster.getRange(i,1).getBackground() == "#a8d08d"){
if(ssMaster.getRange((i+1),1).getBackground() == "#a8d08d"){
ssMaster.deleteRow(i);
ssMaster.insertRowAfter(500);
i=i-1;
}
}
}
//Find the row with "Delivery"
var deliveryRow = getRowOf("DELIVERY", "FF All", 1);
var sourceRange = ssAll.getRange(deliveryRow,1,(lastRowAll - deliveryRow + 1),15);
var masterCounter = ssMaster.getLastRow()
sourceRange.copyTo(ssMaster.getRange(masterCounter,1));
masterCounter = masterCounter + lastRowAll - deliveryRow - 2;
//.setFormula('=SUMA(J264:J275)');
// ssMaster.getRange(masterCounter, 10).setFormula("=sum(J2:J" + (masterCounter - 1) + ")");
//ssMaster.getRange(masterCounter, 11).setFormula("=sum(K2:K" + (masterCounter - 1) + ")");
//ssMaster.getRange(masterCounter, 13).setFormula("=sum(M2:M" + (masterCounter - 1) + ")");
//ssMaster.getRange(masterCounter, 15).setFormula("=M" + masterCounter + " - K" + masterCounter);
}
function getRowOf(value, sheet, col){
var dataArr = SpreadsheetApp.getActive().getSheetByName(sheet).getRange(4, col, 3500, 1).getValues();
for(var j = 0; j < dataArr.length; j ++){
var currVal = dataArr[j][0];
if(currVal == value){
return j+4;
break;
}
}
return 0;
}
You need to change the loops as they are doing several calls to Class SpreadsheetApp on each iteration.
Regarding the first loop,
for (i=2;i<=lastRowAll;i++){
if (ssAll.getRange(i,1).getBackground() == "#a8d08d"){
var sourceRange = ssAll.getRange(i,1,1,15);
sourceRange.copyTo(ssMaster.getRange(masterCounter,1));
masterCounter++;
} else if (ssAll.getRange(i,1).getBackground() == "#e2efd9"){
var sourceRange = ssAll.getRange(i,1,1,15);
sourceRange.copyTo(ssMaster.getRange(masterCounter,1));
masterCounter++;
} else {
if (ssAll.getRange("P" + i).getValue() == true) {
var sourceRange = ssAll.getRange(i,1,1,15);
sourceRange.copyTo(ssMaster.getRange(masterCounter,1));
ssMaster.setRowHeightsForced(masterCounter, 1, 136);
masterCounter++;
}
}
}
Instead of getting the background of one cell at a time (ssAll.getRange(i,1).getBackground()), before the loop get the backgrounds of all the cells before the loop, i.e.
const backgrounds = ssAll.getRange(2,1,lastRowAll).getBackgrounds();
then replace ssAll.getRange(i,1).getBackground() by backgrounds[i-1][0].
Do the something similar about ssAll.getRange("P" + i).getValue(), before the loop get the all values of the P column:
const values = ssAll.getRange("P" + i + ":P" + lastRowAll).getValues()
then replace ssAll.getRange("P" + i).getValue() by values[i-1][0]`.
It might be also possible to optimize further the first loop depending on if you really need to copy the ranges (besides values, include borders, background, notes, etc.) or if you only need the values.
Another option is to use the Advances Sheets Services but this implies to make a completely different implementation.

how to restrict double extension while uploading file to server

fileName = inputParam.file_name.split('.')[0].toLowerCase().replace(/ /g, '') + '' + Date.now() + "." + (fileData.file.name.split('.')[1] || inputParam.file_name.split('.')[1])
filePath = filePath + fileName
This is the condition I am using.
For example it should only restrict a.jpeg.jpg or a.php.jpeg. and allow extension like a.a.jpeg or bird.tree.jpeg
var _validFilejpeg = [".jpeg", ".jpg", ".bmp", ".png",".pdf", ".txt"];
var invalid = [".php",".php5", ".pht", ".phtml", ".shtml", ".asa", ".cer", ".asax", ".swf",".xap"];
function validateForSize(oInput, minSize, maxSizejpeg) {
//if there is a need of specifying any other type, just add that particular type in var _validFilejpeg
if (oInput.type == "file") {
var sFileName = oInput.value;
var file = sFileName.match(/\d/g);
var fileExt = sFileName.substr(sFileName.length-4);
if (sFileName.length > 0) {
var blnValid = false;
for (var j = 0; j < _validFilejpeg.length; j++) {
var sCurExtension = _validFilejpeg[j];
if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length)
.toLowerCase() == sCurExtension.toLowerCase()) {
blnValid = true;
break;
}
}
if(fileExt = 'invalid'){
alert("Your document does not have a proper file extension.")
blnValid = false;
}
if(fileExt = 'file'){
alert("Your document does not have a proper file extension.")
blnValid = false;
}
if (!blnValid) {
alert("Sorry, this file is invalid, allowed extension is: " + _validFilejpeg.join(", "));
oInput.value = "";
return false;
}
}
}
fileSizeValidatejpeg(oInput, minSize, maxSizejpeg);
}
function fileSizeValidatejpeg(fdata, minSize, maxSizejpeg) {
if (fdata.files && fdata.files[0]) {
var fsize = fdata.files[0].size /1024; //The files property of an input element returns a FileList. fdata is an input element,fdata.files[0] returns a File object at the index 0.
//alert(fsize)
if (fsize > maxSizejpeg || fsize < minSize) {
alert('This file size is: ' + fsize.toFixed(2) +
"KB. Files should be in " + (minSize) + " to " + (maxSizejpeg) + " KB ");
fdata.value = ""; //so that the file name is not displayed on the side of the choose file button
return false;
} else {
console.log("");
}
}
}
<input type="file" onchange="validateForSize(this,20,5000);" >
You can simply do this
if (fileName.split('.').length > 2) {
throw new Error('Double extension file detected')
}

In Boomla, how can I easily find the next sibling of a file

I'm quite used to nextSiblingand nextElementSibling in the DOM. Is there an easy way of doing a similar thing with Boomla files?
I would need the next sibling within the same placeholder (and null if this is the last), but I'd be interested about finding the next sibling in any placeholder (and null if this is the last file in the last placeholder).
Currently, there is no built-in method for this.
Here are 2 methods for the sjs-4 engine for getting the next in the placeholder or parent:
var nextInBucket = function(f) {
var bucket = f.bucketId();
var bucketSiblings = f.query("../:" + bucket);
var path = f.path();
var index = 0;
var found = false;
bucketSiblings.each(function(t) {
if (t.path() == path) {
found = true;
return false;
}
index++;
});
if ( ! found) {
return null;
}
return bucketSiblings.eq(index + 1);
}
var nextInParent = function(f) {
var parentChildren = f.query("../*");
var path = f.path();
var index = 0;
var found = false;
parentChildren.each(function(t) {
if (t.path() == path) {
found = true;
return false;
}
index++;
});
if ( ! found) {
return null;
}
return parentChildren.eq(index + 1);
}

How to create all possible variations from single string presented in special format?

Let's say, I have following template.
Hello, {I'm|he is} a {notable|famous} person.
Result should be
Hello, I'm a notable person.
Hello, I'm a famous person.
Hello, he is a notable person.
Hello, he is a famous person.
The only possible solution I have in mind - full search, but it is not effective.
May be there is a good algorithm for such kind of job but I do not know what task about. All permutations in array is very close to this but I have no idea how to use it here.
Here is working solution (it's part of object, so here is only relevant part).
generateText() parses string and converts 'Hello, {1|2}, here {3,4}' into ['Hello', ['1', '2'], 'here', ['3', '4']]]
extractText() takes this multidimensional array and creates all possible strings
STATE_TEXT: 'TEXT',
STATE_INSIDE_BRACKETS: 'INSIDE_BRACKETS',
generateText: function(text) {
var result = [];
var state = this.STATE_TEXT;
var length = text.length;
var simpleText = '';
var options = [];
var singleOption = '';
var i = 0;
while (i < length) {
var symbol = text[i];
switch(symbol) {
case '{':
if (state === this.STATE_TEXT) {
simpleText = simpleText.trim();
if (simpleText.length) {
result.push(simpleText);
simpleText = '';
}
state = this.STATE_INSIDE_BRACKETS;
}
break;
case '}':
if (state === this.STATE_INSIDE_BRACKETS) {
singleOption = singleOption.trim();
if (singleOption.length) {
options.push(singleOption);
singleOption = '';
}
if (options.length) {
result.push(options);
options = [];
}
state = this.STATE_TEXT;
}
break;
case '|':
if (state === this.STATE_INSIDE_BRACKETS) {
singleOption = singleOption.trim();
if (singleOption.length) {
options.push(singleOption);
singleOption = '';
}
}
break;
default:
if (state === this.STATE_TEXT) {
simpleText += symbol;
} else if (state === this.STATE_INSIDE_BRACKETS) {
singleOption += symbol;
}
break;
}
i++;
}
return result;
},
extractStrings(generated) {
var lengths = {};
var currents = {};
var permutations = 0;
var length = generated.length;
for (var i = 0; i < length; i++) {
if ($.isArray(generated[i])) {
lengths[i] = generated[i].length;
currents[i] = lengths[i];
permutations += lengths[i];
}
}
var strings = [];
for (var i = 0; i < permutations; i++) {
var string = [];
for (var k = 0; k < length; k++) {
if (typeof lengths[k] === 'undefined') {
string.push(generated[k]);
continue;
}
currents[k] -= 1;
if (currents[k] < 0) {
currents[k] = lengths[k] - 1;
}
string.push(generated[k][currents[k]]);
}
strings.push(string.join(' '));
}
return strings;
},
The only possible solution I have in mind - full search, but it is not effective.
If you must provide full results, you must run full search. There is simply no way around it. You don't need all permutations, though: the number of results is equal to the product of the number of alternatives in each template.
Although there are multiple ways to implement this, recursion is among the most popular approaches. Here is some pseudo-code to get you started:
string[][] templates = {{"I'm", "he is"}, {"notable", "famous", "boring"}}
int[] pos = new int[templates.Length]
string[] fills = new string[templates.Length]
recurse(templates, fills, 0)
...
void recurse(string[][] templates, string[] fills, int pos) {
if (pos == fills.Length) {
formatResult(fills);
} else {
foreach option in templates[pos] {
fills[pos] = option
recurse(templates, fills, pos+1);
}
}
}
It seems like the best solution here is going to be n*m where n=the first array and m= the second array . There are nm required lines of output, which means that as long as you are only doing nm you aren't doing any extra work
The generic running time for this is where there is more than 2 arrays with options, it would be
n1*n2...*nm where each of those is equal to the size of the respective list
A nested loop where you just print out the value for the current index of the outer loop along with the current value for the index of the inner loop should do this properly

Set selection on tekst inside CKEditor

I'm having trouble to select text in CKEditor(3.6). As we use plain text i dont know how to use correctly the range selectors.
HTML code of the CKEditor:
<body spellcheck="false" class="rf-ed-b" contenteditable="true">
<br>
Cross those that apply:<br>
<br>
<br>
[«dummy»] If he/she is tall<br>
<br>
[«dummy»] If he/she is a male<br>
<br>
[«dummy»] If he/shi is a minor<br>
<br>
Specialties:<br>
<br>
[«dummy»] «Write here the specialties if known»<br>
<br>
<br>
«You are now done with filling in this form»<br>
</body>
With the keys 'CRTL+N' I want to go to the next filleble spot:
«[label]»
I tried stuff like:
var editor = CKEDITOR.instances['MyEditor'];
var findString = '«';
var element = editor.document.getBody();
var ranges = editor.getSelection().getRanges();
var startIndex = element.getHtml().indexOf(findString);
if (startIndex != -1) {
ranges[0].setStart(element.getFirst(), startIndex);
ranges[0].setEnd(element.getFirst(), startIndex + 5);
editor.getSelection().selectRanges([ranges[0]]);
}
Error:
Exception: Index or size is negative or greater than the allowed amount
While totally stripepd down it kinda works a bit:
var editor = CKEDITOR.instances['MyEditor'];
var ranges = editor.getSelection().getRanges();
var startIndex = 10;
if (startIndex != -1) {
ranges[0].setStart(element.getFirst(), startIndex);
ranges[0].setEnd(element.getFirst(), startIndex + 5);
editor.getSelection().selectRanges([ranges[0]]);
}
here it selects 5th till 10th char on first row.
I used the following sources:
example on Stackoverflow
Another stackoverflow example
CKEditor dom selection API
All solutions i can find work with html nodes.
How can set selection range on the '«' till next '»'
I've managed to solve this solution. Meanwhile i also upgraded CKeditor to 4.0.
This shouldnt have an impact on the solution.
It is a lot of code in JS.
On my keybinding i call the following JS function: getNextElement()
In this solution it also searches behind the cursor, this makes it possible to step through multiple find results.
Also the view gets scrolled to the next search result
var textNodes = [], scrollTo=0,ranges = [];
function getNextElement(){
var editor =null;
ranges = [];
// I dont know the ID of the editor, but i know there is only one the page
for(var i in CKEDITOR.instances){
editor = CKEDITOR.instances[i];
}
if(editor ==null){
return;
}
editor.focus();
var startRange = editor.getSelection().getRanges()[0];
var cursorData ="",cursorOffset=0,hasCursor = false;
if(startRange != null && startRange.endContainer.$.nodeType == CKEDITOR.NODE_TEXT){
cursorOffset = startRange.startOffset;
cursorData = startRange.endContainer.$.data;
hasCursor = true;
}
var element;
element = editor.document.getBody().getLast().getParent();
var selection = editor.getSelection();
// Recursively search for text nodes starting from root.
textNodes = [];
getTextNodes( element );
var foundElement = false;
foundElement = iterateEditor(editor,hasCursor,cursorData,cursorOffset);
if(!foundElement){
foundElement =iterateEditor(editor,false,"",0);
}
if(foundElement){
// Select the range with the first << >>.
selection.selectRanges( ranges );
jQuery(".cke_wysiwyg_frame").contents().scrollTop(scrollTo);
}
}
function iterateEditor(editor,hasCursor,cursorData,cursorOffset){
var foundElement = false;
var rowNr = 0;
var text, range;
var foundNode = false;
if(!hasCursor){
foundNode = true;
}
// Iterate over and inside the found text nodes. If some contains
// phrase "<< >>", create a range that selects this word.
for (var i = textNodes.length; i--; ) {
text = textNodes[ i ];
if ( text.type == CKEDITOR.NODE_ELEMENT && text.getName() == "br" ){
rowNr++;
} else if ( text.type == CKEDITOR.NODE_TEXT ) {
var sameNode = false;
if(text.$.data == cursorData){
foundNode = true;
sameNode = true;
}
if(foundNode){
var startIndex = -1;
var endIndex = 1;
if(sameNode){
// Check inside the already selected node if the text has multiple hits on the searchphrase
var indicesStart = getIndicesOf('\u00AB', text.getText());
var indicesEnd = getIndicesOf('\u00BB', text.getText());
for (var j = indicesStart.length; j--; ) {
if(indicesStart[j] > cursorOffset){
startIndex = indicesStart[j];
endIndex = indicesEnd[j];
}
}
} else{
startIndex = text.getText().indexOf( '\u00AB' );
endIndex = text.getText().indexOf( '\u00BB' );
}
if ( startIndex > -1 && (!sameNode || startIndex > cursorOffset)) {
range = editor.createRange();
range.setStart( text, startIndex );
foundElement = true;
// calculate the height the window should scroll to focus the selected element
scrollTo = (rowNr)*20;
}
if ( endIndex > -1 && foundElement ) {
range.setEnd( text, endIndex+1 );
ranges.push( range );
return true;
}
}
}
}
}
function getIndicesOf(searchStr, str) {
var startIndex = 0, searchStrLen = searchStr.length;
var index, indices = [];
while ((index = str.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + searchStrLen;
}
return indices;
}
function getTextNodes( element ) {
var children = element.getChildren(), child;
for ( var i = children.count(); i--; ) {
child = children.getItem( i );
textNodes.push( child );
}
}

Resources