Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Thursday, July 7, 2011

Extend jQuery.highlight to highlight regular expressions

The jquery.highlight is a succinct and easy-to-use jQuery plugin to highlight texts. The current version can only highlight literary words case insensitively, but I extended it to highlight regular expressions so that you can highlight things like "foo*bar" as well. jquery.myhighlight-3.js:
/*

highlight v3 - Modified by Marshal (beatgates@gmail.com) to add regexp highlight, 2011-6-24

Highlights arbitrary terms.

<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>

MIT license.

Johann Burkard
<http://johannburkard.de>
<mailto:jb@eaio.com>

*/

jQuery.fn.highlight = function(pattern) {
    var regex = typeof(pattern) === "string" ? new RegExp(pattern, "i") : pattern; // assume very LOOSELY pattern is regexp if not string
    function innerHighlight(node, pattern) {
        var skip = 0;
        if (node.nodeType === 3) { // 3 - Text node
            var pos = node.data.search(regex);
            if (pos >= 0 && node.data.length > 0) { // .* matching "" causes infinite loop
                var match = node.data.match(regex); // get the match(es), but we would only handle the 1st one, hence /g is not recommended
                var spanNode = document.createElement('span');
                spanNode.className = 'highlight'; // set css
                var middleBit = node.splitText(pos); // split to 2 nodes, node contains the pre-pos text, middleBit has the post-pos
                var endBit = middleBit.splitText(match[0].length); // similarly split middleBit to 2 nodes
                var middleClone = middleBit.cloneNode(true);
                spanNode.appendChild(middleClone);
                // parentNode ie. node, now has 3 nodes by 2 splitText()s, replace the middle with the highlighted spanNode:
                middleBit.parentNode.replaceChild(spanNode, middleBit); 
                skip = 1; // skip this middleBit, but still need to check endBit
            }
        } else if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) { // 1 - Element node
            for (var i = 0; i < node.childNodes.length; i++) { // highlight all children
                i += innerHighlight(node.childNodes[i], pattern); // skip highlighted ones
            }
        }
        return skip;
    }
    
    return this.each(function() {
        innerHighlight(this, pattern);
    });
};

jQuery.fn.removeHighlight = function() {
    return this.find("span.highlight").each(function() {
        this.parentNode.firstChild.nodeName;
        with (this.parentNode) {
            replaceChild(this.firstChild, this);
            normalize();
        }
    }).end();
};
Here is a test file:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/javascript" src="lib/jquery-1.6.js"></script>
<script type="text/javascript" src="lib/jquery.myhighlight-3.js"></script>
<style>
.highlight {
    background-color: yellow;
}
</style>
</head>
<body>

<div id="row">
    <div>
        <a class="fullname" href="#"><span class="lastname">Goog</span>, <span class="firstname">Billy</span></a>
        <div id="remove">ServIcE: (click me to remove all highlight)</div>
        <div><span class="section">Pig &amp; Sheep Serv</span>, <span class="department">Cow Administration &amp; Management</span></div>
        <div class="org">Trade Administration, Administration Services</div>
        <div id="email">
            <a class="email" href="mailto:a@abc.com">a@abc.com</a>
        </div>
    </div>
</div>

<script type="text/javascript">
    $(function() {
        $("#row").highlight("service");
        $(".lastname").highlight("o");
        $(".section").highlight(/g.*ep/i);
        $(".department").highlight(/.*/i);
        $(".org").highlight(/adm.*(?=, )/i);
        $("#email").highlight(/a.c\./);
        $("#remove").click(function() {$("#row").removeHighlight();});
    });
</script>

</body>
</html>
And the result:

Here are the links for the source code:
  1. jquery.myhighlight-3.js
  2. jquery.myhighlight-3.min.js

Wednesday, May 25, 2011

Type-as-you-go Ajax People Search Web Part using SharePoint 2007 Search Services - Part II

After prototyped and compared both solutions, I found that Content Editor Web Part(CEWP) + Javascript seems more suitable for our needs. It's not only more lightweight, interactive and flexible, but also less administration overhead. The product looks like this:

Here is the design diagram:

Pure Javascript and HTML stuff wrapped in a SharePoint CEWP. The core component here is MyXslt transformer, a small Javascript library I released to transform the search service result (XML) into HTML elements. Below is a list of libraries I used:

Javascript libraries

jQuery1.5+
MyXsltXSLT transformer that transforms the search service result XML directly into HTML elements
jQuery UIUI for dialogs
QTipjQuery plugin for tip style people's details
HighlightjQuery plugin for keyword highlighting
MyImgScalejQuery plugin for Image scaling

The solution layout (for commercial reasons, the full source code is not published at this stage):
PeopleSearch
    +---.hg
    +---clientSideSolution
    |   +---cewp
    |   +---release
    |   +---standalone
    |   +---unitTest
    |   \---_layouts
    |       \---1033
    |           +---images
    |           +---js
    |           +---styles
    |           \---xslt
    +---PeopleSearchWebpart
    +---data
    +---script
    +---UnitTest
    +---UserControlTest
    +---WebTest
    +---LoadTest
    \---TestResults

Another thing worth mention is that the load testing results (see above, using Visual Studio 2010's built-in load testing tool) showed the application was very responsive too.

Sunday, February 20, 2011

Fix jQuery plugin xslt.js not working in Firefox 3.x

First of all, thanks Johann for his excellent jQuery XSLT plugin here.

Unfortunately, this one doesn't work with jQuery 1.5 in Firefox 3. One of the reasons is the readyState was changed to 0 after $.ajax loaded the xml and xslt files. Below is my fix by replacing line 84-118 in jquery.xslt.js with the following:
var change = function() {
    if (xm.readyState == xs.readyState && !transformed) {
        var processor = new XSLTProcessor();
        if ($.isFunction(processor.transformDocument)) {
            // obsolete Mozilla interface
            resultDoc = document.implementation.createDocument("", "", null);
            processor.transformDocument(xm.responseXML, xs.responseXML, resultDoc, null);
            target.html(new XMLSerializer().serializeToString(resultDoc));
        }
        else {
            processor.importStylesheet(xs.responseXML);
            resultDoc = processor.transformToFragment(xm.responseXML, document);
            target.empty().append(resultDoc);
        }
        transformed = true;
    }
};

if (str.test(xml)) {
    xm.responseXML = new DOMParser().parseFromString(xml, "text/xml");
}
else {
    xm = $.ajax({ dataType: "xml", url: xml});
}

if (str.test(xslt)) {
    xs.responseXML = new DOMParser().parseFromString(xslt, "text/xml");
}
else {
    xs = $.ajax({ dataType: "xml", url: xslt});
}
change();
return this;
Will contact the author and update the post later...
(Update: the author hasn't responded, but I created a better solution here.)

Ref: xslt.js version 3.2

Thursday, February 17, 2011

jQuery "Object Expected" error in IE

I encountered this problem when prototyping some SharePoint webparts. It actually works well in Firefox and Chrome. Here's the snippet for illustration:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/javascript" src="../js/jquery-1.5.min.js"></script>

<script type="text/javascript">

    $(function() { // <=> $(document).ready(function() {
...
By adding one line of code in line 7 before $(function(),
alert(typeof $);
it prompts "undefined", meaning jQuery is not loaded by IE. The solution is quite simple, IE->Tools->Internet Options->Security, by default it is High, either change it to Medium, or use custom level then enable Scripting->Active scripting (IE8). Now it alerts "function" and jQuery is working nifty then.

Ref: jQuery $(document).ready() failing in IE6