Now I’m not sure the best way to do this but I did find that this is probably they way I’ll push for this.

We have multiple knowledge bases at my work and as such the default search is very limited. I wanted to add to the type ahead a result like “Search all KB’s for your term here”.

I looked at the search sources and found it has a scripted bit but it’s not documented well.

Finished Product

OOB Search Source

So first lets look at the out of box “Service Catalog” search source, specifically it’s data fetch (shows up when you select, Is scripted source)

(function(query) {
    var results = [];
    //Here goes the logic. Compute results however you want!
    if (!gs.isLoggedIn())
        return results;

    var sc = new GlideRecord('sc_cat_item');
    sc.addQuery('123TEXTQUERY321', query);
    sc.addQuery('active',true);
    sc.addQuery('no_search', '!=', true);
    sc.addQuery('visible_standalone', true);
    sc.addQuery('sys_class_name', 'NOT IN', 'sc_cat_item_wizard');
    var portalValue = $sp.getValue('sc_catalog');
    if (portalValue)
        sc.addQuery('sc_catalogs', portalValue);
    sc.query();
    var catCount = 0;
    while (sc.next() && catCount < data.limit) {
        if (!$sp.canReadRecord(sc))
            continue;

        var item = {};
        item.type = "sc";
        item.page = "sc_cat_item";

        if (sc.getRecordClassName() == "sc_cat_item_guide")
            item.page = "sc_cat_item_guide";
        else if (sc.getRecordClassName() == "sc_cat_item_content") {
            var gr = new GlideRecord('sc_cat_item_content');
            gr.get(sc.getUniqueValue());
            $sp.getRecordValues(item, gr, 'url,content_type,kb_article');
            item.type = "sc_content";
        }
        else
            item.type = "sc";

        $sp.getRecordDisplayValues(item, sc, 'name,short_description,picture,price,sys_id,sys_class_name');
        item.score = parseInt(sc.ir_query_score.getDisplayValue());
        item.label = item.name;
        item.primary = item.name;

        //calculating URL
        if (item.type == "sc")
            item.url = '?id=' + item.page + '&sys_id=' + item.sys_id;
        if (item.type == "sc_content") {
            if (item.content_type == "kb")
                item.url = '?id=kb_article&sys_id=' + item.kb_article;
            else if (item.content_type == "external")
                item.target = '_blank';
            else
                item.url = '?id=sc_cat_item&sys_id=' + item.sys_id;
        }
        if (item.type == "sc_guide")
            item.url = '?id=sc_cat_item_guide&sys_id=' + item.sys_id;

        results.push(item);
        catCount++;
    }

    return results;
})(query);

There’s a lot going on there, but what I picked out was, it returns an array of objects where the object has the following properties;

{
    score:"-100",
    label:resultMsg,
    primary:resultMsg,
    url: "?id=kb_search&spa=1&query=" + query,
    //target: "",
    //page:"kb_search"
}

Score

This seems pretty obvious to me, a integer to determine order in the results

Label and Primary

I’m not sure the difference but this seems to be what shows up as text in the result.

URL

This is where the browser will go on click.

Target

I assume this is the a tag’s target attribute, so if you want a new tab each time use a value of _blank.

Page

I am not sure if this does anything on it’s own, in the out of box widget they use this in the defined url.

Search Source I made

Below is my search source script.

(function(query) {
    var resultMsg = "Search KB for " + query;
    var results = [{
        score:"-100",
        label:resultMsg,
        primary:resultMsg,
        url: "?id=kb_search&spa=1&query=" + query,
        //target: "",
        //page:"kb_search"
    }];
    return results;
})(query);

Further Reading

Community Thread