diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..677c465
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.bundle
diff --git a/.versions.conf b/.versions.conf
new file mode 100644
index 0000000..f2cdbd3
--- /dev/null
+++ b/.versions.conf
@@ -0,0 +1,2 @@
+ruby=ruby-2.1.0
+ruby-gemset=grokdebug
diff --git a/public/sticky.css b/public/sticky.css
index d3482b7..ab671e9 100644
--- a/public/sticky.css
+++ b/public/sticky.css
@@ -2,6 +2,10 @@ html, body, .container, .container-fluid, .content {
height: 100%;
}
+label[for]:not([for=""]) {
+ cursor: pointer;
+}
+
.container, .container-fluid, .content {
position: relative;
}
@@ -17,10 +21,63 @@ html, body, .container, .container-fluid, .content {
margin: 0 auto -50px; /* same as the footer */
}
+.text-right {
+ text-align: right;
+}
+
.push {
height: 50px; /* same as the footer */
}
.footer-wrapper {
position: relative;
height: 50px;
+}
+
+/* Animated rotating icon */
+.icon-spin {
+ display: inline-block;
+ -moz-animation: spin 2s infinite linear;
+ -o-animation: spin 2s infinite linear;
+ -webkit-animation: spin 2s infinite linear;
+ animation: spin 2s infinite linear;
+}
+@-moz-keyframes spin {
+ 0% {
+ -moz-transform: rotate(0deg);
+ }
+ 100% {
+ -moz-transform: rotate(359deg);
+ }
+}
+@-webkit-keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ }
+}
+@-o-keyframes spin {
+ 0% {
+ -o-transform: rotate(0deg);
+ }
+ 100% {
+ -o-transform: rotate(359deg);
+ }
+}
+@-ms-keyframes spin {
+ 0% {
+ -ms-transform: rotate(0deg);
+ }
+ 100% {
+ -ms-transform: rotate(359deg);
+ }
+}
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(359deg);
+ }
}
\ No newline at end of file
diff --git a/views/discover.haml b/views/discover.haml
index ea86562..51d3564 100644
--- a/views/discover.haml
+++ b/views/discover.haml
@@ -5,13 +5,15 @@
.control-group
.controls
%form{ :action => "#", :class => "form-horizontal", :id => "grok-form"}
- %textarea{ :id => "input", :rows => "5", :action => "#", :class => "span9" }
- %button{ :type => "submit", :class => "btn btn-primary"}
- Discover
- %button{ :class => "btn btn-danger", :type => "button", :id => "resetall" }
- Reset
- .well-large
- %pre{ :class => "span9", :id => "grok"}
+ %textarea{ :id => "input", :rows => "5", :action => "#", :class => "span12" }
+ %br
+ .text-right
+ %button{ :type => "submit", :class => "btn btn-primary"}
+ Discover
+ %button{ :class => "btn btn-danger", :type => "button", :id => "resetall" }
+ Reset
+ .well
+ %pre{ :id => "grok"}
.push
.footer-wrapper
%footer
diff --git a/views/index.haml b/views/index.haml
index 21de2c6..377f2bd 100644
--- a/views/index.haml
+++ b/views/index.haml
@@ -1,30 +1,33 @@
.container
.content
.wrapper
- .proper-content
+ .proper-content
%form{ :action => "#", :id => "grok-form" }
- %textarea{ :type => "text", :class => "span12", :placeholder => "Input", :id => "input" }
+ %textarea{ :type => "text", :class => "span12", :placeholder => "Input", :id => "input", :rows => "5" }
.ui-widget
- %textarea{ :type => "text", :class => "span12", :placeholder => "Pattern", :id => "tags" }
- %label{ :class => "checkbox inline",}
+ %textarea{ :type => "text", :class => "span12", :placeholder => "Pattern", :id => "tags", :rows => "5" }
+ %label{ :for => "add_custom_patterns", :class => "checkbox inline",}
%input{ :id => "add_custom_patterns", :type => "checkbox", :value= => "" }
Add custom patterns
- %label{ :class => "checkbox inline",}
+ %label{ :for => "keep_empty_captures", :class => "checkbox inline",}
%input{ :id => "keep_empty_captures", :type => "checkbox", :value= => "" }
Keep Empty Captures
- %label{ :class => "checkbox inline" }
+ %label{ :for => "named_captures_only", :class => "checkbox inline" }
%input{ :id => "named_captures_only", :type => "checkbox", :value => "" }
Named Captures Only
- %label{ :class => "checkbox inline" }
+ %label{ :for => "singles", :class => "checkbox inline" }
%input{ :id => "singles", :type => "checkbox", :value => "" }
Singles
- %label{ :class => "checkbox inline pull-right" }
- %input{ :id => "autocomplete", :type => "checkbox", :value => "" }
- Autocomplete
+ %span{ :class => "pull-right" }
+ %label{ :for => "autocomplete", :class => "checkbox inline" }
+ %input{ :id => "autocomplete", :type => "checkbox", :value => "" }
+ Autocomplete
+
+ %input{ :type => "submit", :class => "inline btn btn-primary", :value => "Go"}
%div{:id => "custom_patterns_container", :style=>"display:none;"}
%p
One per line, the syntax for a grok pattern is %{SYNTAX:SEMANTIC}
- %textarea{ :class => "span12", :placeholder => "Custom patterns", :id => "custom_patterns", }
+ %textarea{ :class => "span12", :placeholder => "Custom patterns", :id => "custom_patterns", :rows => "5" }
%div{ :class => "well" }
%pre{ :id => "grok" }
.push
@@ -36,81 +39,145 @@
%script{ :type => "text/javascript", :src => "//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js" }
%script{ :type => "text/javascript", :src => "//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js" }
:javascript
+ // function to load settings from localstorage
+ var loadLocalstorage = function() {
+ $('#input').val(localStorage.getItem('input'));
+ $('#tags').val(localStorage.getItem('pattern'));
+ $('#add_custom_patterns').prop('checked', parseInt(localStorage.getItem('add_custom_patterns')));
+ $('#named_captures_only').prop('checked', parseInt(localStorage.getItem('named_captures_only')));
+ $('#keep_empty_captures').prop('checked', parseInt(localStorage.getItem('keep_empty_captures')));
+ $('#singles').prop('checked', parseInt(localStorage.getItem('singles')));
+ $('#autocomplete').prop('checked', parseInt(localStorage.getItem('autocomplete')));
+
+ // show custom pattern window and fill valueif needed
+ if ($('#add_custom_patterns').is(':checked')) {
+ $('#custom_patterns').val(localStorage.getItem('custom_patterns'));
+ $('#custom_patterns_container').show();
+ }
+ };
+ // function to save settings to localstorage
+ var saveLocalstorage = function(custom_patterns, input, pattern, add_custom_patterns, named_captures_only, keep_empty_captures, singles, autocomplete) {
+ localStorage.setItem('custom_patterns', custom_patterns);
+ localStorage.setItem('input', input);
+ localStorage.setItem('pattern', pattern);
+ localStorage.setItem('add_custom_patterns', (add_custom_patterns == true ? 1 : 0));
+ localStorage.setItem('named_captures_only', (named_captures_only == true ? 1 : 0));
+ localStorage.setItem('keep_empty_captures', (keep_empty_captures == true ? 1 : 0));
+ localStorage.setItem('singles', (singles == true ? 1 : 0));
+ localStorage.setItem('autocomplete', (autocomplete == true ? 1 : 0));
+ };
+
+ // function to execute AJAX matching
var match = function() {
- var custom_patterns = $('#custom_patterns').val();
+ var custom_patterns = $('#custom_patterns').val();
var input = $('#input').val();
var pattern = $('#tags').val();
+ var add_custom_patterns = $('#add_custom_patterns').is(':checked');
var named_captures_only = $('#named_captures_only').is(':checked');
var keep_empty_captures = $('#keep_empty_captures').is(':checked');
var singles = $('#singles').is(':checked');
-
+ var autocomplete = $('#autocomplete').is(':checked');
+
+ // Save the user's settings to localstorage for next time
+ saveLocalstorage(custom_patterns, input, pattern, add_custom_patterns, named_captures_only, keep_empty_captures, singles, autocomplete);
+
+ // Display a loading indicator
+ $('#grok').parent().prepend("");
+
+ // Get the results from Grok
$.post('/grok',
{
- "custom_patterns":custom_patterns,
+ "custom_patterns":custom_patterns,
"input":input,
"pattern":pattern,
"named_captures_only":named_captures_only,
"keep_empty_captures":keep_empty_captures,
"singles":singles
}, function(data){
- $('#grok').html(data);
- });
+ // Display the results to the user
+ $('#grok').html(data);
+
+ // Remove the loading indicator after a short time
+ setTimeout(function(){$('#grokSpinner').remove();}, 500);
+ }
+ );
};
+
+ // load settings from localstorage
+ loadLocalstorage();
+
+ // go ahead and match just in case we have something already
+ match();
+
+ // call match() if pattern, input, or custom patterns change
var oldPat = $("#tags").val();
var oldIn = $("#input").val();
+ var oldCust = $("#custom_patterns").val();
setInterval(function (){
pat = $("#tags").val();
inp = $("#input").val();
- if(inp == oldIn && pat == oldPat){
+ cust = $("#custom_patterns").val();
+ if(inp == oldIn && pat == oldPat && cust == oldCust){
return;
} else {
oldPat = pat;
oldIn = inp;
+ oldCust = cust;
match();
}
}, 1000);
- $("#add_custom_patterns").click(function(){
- $( "#custom_patterns_container" ).toggle(function() {
- $( "#custom_patterns" ).val("")
- })
- })
+
+ // also match if various buttons are clicked
$("#named_captures_only").click(function(){
- match();
+ match();
})
$("#keep_empty_captures").click(function(){
- match();
+ match();
})
$("#singles").click(function(){
match();
})
+ $("#grok-form").submit(function(){
+ match();
+ return false;
+ });
+
+ // show/hide custom patterns container, and remove patterns
+ $("#add_custom_patterns").click(function(){
+ $( "#custom_patterns_container" ).toggle(function() {
+ $( "#custom_patterns" ).val("")
+ })
+ })
+
+
+ // autocomplete functionality
$("#autocomplete").click(function(){
var autocomplete = $('#autocomplete').is(':checked');
$( "#tags" ).autocomplete({ disabled: !autocomplete });
});
- $("#grok-form").submit(match);
var availableTags = #{@tags};
function split( val ) {
- return val.split( /}\s*/ );
+ return val.split( /}\s*/ );
}
function extractLast( term ) {
- return split( term ).pop();
+ return split( term ).pop();
}
$( "#tags" )
- // don't navigate away from the field on tab when selecting an item
- .bind( "keydown", function( event ) {
- if ( event.keyCode === $.ui.keyCode.TAB &&
- $( this ).data( "autocomplete" ).menu.active ) {
- event.preventDefault();
- }
- })
- .autocomplete({
- minLength: 3,
- disabled: true,
- source: function( request, response ) {
- $.each($( "#custom_patterns" ).val().split('\n'), function(){
+ // don't navigate away from the field on tab when selecting an item
+ .bind( "keydown", function( event ) {
+ if ( event.keyCode === $.ui.keyCode.TAB &&
+ $( this ).data( "autocomplete" ).menu.active ) {
+ event.preventDefault();
+ }
+ })
+ .autocomplete({
+ minLength: 3,
+ disabled: true,
+ source: function( request, response ) {
+ $.each($( "#custom_patterns" ).val().split('\n'), function(){
var line_splitted = this.replace(/^\s*/, "").split(/\s+/)
var name = line_splitted[0]
if ( $.inArray(name, availableTags) == -1 ) {
@@ -118,23 +185,23 @@
}
});
- // delegate back to autocomplete, but extract the last term
- response( $.ui.autocomplete.filter(
- availableTags, extractLast( request.term ) ) );
- },
- focus: function() {
- // prevent value inserted on focus
- return false;
- },
- select: function( event, ui ) {
- var terms = split( this.value );
- // remove the current input
- terms.pop();
- // add the selected item
- terms.push( ui.item.value );
- // add placeholder to get the comma-and-space at the end
- terms.push( "" );
- this.value = terms.join( "}" );
- return false;
- }
- })
+ // delegate back to autocomplete, but extract the last term
+ response( $.ui.autocomplete.filter(
+ availableTags, extractLast( request.term ) ) );
+ },
+ focus: function() {
+ // prevent value inserted on focus
+ return false;
+ },
+ select: function( event, ui ) {
+ var terms = split( this.value );
+ // remove the current input
+ terms.pop();
+ // add the selected item
+ terms.push( ui.item.value );
+ // add placeholder to get the comma-and-space at the end
+ terms.push( "" );
+ this.value = terms.join( "}" );
+ return false;
+ }
+ })
diff --git a/views/layout.haml b/views/layout.haml
index 5c735c2..53e3807 100644
--- a/views/layout.haml
+++ b/views/layout.haml
@@ -15,7 +15,7 @@
%link{ :href => "//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap.min.css", :rel => "stylesheet" }
%link{ :href => "//ajax.googleapis.com/ajax/libs/jqueryui/1.9.0/themes/ui-lightness/jquery-ui.css", :rel => "stylesheet" }
%link{ :href => "sticky.css", :rel => "stylesheet"}
- / Le fav and touch icons
+ / Le fav and touch icons
%link{ rel: "apple-touch-icon", href: "/bootstrap/images/apple-touch-icon.png"}
%link{ rel: "apple-touch-icon", sizes: "72x72", href: "/bootstrap/images/apple-touch-icon-72x72.png"}
%link{ rel: "apple-touch-icon", sizes: "114x114", href: "/bootstrap/images/apple-touch-icon-114x114.png"}
diff --git a/views/navbar.haml b/views/navbar.haml
index 44e8307..982dc0d 100644
--- a/views/navbar.haml
+++ b/views/navbar.haml
@@ -11,7 +11,7 @@
%li{:class => ('active' if request.path_info == '/')}
%a{:href => '/'}Debugger
%li{:class => ('active' if request.path_info == '/discover')}
- %a{:href => '/discover?#'} Discover
+ %a{:href => '/discover?#', :target => '_blank'} Discover
%li{:class => ('active' if request.path_info == '/patterns')}
- %a{:href => '/patterns'} Patterns
+ %a{:href => '/patterns', :target => '_blank'} Patterns
%p.navbar-text.pull-right