Last active
September 18, 2016 21:32
-
-
Save xfenix/df0e738f9e4514cc583e231e9ab72d1b to your computer and use it in GitHub Desktop.
Global text search for bizagi web application (non-native, very dirty)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// поиск | |
$(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