searchbox wip

This commit is contained in:
Vlad Zinculescu 2012-11-28 16:01:31 +01:00 committed by nightwing
commit 8d3c4feeb5
4 changed files with 394 additions and 11 deletions

View file

@ -108,7 +108,7 @@ env.editor.commands.addCommands([{
editor.gotoLine(line);
},
readOnly: true
}, {
}/*, {
name: "find",
bindKey: {win: "Ctrl-F", mac: "Command-F"},
exec: function(editor, needle) {
@ -121,7 +121,7 @@ env.editor.commands.addCommands([{
editor.find(needle);
},
readOnly: true
}, {
}*/, {
name: "focusCommandLine",
bindKey: "shift-esc",
exec: function(editor, needle) { editor.cmdLine.focus(); },

View file

@ -33,6 +33,7 @@ define(function(require, exports, module) {
var lang = require("../lib/lang");
var SearchBox = require("ace/ext/searchbox");
function bindKey(win, mac) {
return {
win: win,
@ -94,8 +95,7 @@ exports.commands = [{
name: "find",
bindKey: bindKey("Ctrl-F", "Command-F"),
exec: function(editor) {
var needle = prompt("Find:", editor.getCopyText());
editor.find(needle);
SearchBox.SearchBox(editor, editor.getSelectionRange());
},
readOnly: true
}, {
@ -345,13 +345,7 @@ exports.commands = [{
name: "replace",
bindKey: bindKey("Ctrl-R", "Command-Option-F"),
exec: function(editor) {
var needle = prompt("Find:", editor.getCopyText());
if (!needle)
return;
var replacement = prompt("Replacement:");
if (!replacement)
return;
editor.replace(replacement, {needle: needle});
SearchBox.SearchBox(editor, editor.getSelectionRange(), true);
}
}, {
name: "replaceall",

View file

@ -366,3 +366,133 @@
.ace_italic {
font-style: italic;
}
/* ------------------------------------------------------------------------------------------
* Editor Search Form
* --------------------------------------------------------------------------------------- */
.ace_search {
background-color: #ddd;
border: 1px solid #cbcbcb;
border-top: 0 none;
max-width: 297px;
overflow: hidden;
padding: 4px;
padding-right: 6px;
padding-bottom: 0;
position: absolute;
top: 0px;
z-index: 99;
}
.ace_search.left {
border-left: 0 none;
border-radius: 0px 0px 5px 0px;
left: 0;
}
.ace_search.right {
border-radius: 0px 0px 0px 5px;
border-right: 0 none;
right: 0;
}
.ace_search_form {
border-radius: 3px;
border: 1px solid #cbcbcb;
float: left;
margin-bottom: 4px;
overflow: hidden;
}
.ace_search label {
float: left;
color: #656565;
}
.ace_search input {
background: white;
border-right: 1px solid #cbcbcb;
border: 0 none;
box-sizing: border-box;
display: block;
float: left;
height: 22px;
outline: 0;
padding: 0 7px;
width: 214px;
}
.ace_searchbtn,
.ace_replacebtn {
background: #fff;
border: 0 none;
border-left: 1px solid #dcdcdc;
cursor: pointer;
display: block;
float: left;
height: 22px;
margin: 0;
padding: 0;
position: relative;
}
.ace_searchbtn:last-child,
.ace_replacebtn:last-child {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.ace_searchbtn {
width: 27px;
}
.ace_searchbtn:after {
border: 2px solid #656565;
content: "";
display: block;
height: 4px;
position: absolute;
width: 4px;
-webkit-transform: rotateZ(45deg);
}
.ace_searchbtn.prev:after {
border-right: 0 none;
border-bottom: 0 none;
left: 10px;
top: 9px;
}
.ace_searchbtn.next:after {
border-left: 0 none;
border-top: 0 none;
left: 10px;
top: 7px;
}
.ace_searchbtn:disabled {
background: none;
cursor: default;
}
.ace_searchbtn:disabled:after {
border-color: #ccc;
}
.ace_searchbtn_close {
background: none;
border-radius: 50%;
border: 0 none;
color: #656565;
cursor: pointer;
display: block;
float: right;
font-family: Arial;
font-size: 16px;
height: 14px;
line-height: 16px;
margin: 5px 1px 9px 5px;
padding: 0;
text-align: center;
width: 14px;
}
.ace_searchbtn_close:hover {
background: #656565;
color: white;
}
.ace_replacebtn {
}
.ace_replacebtn.prev {
width: 54px
}
.ace_replacebtn.next {
width: 27px
}

259
lib/ace/ext/searchbox.js Normal file
View file

@ -0,0 +1,259 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var dom = require("ace/lib/dom");
var event = require("ace/lib/event");
var Range = require("ace/range").Range;
exports.SearchBox = function (editor, range, showReplaceForm) {
var _self = this;
var sb = null;//search box
var n = null;//needle
var r = null;//replace
var p = null;//parent DOM node
var needle = editor.session.getTextRange(range);
this.$init = function() {
p = editor.container.parentNode;
sb = p.querySelector(".ace_search"); //the complete form
if(!sb) {
//Create the elements
sb = document.createElement("div");
sb.setAttribute("class", "ace_search right");
p.appendChild( sb );
var c = document.createElement("button"); //cancel btn
c.setAttribute("type","button");
c.setAttribute("class","ace_searchbtn_close");
c.innerHTML = "&times";
sb.appendChild( c );
c.onclick = _self.hide;
var sf = document.createElement("div"); //search form
sf.setAttribute("id", "ace_search_form");
sf.setAttribute("class", "ace_search_form");
sb.appendChild( sf );
n = document.createElement("input"); //needle
n.setAttribute("class", "ace_search_field");
n.setAttribute("id", "ace_search_field");
n.setAttribute("placeholder", "Search for");
n.setAttribute("type", "text");
sf.appendChild( n );
var sp = document.createElement("button");
sp.setAttribute("type","button");
sp.setAttribute("class","ace_searchbtn prev");
sf.appendChild( sp );
sp.onclick = _self.findPrev;
var sn = document.createElement("button");
sn.setAttribute("type","button");
sn.setAttribute("class","ace_searchbtn next");
sf.appendChild( sn );
sn.onclick = _self.findNext;
var rf = document.createElement("div"); //replace form
rf.setAttribute("id", "ace_replace_form");
rf.setAttribute("class", "ace_search_form");
rf.setAttribute("style", "display: none");
sb.appendChild( rf);
r = document.createElement("input"); //needle
r.setAttribute("class", "ace_search_field");
r.setAttribute("id", "ace_replace_field");
r.setAttribute("placeholder", "Replace with");
r.setAttribute("type", "text");
rf.appendChild( r );
var rr = document.createElement("button");
rr.setAttribute("type","button");
rr.setAttribute("class","ace_replacebtn prev");
rr.innerHTML = "Replace";
rf.appendChild( rr );
rr.onclick = _self.replace;
var ra = document.createElement("button");
ra.setAttribute("type","button");
ra.setAttribute("class","ace_replacebtn next");
ra.innerHTML = "All";
rf.appendChild( ra );
ra.onclick = _self.replaceAll;
} else {
sb.removeAttribute("style");
n = sb.querySelector("#ace_search_field");
r = sb.querySelector("#ace_replace_field");
}
console.log( "showReplaceForm", showReplaceForm );
if( showReplaceForm ) {
p.querySelector("#ace_replace_form").removeAttribute("style");
}
if( needle )
n.value = needle;
//set initial focus and select text in input
n.focus();
n.select();
//keybinging outsite of the searchbox
_self.$searchKeybingin = {
handleKeyboard: function(data, hashId, keyString, keyCode) {
console.log("MERGE");
if (keyString == "esc")
return {command: this.command};
},
command: {
exec: function(editor) {
_self.hide();
}
}
};
editor.keyBinding.addKeyboardHandler(this.$searchKeybingin);
n.onkeydown = searchonkeydown;
r.onkeydown = searchonkeydown;
function searchonkeydown(e) {
var cmdKey = e.metaKey || e.ctrlKey;
console.log(cmdKey);
if( cmdKey ) {
if( e.which == 70 ) { //f key
var rf = p.querySelector("#ace_replace_form");
if( e.altKey && rf.hasAttribute("style") ) {
p.querySelector("#ace_replace_form").removeAttribute("style");
} else {
_self.hide();
}
return false;
}
}
if( e.which === 9 ) { //tab
if( e.target == n ) {
r.focus();
r.select();
} else {
n.focus();
n.select();
}
return false;
}
}
n.onpaste = function(e) {
//I do this because the onpaste event is fired before the value of the input actually changes
setTimeout(function() {
e.target.onkeyup();
}, 100);
}
n.onkeyup = function(e){
console.log("KEYUP", e);
if(!e) {
e = {};
e.which = 0;
}
if( e.which === 27 ) { //esc key
_self.hide();
} else if( e.which === 13 ) { //enter key
_self.findNext( );
} else {
editor.moveCursorTo( range.start.row, range.start.column );
_self.findNext();
}
};
r.onkeyup = function(e){
if( e.which === 27 ) { //esc key
_self.hide();
} else if( e.which === 13 ) { //enter key
editor.moveCursorTo( range.start.row, range.start.column );
_self.replace();
}
};
};
this.findPrev = function() {
editor.find(n.value, {
backwards: true,
wrap: true
});
};
this.findNext = function() {
editor.find(n.value, {
backwards: false,
wrap: true
});
};
this.replace = function() {
editor.replace( r.value );
_self.findNext();
};
this.replaceAll = function() {
editor.replaceAll( r.value );
};
this.hide = function () {
n.value = "";
r.value = "";
sb.setAttribute("style", "display: none");
sb.querySelector("#ace_replace_form").setAttribute("style", "display: none");
editor.keyBinding.removeKeyboardHandler(this.$searchKeybingin);
editor.focus();
};
_self.$init();
};
});
/* ------------------------------------------------------------------------------------------
* TODO
* --------------------------------------------------------------------------------------- */
/*
- move search form to the left if it masks current word
- includ all options that search has. ex: regex
- searchbox.searchbox is not that pretty. we should have just searchbox
- disable prev button if it makes sence
*/