Javascript/Safari - Searching a webpage's text using innerHTML - javascript

I'm working on an extension for Mac OS X's Safari browser. I only want this extension to execute if a few specific strings appear on the page. It should search for these strings throughout the entire HTML document.
Validation bool:
function validateStringsPresent(){
var index1 = document.documentElement.innerHTML.indexOf(validationText1);
var index2 = document.documentElement.innerHTML.indexOf(validationText2);
/* For testing purposes only */
alert("If an index = -1, it is not on the page" + "\n" + "\n"
+ index1 + "\n" + "\n"
+ index2);
if (index1 != -1 && index2 != -1) {return true};
else {return false};
}
As you've guessed, I get -1 for both indexes on a page that does contain the Validation Text. There are no special characters in these strings except for :, but that shouldn't be a factor.
My theory is that I need something other than the document class when using an extension in Safari. To get the current URL, for example, the document class didn't work either. I had to use var currentUrl = safari.application.activeBrowserWindow.activeTab.url;
I haven't been able to find the correct Safari Class to accomplish what I am trying to do, though.
Can anyone point me in the right direction?
EDIT
Now trying via injected script.
Button click function:
function performCommand(event)
{
getHTML();
}
safari.application.addEventListener("command", performCommand, true);
injected.js:
function getHTML()
{
var val1 = document.documentElement.innerHTML;
alert("You are using injected.js" + "\n" + "\n"
+ val1);
}
As you can see in the screen shots below, getHTML() is returning the HTML from my global file and not the current web page.

Related

How to calculate equasion from text content of element?

I'm trying to write basic calculator in js (I'm learning) and so far i wrote something like this:
function Wprowadzanie(nacisnieto){
var temp = document.getElementById('kalkulator_linia_2').textContent;
temp = temp + nacisnieto;
document.getElementById('kalkulator_linia_2').innerHTML = temp;
}
function Dzialanie(nacisnieto){
var temp = document.getElementById('kalkulator_linia_2').textContent;
if(temp!="") document.getElementById('kalkulator_linia_1').innerHTML = document.getElementById('kalkulator_linia_1').textContent + ' ' + temp + ' ' + nacisnieto;
document.getElementById('kalkulator_linia_2').textContent = "";
}
function Rowna_Sie(){
var dzialanie = document.getElementById('kalkulator_linia_1').textContent + ' ' + document.getElementById('kalkulator_linia_2').textContent;
document.getElementById('kalkulator_linia_1').innerHTML = dzialanie + ' =';
var wynik = 0;
document.getElementById('kalkulator_linia_2').innerHTML = wynik;
}
Function Wprowadzanie is activated when a button (div) with number is pressed and gets the content of the button (0,1,2,3,etc..).
Example:
<div class="klawiatura_przycisk" onclick="Wprowadzanie(1)">1</div>
Same with function Dzialanie, it gets activated when button with +,-,* or / is pressed and gets content of that button (for example '+').
Example:
<div class="klawiatura_przycisk" onclick="Dzialanie('+')">+</div>
Function Rowna_Sie is activated when button with "=" is pressed.
<div class="klawiatura_przycisk" onclick="Rowna_Sie()";>=</div>
I tried to make function "Rowna_Sie()" calculate the content of var "dzialanie" and save it to var "wynik", but everything I tried didn't want to work. Could you please show me how to correctly finish that function?
You could use the eval function, which treats its argument as javascript code and tries to execute it. There are huge security concerns when you do this, but because the string is being built by buttons like that, and because this looks like it's just a project you're doing for fun, it should be fine. The code you need is this:
var wynik = eval(dzialanie);
I don't speak the language you named things in so it's a little hard to follow, and I may have made a small mistake in the snippet. The argument should be the string containing the equation the user has entered. So if they wanted to calculate 1+1, you need to do eval("1 + 1") to get the answer.

Pagedown Editor - make inline links instead of referenced links

