Skip to content

Instantly share code, notes, and snippets.

@xfenix
Last active September 18, 2016 21:32
Show Gist options
  • Save xfenix/df0e738f9e4514cc583e231e9ab72d1b to your computer and use it in GitHub Desktop.
Save xfenix/df0e738f9e4514cc583e231e9ab72d1b to your computer and use it in GitHub Desktop.
Global text search for bizagi web application (non-native, very dirty)
// поиск
$(function() {
$('.biz-ex-search-input, .biz-ex-btn-search, .biz-ex-search').unbind();
var $root = $('#search'),
$searchContainer = $('<ul>'),
$search = $root.find('.biz-ex-search-input'),
searchClassList = 'custom-ul ui-autocomplete ui-front ui-menu ui-widget ui-corner-all',
defaultSearchPlaceholder = 'Искать везде',
unicodeBoundaryStart = "(^\|[ \n\r\t.,'\"\+!?-]+)",
unicodeBoundaryEnd = "($\|[ \n\r\t.,'\"\+!?-]+)",
greedRe = '.*?',
liClassItem = 'ui-menu-item',
icons = {
'default': 'biz-ex-icon-AbstractTask',
'link': 'biz-ex-icon-Reference',
},
newStyles = $(
'<style>' +
'.custom-ul .biz-ex-result { overflow: hidden; }' +
'.custom-ul .biz-ex-icon-Reference { margin-left: -4px; margin-top: 0; }' +
'</style>'
),
liItem = '<li class="' + liClassItem + '">' +
'<a href="#url" target="_blank" data-fid="#id" class="biz-ex-result ui-corner-all" tabindex="-1">' +
'<i class="biz-ex-result-icon #icon"></i>' +
'<p class="biz-ex-result-name">#text</p></a>';
//'<p class="biz-ex-result-container"></p>';
fullIndex = [],
foundedItems = [],
tmp = '',
lastDiagramUrl = '',
minQueryLength = 3,
pushItemToIndex = function(item) {
if(item.value) {
item.value = cleanString(item.value);
if(item.value.length >= minQueryLength) {
fullIndex.push(item);
}
}
},
addElToIndex = function(id, element, parent) {
pushItemToIndex({
'type': 'element',
'value': 'description' in element ? element.description : '',
'title': element.name,
'id': id,
'parent': parent,
'icon': 'default',
});
},
cleanString = function(dirtyString) {
return $.trim(
dirtyString
.replace( /<.*?>/g, '')
.replace(/[^а-яА-Я\s]/g, '')
.replace('↵', '')
.replace(/\n/, ' ')
.replace('/\s{2,}/g', ' ')
.toLowerCase()
);
},
getUrlFromItem = function(item) {
return (item.type == 'diagram' ? 'diagram' : 'dialog/element') + '/' + item.id;
},
goToHashUrl = function(url) {
return Bizagi.App.Router.navigate(url, {trigger: true});
},
goToLastDiagramIfNeeded = function() {
// works only if we wait 500ms (why? motherfucker? why?)
if(lastDiagramUrl.length > 0) {
setTimeout(function() {
window.location.hash = lastDiagramUrl;
lastDiagramUrl = '';
}, 500);
}
},
compareVals = function(a, b) {
if(a < b)
return -1;
else if(a > b)
return 1;
return 0;
},
runSearch = function() {
// init vars
var i,
totalCount = 0,
alreadyAppendedIds = [],
alreadyAppendedTitles = [],
queryRaw = $search.val().toLowerCase(),
isMatched = false,
query = new RegExp('^' + greedRe + queryRaw + greedRe + '$');
// check length
if(queryRaw.length < minQueryLength) {
$search.attr('placeholder', 'Введите запрос минимум из ' + minQueryLength + ' букв');
return true;
}
// clear search list
foundedItems = [];
$searchContainer.html('');
// search itself
for(i in fullIndex) {
isMatched = query.test(fullIndex[i].value) || query.test(fullIndex[i].title);
// append search item only if not already appended
if(isMatched && alreadyAppendedIds.indexOf(fullIndex[i].id) == -1 &&
alreadyAppendedTitles.indexOf(fullIndex[i].title) == -1) {
totalCount++;
alreadyAppendedIds.push(fullIndex[i].id);
alreadyAppendedTitles.push(fullIndex[i].title);
foundedItems.push(fullIndex[i]);
}
}
// no matches
if(totalCount == 0) {
$searchContainer.append(
'<li style="padding: 10px;" class="' + liClassItem + '">' +
'<p class="biz-ex-result-name">Ничего не найдено</p>'
);
// matches - sort list, and build ui
} else {
// sort search items
foundedItems.sort(function(a, b) {
var a = a.title,
b = b.title,
a2 = parseInt(a.substr(0,2)),
b2 = parseInt(b.substr(0,2));
if(!isNaN(a2)) {
a = a2*100;
}
if(!isNaN(b2)) {
b = b2*100;
}
return compareVals(a, b);
});
// and build html list
for(i in foundedItems) {
tmp = liItem
.replace('#text', foundedItems[i].title)
.replace('#icon', icons[foundedItems[i].icon])
.replace('#id', i);
if(foundedItems[i].type == 'link') {
tmp = tmp.replace('#url', foundedItems[i].url);
}
$searchContainer.append(tmp);
}
}
// show results
$searchContainer.show();
// on click
$('.' + liClassItem).find('a').on('click', function() {
// go to dialog/element page
var searchItem = foundedItems[parseInt($(this).data('fid'))],
itemUrl = getUrlFromItem(searchItem);
if(searchItem.type != 'diagram') {
// preload parent (strange crash happens if we dont do this)
lastDiagramUrl = getUrlFromItem(fullIndex[searchItem.parent]);
goToHashUrl(lastDiagramUrl);
goToHashUrl(itemUrl);
} else {
goToHashUrl(itemUrl);
}
$searchContainer.hide();
if(searchItem.type != 'link') {
return false;
}
});
};
// build index
var parent = 0;
$(Bizagi.AppModel.pages).each(function(id, page) {
// search in page title
pushItemToIndex({
'type': 'diagram',
'value': page.name,
'id': page.id,
'title': page.name,
'icon': 'default',
});
parent = fullIndex.length - 1;
// go through elements
$(page.elements).each(function(_, element) {
// search in page subtitle
addElToIndex(element.id, element, parent);
// go throug page SUB elements (what is it?)
$(element.pageElements).each(function(_, subelement) {
addElToIndex(subelement.id, subelement, parent);
// go through properties (what is it? :) and gather sppr links
$(subelement.properties).each(function(_, property) {
if(property.name.indexOf('1С:СППР') > -1 && 'table' in property) {
// property.table is two dimension array
$(property.table.table).each(function(_, table) {
$(table).each(function(_, link) {
pushItemToIndex({
'type': 'link',
'value': link.urlText,
'title': link.urlText,
'url': link.value,
'id': subelement.id,
'icon': 'link',
});
});
});
}
});
});
});
});
// console.log(fullIndex);
// create search container and add styles
$('body').append($searchContainer);
$searchContainer.css({
width: $search.parent().width(),
top: $search.offset().top + $search.height(),
left: $search.offset().left,
})
.attr('class', searchClassList)
.hide();
// add custom styles
$('html > head').append(newStyles);
// react on hash change
if ("onhashchange" in window) {
window.onhashchange = function() {
$search.attr('placeholder', defaultSearchPlaceholder);
};
}
// user actions
$('.biz-ex-btn-search').on('click', function() {
runSearch();
return false;
});
$search.closest('form').on('submit', function() {
runSearch();
return false;
});
$search.on('focus click', function() {
runSearch();
});
// listen on window close (two ways)
// return to parent diagram, if we have one
$('body').on('click', '.reveal-modal-bg, .biz-ex-icon-close', function() {
goToLastDiagramIfNeeded();
});
// listen window close (third way) + search panel closing
// all on esc key
$(document).keyup(function(e) {
if (e.keyCode === 27) {
goToLastDiagramIfNeeded();
$searchContainer.hide();
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment