diff --git a/notebook/static/notebook/js/actions.js b/notebook/static/notebook/js/actions.js index 0f73e24cd..151833179 100644 --- a/notebook/static/notebook/js/actions.js +++ b/notebook/static/notebook/js/actions.js @@ -4,15 +4,17 @@ define(function(require){ "use strict"; + var dialog = require('base/js/dialog'); + var ActionHandler = function (env) { this.env = env || {}; Object.seal(this); }; - + function escapeRegExp(string){ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } - + /** * Give a `needle` string, find all occurences of `needle` ins it * and return an array of [][start, stop], ...] non-overlapping indexes. @@ -21,7 +23,7 @@ define(function(require){ var findAll = function(needle, haystack, caseinsensitive){ if(!needle){ return []; - + } if(caseinsensitive){ needle = needle.toLowerCase(); @@ -30,7 +32,7 @@ define(function(require){ var result = []; for(var j=0; j< haystack.length; j++){ var next = haystack.indexOf(needle, j); - + if(next === -1){ break; } else{ @@ -40,7 +42,7 @@ define(function(require){ } return result; }; - + /** * A bunch of predefined `Simple Actions` used by Jupyter. @@ -388,7 +390,7 @@ define(function(require){ .css('border-radius', '0') .css('border-left', 'none') .text('.*'); - + var isCaseSensitiveButton = $('') .attr('type', 'button') .addClass("btn btn-default") @@ -398,24 +400,47 @@ define(function(require){ .css('border-top-left-radius', '0') .css('border-bottom-left-radius', '0') .css('border-left', 'none') - .click(function(){search.focus();}) .text('a≠A'); - + + var repl = $("") + .addClass('form-control') + .attr('placeholder','replace'); + var body = $('
') + .css('max-height','60vh') + .css('overflow','auto'); + var form = $('') + .append($('').addClass('form-group') + .append( + $('').addClass('input-group').css("width","100%") + .append(search) + .append(isRegExpButton) + .append(isCaseSensitiveButton) + ) + ) + .append($('').addClass('form-group').append(repl)) + .append(body); + + + // return wether the search is case sensitive var isCaseSensitive = function(){ var value = isCaseSensitiveButton.attr('aria-pressed') == 'true'; return value; }; - + + // return wether the search is reex based, or + // plain string maching. var isReg = function(){ var value = isRegExpButton.attr('aria-pressed') == 'true'; return value; }; - + + + // returna Pseudo RexEx object that acts + // either as a plain RegExp Object, or as a pure string matching. + // automatically set the flags for case sensitivity from the UI var RegExpOrNot = function(str, flags){ if (!isCaseSensitive()){ - flags = flags || ''; - flags = flags+'i'; - console.info('using flags:', flags); + flags = (flags || '')+'i'; } if (isRegExpButton.attr('aria-pressed') === 'true'){ return new RegExp(str, flags); @@ -423,142 +448,148 @@ define(function(require){ return new RegExp(escapeRegExp(str), flags); } }; - - var repl = $("") - .addClass('form-control') - .attr('placeholder','replace'); - //var submit = $("").attr('type', 'submit'); - var body = $('').css('max-height','60vh').css('overflow','auto'); - var form = $('') - .append($('').addClass('form-group') - .append( - $('').addClass('input-group').css("width","100%") - .append(search) - .append(isRegExpButton) - .append(isCaseSensitiveButton) - ) - ) - .append($('').addClass('form-group').append(repl)) - .append(body); - - var onsubmit = function(event){ - var sre = search.val(); - var replace = repl.val(); - if(!sre){ - return false; + + + var onError = function(){ + body.empty(); + body.append($('').text('No matches, invalid or empty regular expression')); + + }; + + var get_all_text = function(cells){ + if(get_all_text._cache){ + return get_all_text._cache; } - var cells = env.notebook.get_cells(); var arr = []; for(var c=0; c < cells.length; c++){ - var oldvalue = cells[c].code_mirror.getValue(); - var newvalue = oldvalue.replace(new RegExpOrNot(sre, 'g'), replace); - cells[c].code_mirror.setValue(newvalue); - if(cells[c].cell_type === 'markdown'){ - cells[c].rendered = false; - cells[c].render(); - } - + arr = arr.concat(cells[c].code_mirror.getValue().split('\n')); } - + get_all_text._cache = arr; + return arr; }; - - - var ontype = function(){ - + /** + * callback trigered anytime a change is made to the + * request, caseSensitivity, isregex, search or replace + * modification. + **/ + var onchange = function(){ + var sre = search.val(); // abort on invalid RE if(!sre){ - body.empty(); - body.append($('').text('No matches, invalid or empty regular expression')); - return; + return onError(); } - + try { new RegExpOrNot(sre); } catch (e){ - body.empty(); - body.append($('').text('No matches, invalid or empty regular expression')); - return; + return onError(); } + + // might want to warn if replace is empty var replace = repl.val(); var cells = env.notebook.get_cells(); - var arr = []; - for(var c=0; c < cells.length; c++){ - arr = arr.concat(cells[c].code_mirror.getValue().split('\n')); - } - + var arr = get_all_text(cells); var html = []; - - - // and create an array of // before_match, match , replacement, after_match var aborted = false; + var replacer_reg = new RegExpOrNot(sre); for(var r=0; r < arr.length; r++){ - var match_abort = getMatches(sre, arr[r], isCaseSensitive(), RegExpOrNot); + var current_line = arr[r]; + var match_abort = getMatches(sre, current_line, isCaseSensitive(), RegExpOrNot); aborted = aborted || match_abort[1]; var matches = match_abort[0]; - console.info('len:', matches.length); for(var mindex=0; mindex < matches.length ; mindex++){ var start = matches[mindex][0]; var stop = matches[mindex][1]; - var init = arr[r].slice(start, stop); - var replaced; - if (isReg()||true){ - replaced = init.replace( new RegExpOrNot(sre), replace); - } else { - replaced = sre; - } - html.push([cutBefore(arr[r].slice(0, start)), arr[r].slice(start, stop), replaced, cutAfter(arr[r].slice(stop), 30-(stop-start))]); + var initial = current_line.slice(start, stop); + var replaced = initial.replace(replacer_reg, replace); + // that might be better as a dict + html.push([cutBefore(current_line.slice(0, start)), + initial, + replaced, + cutAfter(current_line.slice(stop), 30-(stop-start))]); } } - body.empty(); - if(aborted){ - body.append($('').addClass('bg-warning').text("Warning, too many matches ("+html.length+"+), some changes might not be shown or applied")); - } else { - body.append($('').addClass('bg-info').text(html.length+" matche"+(html.length==1?'':'s'))); - - } - - - for(var rindex=0; rindex