Does anyone know how to use hooks or edit Markdown.Editor.js from Pagedown to have it create inline links and instead of referenced ones?
As in, I want this to happen when I click the link button:
[inline link](http://www.google.com)
![alt text](http://website.com/bear.jpg "title text")
instead of this:
[referenced link][1]
![referenced image][2]
[1]: http://google.com/
[2]: http://website.com/bear.jpg "title text"
Thanks!
For reference: https://code.google.com/p/pagedown/
Unfortunately, there do not appear to be any hooks for this functionality in Markdown.Editor.js. I was however able to find the section of code responsible for this, and create a patch for your desired functionality.
Open Markdown.Editor.js in your editor of choice.
Find this section of code:
var linkDef = " [999]: " + properlyEncoded(link);
var num = that.addLinkDef(chunk, linkDef);
chunk.startTag = isImage ? "![" : "[";
chunk.endTag = "][" + num + "]";
Replace with this code:
chunk.startTag = isImage ? "![" : "[";
chunk.endTag = "](" + properlyEncoded(link) + ")";
Profit!
Get a copy
Open a file Markdown.Converter.js
Scroll to the line 724
Edit method function _DoImages(text) {}
Scroll to the line 581
Edit method function _DoAnchors(text) {}
Finally you can achieve absolutely any imaginable results with editing the source code.
UPD:
Just for fun the patch (if you prefer the patches):
converter.hooks.chain("postConversion", function (text) {
var anchors = [];
// definitions
text = text.replace(/\[(\d+)\]\: (htt.+)\n/gi, function(anchor_definition){
anchors.push(anchor_definition.match(/(htt.+)\n/i)[1]);
return("");
});
// anchors in the text
text = text.replace(/\]\[\d+\]/gi, function(anchor){
var id = parseInt(anchor.match(/\d+/)[0]);
var code = "][" + (anchors[id - 1]) + "]";
return(code);
});
return(text);
});

change text color only of user entered string in AJAX extended textbox

I am extending a texbox control with AJAX Autocomplete and I have successfully implemeted an autocomplete text box where once the user enters 3 characters my database returns a list of records that begin with the first 3 characters entered by the user.
I then changed this feature to use some Fuzzy logic so that the strings that returned contain no less than the 3 characters entered by the user and progressively becomes a shorter more refined list as the user enters a more specific search string.
I then used the inlcluded CSS class of the Autocomplete control to change the backgorund color and selected item color in the extended texbox.
<asp:AutoCompleteExtender
ID="TextBox1_AutoCompleteExtender"
runat="server"
DelimiterCharacters=""
Enabled="True"
EnableCaching="True"
ServiceMethod="GetCompletionList"
ServicePath="~/search/strngSrch.asmx"
TargetControlID="TextBox1"
UseContextKey="True"
CompletionSetCount="30"
CompletionInterval="10"
MinimumPrefixLength="2"
CompletionListItemCssClass="itemHighlighted"
CompletionListHighlightedItemCssClass="itemHighlighted1">
</asp:AutoCompleteExtender>
What I would like to do now is change the color of the text ONLY in each string (list item) that matches what the user is entering after 3 or more characters have been entered.
I have been searching for something like this on the web for 2 days and have not found a similar solution. My efforts have become more than frustrating.
User Enters: fish
Results list should look like:
Fishing (The 4 letters = to Fish should be red in each of these list items)
New Fishing licenses
Renew Fishing License
Fish and hatchery lists
If anyone has any links or similar type of solution I would be very pleased to look it over.
This functionality could best be compared to searching for a text string in a PDF where the word background is highlighted yellow for each occurance within the doc. I don't care if it turns the background a different color ONLY behind the text the user entered, or changes the text color.
thanks,
I would like to thank the link below for providing a solution to the question. I finally found something that almost worked. In the interest of not posting only a link, please review the working code below.
Note some of my minor changes in the below code over the original found in the link at the end.
<script type="text/javascript">
function aceSelected(sender, e) {
var value = e._item.innerText; // get_text();
if (!value) {
if (e._item.parentElement && e._item.parentElement.tagName == "LI")
value = e._item.parentElement.attributes["_innerText"].value;
else if (e._item.parentElement && e._item.parentElement.parentElement.tagName == "LI")
value = e._item.parentElement.parentElement.attributes["_innerText"].value;
else if (e._item.parentNode && e._item.parentNode.tagName == "LI")
value = e._item.parentNode._value;
else if (e._item.parentNode && e._item.parentNode.parentNode.tagName == "LI")
value = e._item.parentNode.parentNode._innerText;
else value = "";
}
var searchText = $get('<%=TextBox1.ClientID %>').value;
searchText = searchText.replace('null', '');
sender.get_element().value = value;
}
function acePopulated(sender, e) {
//Give BehaviourId here
var behavior = $find('AutoCompleteEx');
var target = behavior.get_completionList();
if (behavior._currentPrefix != null) {
var prefix = behavior._currentPrefix.toLowerCase();
var i;
for (i = 0; i < target.childNodes.length; i++) {
var sValue = target.childNodes[i].innerHTML.toLowerCase();
if (sValue.indexOf(prefix) != -1) {
var fstr = target.childNodes[i].innerHTML.substring(0, sValue.indexOf(prefix));
var pstr = target.childNodes[i].innerHTML.substring(fstr.length, fstr.length + prefix.length);
var estr = target.childNodes[i].innerHTML.substring(fstr.length + prefix.length, target.childNodes[i].innerHTML.length);
target.childNodes[i].innerHTML = "<div class='autocomplete-item'>" + fstr + '<B><font color=red>' + pstr + '</font></B>' + estr + "</div>";
}
}
}
}
On your AutoComplete Extender provide the following values....
BehaviorID="AutoCompleteEx"
OnClientPopulated="acePopulated"
OnClientItemSelected="aceSelected"
That is about it, I had to perform some minor changes and debugging. Like the closing java script tag is wrong, and the function to get the value from the textbox did not work with e.get_value() so I changed it to e._item.innerText and seem to be working just fine.
Source of Solution

jQuery Plugin "readmore", trim text without cutting words

I'm using http://rockycode.com/blog/jquery-plugin-readmore/ for trim long text and add a "See more" link to reveal all the text.
I would love to avoid cutting words, how could I do that?
If the limit is 35, don't cut the w...
but
If the limit is 35, don't cut the word... (and in this case, trim it at 38 and then show the hidden text from 39th chtill the end.
Instead of doing this:
$elem.readmore({
substr_len: 35
});
You could do this
$elem.readmore({
substr_len: $elem.text().substr(0, 35).lastIndexOf(" ")
});
What we're doing is to go to the latest space posible before index 35.
Of course 35 can be variable. Also you could put it into a function to reuse it.
Hope this helps
You can change the abridge function within that plugin as follows:
function abridge(elem) {
var opts = elem.data("opts");
var txt = elem.html();
var len = opts.substr_len;
var dots = "<span>" + opts.ellipses + "</span>";
var charAtLen = txt.substr(len, 1);
while (len < txt.length && !/\s/.test(charAtLen)) {
len++;
charAtLen = txt.substr(len, 1);
}
var shown = txt.substring(0, len) + dots;
var hidden = '<span class="hidden" style="display:none;">' + txt.substring(len, txt.length) + '</span>';
elem.html(shown + hidden);
}
...and it will behave as you desire. You might want to add an option to turn this feature off and on, but I'll leave that up to you.
See working example →
I was just gathering information about this subject, with your help and the help from other related posts I wrote this:
http://jsfiddle.net/KHd6J/526/

Clean Microsoft Word Pasted Text using JavaScript

I am using a 'contenteditable' <div/> and enabling PASTE.
It is amazing the amount of markup code that gets pasted in from a clipboard copy from Microsoft Word. I am battling this, and have gotten about 1/2 way there using Prototypes' stripTags() function (which unfortunately does not seem to enable me to keep some tags).
However, even after that, I wind up with a mind-blowing amount of unneeded markup code.
So my question is, is there some function (using JavaScript), or approach I can use that will clean up the majority of this unneeded markup?
Here is the function I wound up writing that does the job fairly well (as far as I can tell anyway).
I am certainly open for improvement suggestions if anyone has any. Thanks.
function cleanWordPaste( in_word_text ) {
var tmp = document.createElement("DIV");
tmp.innerHTML = in_word_text;
var newString = tmp.textContent||tmp.innerText;
// this next piece converts line breaks into break tags
// and removes the seemingly endless crap code
newString = newString.replace(/\n\n/g, "<br />").replace(/.*<!--.*-->/g,"");
// this next piece removes any break tags (up to 10) at beginning
for ( i=0; i<10; i++ ) {
if ( newString.substr(0,6)=="<br />" ) {
newString = newString.replace("<br />", "");
}
}
return newString;
}
Hope this is helpful to some of you.
You can either use the full CKEditor which cleans on paste, or look at the source.
I am using this:
$(body_doc).find('body').bind('paste',function(e){
var rte = $(this);
_activeRTEData = $(rte).html();
beginLen = $.trim($(rte).html()).length;
setTimeout(function(){
var text = $(rte).html();
var newLen = $.trim(text).length;
//identify the first char that changed to determine caret location
caret = 0;
for(i=0;i < newLen; i++){
if(_activeRTEData[i] != text[i]){
caret = i-1;
break;
}
}
var origText = text.slice(0,caret);
var newText = text.slice(caret, newLen - beginLen + caret + 4);
var tailText = text.slice(newLen - beginLen + caret + 4, newLen);
var newText = newText.replace(/(.*(?:endif-->))|([ ]?<[^>]*>[ ]?)|( )|([^}]*})/g,'');
newText = newText.replace(/[·]/g,'');
$(rte).html(origText + newText + tailText);
$(rte).contents().last().focus();
},100);
});
body_doc is the editable iframe, if you are using an editable div you could drop out the .find('body') part. Basically it detects a paste event, checks the location cleans the new text and then places the cleaned text back where it was pasted. (Sounds confusing... but it's not really as bad as it sounds.
The setTimeout is needed because you can't grab the text until it is actually pasted into the element, paste events fire as soon as the paste begins.
How about having a "paste as plain text" button which displays a <textarea>, allowing the user to paste the text in there? that way, all tags will be stripped for you. That's what I do with my CMS; I gave up trying to clean up Word's mess.
You can do it with regex
Remove head tag
Remove script tags
Remove styles tag
let clipboardData = event.clipboardData || window.clipboardData;
let pastedText = clipboardData.getData('text/html');
pastedText = pastedText.replace(/\<head[^>]*\>([^]*)\<\/head/g, '');
pastedText = pastedText.replace(/\<script[^>]*\>([^]*)\<\/script/g, '');
pastedText = pastedText.replace(/\<style[^>]*\>([^]*)\<\/style/g, '');
// pastedText = pastedText.replace(/<(?!(\/\s*)?(b|i|u)[>,\s])([^>])*>/g, '');
here the sample : https://stackblitz.com/edit/angular-u9vprc
I did something like that long ago, where i totally cleaned up the stuff in a rich text editor and converted font tags to styles, brs to p's, etc, to keep it consistant between browsers and prevent certain ugly things from getting in via paste. I took my recursive function and ripped out most of it except for the core logic, this might be a good starting point ("result" is an object that accumulates the result, which probably takes a second pass to convert to a string), if that is what you need:
var cleanDom = function(result, n) {
var nn = n.nodeName;
if(nn=="#text") {
var text = n.nodeValue;
}
else {
if(nn=="A" && n.href)
...;
else if(nn=="IMG" & n.src) {
....
}
else if(nn=="DIV") {
if(n.className=="indent")
...
}
else if(nn=="FONT") {
}
else if(nn=="BR") {
}
if(!UNSUPPORTED_ELEMENTS[nn]) {
if(n.childNodes.length > 0)
for(var i=0; i<n.childNodes.length; i++)
cleanDom(result, n.childNodes[i]);
}
}
}
This works great to remove any comments from HTML text, including those from Word:
function CleanWordPastedHTML(sTextHTML) {
var sStartComment = "<!--", sEndComment = "-->";
while (true) {
var iStart = sTextHTML.indexOf(sStartComment);
if (iStart == -1) break;
var iEnd = sTextHTML.indexOf(sEndComment, iStart);
if (iEnd == -1) break;
sTextHTML = sTextHTML.substring(0, iStart) + sTextHTML.substring(iEnd + sEndComment.length);
}
return sTextHTML;
}
Had a similar issue with line-breaks being counted as characters and I had to remove them.
$(document).ready(function(){
$(".section-overview textarea").bind({
paste : function(){
setTimeout(function(){
//textarea
var text = $(".section-overview textarea").val();
// look for any "\n" occurences and replace them
var newString = text.replace(/\n/g, '');
// print new string
$(".section-overview textarea").val(newString);
},100);
}
});
});
Could you paste to a hidden textarea, copy from same textarea, and paste to your target?
Hate to say it, but I eventually gave up making TinyMCE handle Word crap the way I want. Now I just have an email sent to me every time a user's input contains certain HTML (look for <span lang="en-US"> for example) and I correct it manually.

Categories