/**
* Implements the Find and Replace dialog
*
* @param {string} edid
* @constructor
*/
var ToolboxFindAndReplace = function (edid) {
var textarea = jQuery('#' + edid)[0];
// the dialog HTML
var $dialog = jQuery(
'
' +
'' +
' ' +
'' +
' ' +
' ' +
' ' +
'' +
'
'
);
// pointers to the various elements in the dialog
$dialog.components = {
in_find: $dialog.find('input.find'),
btn_find: $dialog.find('button.find'),
chk_casematch: $dialog.find('input.casematch'),
chk_regexp: $dialog.find('input.regexp'),
chk_words: $dialog.find('input.words'),
in_replace: $dialog.find('input.replace'),
btn_replace: $dialog.find('button.replace'),
btn_find_replace: $dialog.find('button.find_replace'),
btn_replace_all: $dialog.find('button.replace_all')
};
// register handlers
$dialog.components.btn_find.click(handle_find);
$dialog.components.btn_replace.click(handle_replace);
$dialog.components.btn_find_replace.click(handle_find_replace);
$dialog.components.btn_replace_all.click(handle_replace_all);
/**
* Initialize the dialog
*/
$dialog.dialog({
title: toolbox_lang.f_r,
resizable: false,
// show outside the textarea
position: {
my: 'right+25 bottom-25',
at: 'right top',
of: textarea
},
// clean up on close
close: function () {
$dialog.dialog('destroy');
$dialog.remove();
}
});
/**
* Refocus the textarea after interaction with the dialog
*
* except for input fields. this makes sure selections are visible
*/
$dialog.dialog('widget').mouseup(function (e) {
if (e.target.nodeName == 'INPUT') return;
window.setTimeout(function () {
textarea.focus();
}, 1);
});
/**
* Handle find
*
* It highlights the next place where the current search term
* can be found. Looking from the cursor position onward.
*
* @return {boolean} true when the word was found
*/
function handle_find() {
var sel = DWgetSelection(textarea);
var term = $dialog.components.in_find.val();
if (term == '') return false;
var found = findNextPosition(term, sel.end);
if (found[0] === -1) return false;
selectWord(found[0], found[1].length);
return true;
}
/**
* Handle replace
*
* It replaces the current selection with the replacement
*
* @return {boolean} true when the selection was replaced
*/
function handle_replace() {
var sel = DWgetSelection(textarea);
if (sel.start === sel.end) {
window.alert(toolbox_lang.notext);
return false;
}
var text = $dialog.components.in_replace.val();
pasteText(sel, text, {startofs: 0, endofs: 0, nosel: true});
return true;
}
/**
* Handle find&replace
*
* Look for the next match and replace it
*
* @return {boolean}
*/
function handle_find_replace() {
return handle_find() && handle_replace();
}
/**
* Handle replace all
*
* Counts matches first and asks for confirmation
*
* @return {boolean}
*/
function handle_replace_all() {
var term = $dialog.components.in_find.val();
if (term == '') return false;
var text = textarea.value;
var repl = $dialog.components.in_replace.val();
var re = makeRegexp(term, 'g');
// count the matches
var m;
var found = 0;
while (m = re.exec(text)) {
found++;
}
if (!found) {
window.alert(toolbox_lang.nothing);
return false;
}
if (window.confirm(toolbox_lang.really.replace('%d', found))) {
textarea.value = text.replace(re, repl);
return true;
}
return false;
}
/**
* Select the given range in the textarea and scrolls to it
*
* @param start
* @param len
*/
function selectWord(start, len) {
var sel = DWgetSelection(textarea);
// first move cursor only, defocus for a moment to make the area scroll
sel.start = start;
sel.end = start;
sel.scroll = undefined;
DWsetSelection(sel);
textarea.blur();
textarea.focus();
// then select the found word
sel.end = start + len;
DWsetSelection(sel);
}
/**
* Find the postion of the term right of pos
*
* @param {string} term
* @param {int} pos
* @returns {[{int}, {string}]} the position and the matched term
*/
function findNextPosition(term, pos) {
var text = textarea.value.substr(pos);
var re = makeRegexp(term);
var idx = text.search(re);
if (idx === -1) {
if (pos !== 0) {
if (window.confirm(toolbox_lang.fromtop)) {
return findNextPosition(term, 0);
} else {
return [-1, term];
}
} else {
window.alert(toolbox_lang.nothing);
return [-1, term];
}
}
var match = text.match(re);
return [pos + idx, match[0]];
}
/**
* create the proper regexp to search for the given term
*
* It checks the current settings and sets the proper flags
* for the regular expression. It also escapes the given term
* if needed
*
* @param term
* @param {string} [flags] initial regexp flags to set
* @returns {RegExp}
*/
function makeRegexp(term, flags) {
if (!flags) flags = '';
if (!$dialog.components.chk_regexp.prop('checked')) {
term = quoteRE(term);
}
if (!$dialog.components.chk_casematch.prop('checked')) {
flags += 'i';
}
if ($dialog.components.chk_words.prop('checked')) {
term = '(?:\\b)' + term + '(?:\\b)';
}
console.log(term);
try {
return new RegExp(term, flags);
} catch (e) {
window.alert(toolbox_lang.reerror + '\n' + e.message);
return null;
}
}
/**
* Escapes characters in the string that are not safe to use in a RegExp.
*
* @param {*} s The string to escape. If not a string, it will be casted to one.
* @return {string} A RegExp safe, escaped copy of {@code s}.
* @link http://stackoverflow.com/a/18151038/172068
*/
function quoteRE(s) {
return String(s).replace(/([-()\[\]{}+?*.$\^|,:#