Saturday, May 24, 2014

Expanding Search Bar Using Only CSS

So I needed a search bar, but I wanted something specific, I wanted something like this:


Which I got from here: http://tympanus.net/codrops/2013/06/26/expanding-search-bar-deconstructed/ - great site by the way!

It really looks and works great, but I just felt that it was way too much for something as simple as a search bar that expands.

At first I thought I could just rework the code I found on Tympanus, but eventually I just re-did it all. This is really not going to be a long post, I'm just going to show you the code.

This is all the HTML you'll need, notice that there's no hint of JavaScript anywhere:

<html>
 <head>
  <title>Expanding Search Bar CSS Only</title>
  <link href="css/style.css" rel="Stylesheet"></link>
 </head>
<body>

 <h1>Expanding Search Bar CSS Only</h1>

<div id="search-bar">
  <form id="search-form">
   <input autocomplete="off" class="search-field" id="search-text" name="search" placeholder="Search…" type="text" />
   <input style="display: none;" type="submit" value="" />
  </form>
</div>

</body>
</html>


And here's the CSS:
body, html {

    background: #285e8e;
    color: #252525;
    font-family: Helvetica, Arial, sans-serif;
    font-weight: bold;
    font-size: 18px;

}

h1 {
    color: #fff;
    margin-left: 20px;
}


input::-webkit-input-placeholder { color:transparent; }
input::-moz-placeholder { color:transparent; }
input:-ms-input-placeholder { color:transparent; }
input::placeholder { color:transparent; }

input:focus::-webkit-input-placeholder { color: #ccc; }
input:focus:-moz-placeholder { color: #ccc; }
input:focus::-moz-placeholder { color: #ccc; }
input:focus:placeholder { color:#ccc; }

input:hover::-webkit-input-placeholder { color: #ccc; }
input:hover:-moz-placeholder { color: #ccc; }
input:hover::-moz-placeholder { color: #ccc; }
input:hover:placeholder { color:#ccc; }

#search-button-1 {
    position: absolute;
    float: right;
    right: 0px;
    display: block;
    width: 52px;
    height: 53px;
    background-color: #eb9316;
}

/** Search Fields **/
.search-field {

    float: right;
    display: block;
    width: 52px;
    padding: 10px 10px;
    background-color: #fff;
    background-image: url('../images/search-icon-box-blue.png');
    background-repeat: no-repeat;
    background-position:right;
    font-size: 22px;
    border: 0px solid #fff;
    color: rgba(255, 255, 255, 0);

    /* CSS3 Box Sizing */
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    -ms-box-sizing: border-box;
    box-sizing: border-box;

    /* CSS3 Rounded Corners */
    border-radius: 2px;

    /* CSS3 Transition (Expanding Effect) */
    -webkit-transition: all 0.4s ease;
    -moz-transition: all 0.4s ease;
    -o-transition: all 0.4s ease;
    -ms-transition: all 0.4s ease;
    transition: all 0.4s ease;

    -webkit-backface-visibility: hidden;
   
}

/** Search Field 1 Focus (Full Width) **/

.search-field:focus, .search-field:hover {

    outline: none;
    min-width: 200px;
    max-width: 500px;
    width: 40%;
    color: #777;

    /* CSS3 Outer Shadow */
    -webkit-box-shadow: 0 0 0 2px #999;
    -moz-box-shadow: 0 0 0 2px #999;
    box-shadow: 0 0 2px #999;

}

/** Don't want the reset auto-button to show up over the button image **/
.search-field::-ms-clear {
  width : 0;
  height: 0;
}

/** Make text visible again on focus or hover **/
#search-text:focus, #search-text:hover {
    color: #777;
}

#search-bar {
    margin-right: 40%;
}
This is what it ended up looking like:





There's a couple of things that are happening in the CSS. The important things to watch out for is that the placeholder text as well as any text you typed in, is set to transparent when the input is not expanded, this is so that the text does not show up over the search icon. The text is made visible on focus or hover.


Pretty cool... There's lots of little things that can be added, but this is a good basis for me to work from.

Here's a CodePen.io link if you want to play around with the code a bit and see how it works. This version has a snippet of plain JavaScript to launch a form submit when the input box is clicked on when there's text present: http://codepen.io/anon/pen/tEBnw



Hope it helps someone!



Monday, July 8, 2013

Better JavaFX Table Example With Integers Decimals & Cell Formatting

The default JavaFX tableview example does not go very far with regards to showing you how to format cells that contain Integers (you typically want them to align right) or Decimal values (aligned right and formatted properly).

I'm posting this here as a reminder to myself, as well as to anyone that might have come across the same issue. This is just a code posting, explanations on how to use JavaFX and the rest of the code can be found in the JavaFX sample code provided by Oracle.

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.beans.property.StringProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.Callback;


public class TableSample extends Application {

    private void init(Stage primaryStage) {
        Group root = new Group();
        primaryStage.setScene(new Scene(root));
       
       
       
        final ObservableList<Person> data = FXCollections.observableArrayList();

        data.add(new Person("Jacobz", "Smithy", "jacobz.smith@example.com", 78, 19.99));
        data.add(new Person("Jacob", "Smith", "jacob.smith@example.com", 23, 116.0));
        data.add(new Person("Isabella", "Johnson", "isabella.johnson@example.com", 101, 20.1));
        data.add(new Person("Ethan", "Williams", "ethan.williams@example.com", 43, 18.0));
        data.add(new Person("Emma", "Jones", "emma.jones@example.com", 44, 23.88));
        data.add(new Person("Michael", "Brown", "michael.brown@example.com", 56, 19.5));


        TableColumn firstNameCol = new TableColumn();
        firstNameCol.setText("First");
        firstNameCol.setCellValueFactory(new PropertyValueFactory("firstName"));

        TableColumn lastNameCol = new TableColumn();
        lastNameCol.setText("Last");
        lastNameCol.setCellValueFactory(new PropertyValueFactory("lastName"));

        TableColumn emailCol = new TableColumn();
        emailCol.setText("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(new PropertyValueFactory("email"));

        TableColumn ageCol = new TableColumn();
        ageCol.setText("Age");
        ageCol.setMinWidth(100);
        ageCol.setCellValueFactory(new PropertyValueFactory("age"));

        TableColumn pricePaidCol = new TableColumn();
        pricePaidCol.setText("PricePaid");
        pricePaidCol.setMinWidth(100);
        pricePaidCol.setCellValueFactory(new PropertyValueFactory("pricePaid"));

//Formatting decimal columns
        pricePaidCol.setCellFactory(new Callback<TableColumn, TableCell>() {
            public TableCell call(TableColumn p) {
                TableCell cell = new TableCell<Person, Double>() {
                    @Override
                    public void updateItem(Double item, boolean empty) {
                        super.updateItem(item, empty);
                        setText(empty ? null : getString());
                        setGraphic(null);
                    }

                    private String getString() {
                        String ret = "";
                        if (getItem() != null) {
                            String gi = getItem().toString();
                            NumberFormat df = DecimalFormat.getInstance();
                            df.setMinimumFractionDigits(2);
                            df.setRoundingMode(RoundingMode.DOWN);

                            ret = df.format(Double.parseDouble(gi));
                        } else {
                            ret = "0.00";
                        }
                        return ret;
                    }
                };

                cell.setStyle("-fx-alignment: top-right;");
                return cell;
            }
        });
//Formatting decimal columns end
       
       
//Formatting integer columns
        ageCol.setCellFactory(new Callback<TableColumn, TableCell>() {
            public TableCell call(TableColumn p) {
                TableCell cell = new TableCell<Person, Integer>() {
                    @Override
                    public void updateItem(Integer item, boolean empty) {
                        super.updateItem(item, empty);
                        setText(empty ? null : getString());
                        setGraphic(null);
                    }

                    private String getString() {
                        String ret = "";
                        if (getItem() != null) {
                            ret = getItem().toString();
                        } else {
                            ret = "0";
                        }
                        return ret;
                    }
                };

                cell.setStyle("-fx-alignment: top-right;");
                return cell;
            }
        });
//Formatting integer columns end       
       
       

        TableView tableView = new TableView();
        tableView.setItems(data);
        tableView.getColumns().addAll(firstNameCol, lastNameCol, emailCol, ageCol, pricePaidCol);
        root.getChildren().add(tableView);
    }

    public static class Person {

        private StringProperty firstName;
        private StringProperty lastName;
        private StringProperty email;
        private IntegerProperty age;
        private DoubleProperty pricePaid;

        private Person(String fName, String lName, String email, int age, Double pPaid) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
            this.age = new SimpleIntegerProperty(age);
            this.pricePaid = new SimpleDoubleProperty(pPaid);
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

        public StringProperty lastNameProperty() {
            return lastName;
        }

        public StringProperty emailProperty() {
            return email;
        }

        public IntegerProperty ageProperty() {
            return age;
        }

        public DoubleProperty pricePaidProperty() {
            return pricePaid;
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        init(primaryStage);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Saturday, June 1, 2013

Quick CRUD Application on Netbeans 7.3

I often find the need for a quick CRUD application to Create, Read, Update & Write to a local or remote database, and previous versions of Netbeans made this very easy to do with the Swing Desktop Database Application feature.

This should be easy to follow for anyone, even if you've never even worked with Netbeans. The only thing you might need to take a look at first, is connecting to a database.

Since the JSR-296 (Swing Application Framework) has been deprecated, you might think that it's no longer possible to quickly throw together a CRUD app, but you'd be wrong :-)

If you want to follow along, fire up Netbeans 7.3 and follow along, this will be a mostly visual how-to. I'm running on Ubuntu, but you should get very similar visuals with a Mac or PC.

Start up a new project - as shown, go for Java->Java Application



Okay, so now add a new form, right-click on your project name, you should see something like this. You will see that once you've done this once, the 'Master/Detail Sample Form' should become one of your top selections when you right-click and then select 'New'.



And look at that! We have a form that allows you to select a database connection, table & fields to use. Not bad at all!


I've just selected the local Derby database, but as long as you know the connection details for you database, you could connect to any other database you like. I'm not going to go into details here, there's lots of information on that if you browse the interwebs a bit. In particular, connecting to a MySQL table is just as easy as connecting to this sample Derby database.


You will see that in the first selection, it shows the 'Customer' database, and this is the one that is used in a lot of demos. There is a particular problem with this though, the fields are very straight-forward, so I will be using the 'Purchase_Order' database, since it has a date field.


If you click next, you will be able to select fields to use and move them up & down.


Click 'Next' and you will get a form with the master-detail components you would expect.


I've just click-dragged it to enlarge the form. 


In the next step we'll do something you might find a bit odd, but it's the easiest in this case. Just go ahead and delete the 'CRUDDemo' form. If you try to run the project now, you will get this notification, just click 'OK' and it will become the new main class.


Once you've done that, you should be able to launch the application. Look at that! A fully functional CRUD application in no time & no coding at all.


Go ahead and click on one of the top rows & you should see the detail part filling up. There is one problem though, take a look at the 'Sales Date' and 'Shipping Date' fields, they're empty. That's the little secret that the other more simplistic demos do not show you how to resolve.


If you take a look at the output window at the bottom, you will see the error that's being thrown - 'Cannot cast java.util.Date to java.lang.String'.


So let's solve this problem, first select the two date fields as shown below and make them smaller.


Find the 'FormattedField' component and drop them next to the date fields.


It should look something like this now.


Take note of the variable name by right-clicking on the original 'Sales Date' item and clicking on 'Change Variable Name'. We're not going to change the name, but you can copy the name to use it in the next step.


Right-click on the 'Formatted Field' and select 'Bind->Value', then pick the 'Binding Source' and 'Binding Expression' as below. Once you've done that, you can delete the original 'Sales Date' field.


Now rename the new Formatted Field to 'salesDateField'.


Do the same for the other date field & hook it up to the 'Shipping Date'. Once you've done that, you should no longer get the error and the date fields should show properly.



You might notice that our new fields do not behave quite the same as the original ones. The original fields are disabled, until you select a row. To make the new fields behave in the same way, click on one of the original fields and copy the text as shown below.



Now just click on one of the new fields & just paste it in.




So that's it! You now have a truly fully functional CRUD application with no real coding required. There is one thing that's still bugging me, I don't like the Nimbus look that much. Let's change that, it's pretty easy to do. Locate the piece of code as shown below.


Type in the bit of code as shown below. Take care where you enter the code by looking at the highlighted starting and ending curly brackets.


Add the javax.swing.UIManager.


Add a reference to the setLookAndFeel in the main section.


Launch the application again & now you should have the same look as your OS. In my case that's Ubuntu & now everything works exactly as expected.


There's still some functionality we can add easily, that's to make it possible to sort any of the fields. Look at the three lines below and add them to your NewMasterDetailForm.


Right-click on the top table grid and then check the box that says 'autoCreateRowSorter' - and that's it!




Let's take it one step further, by adding an icon for the application. Type up the line below.



We'll change it in the next step or two though, I've just copied and pasted the line from code that I had already. There's a really easy way to cheat and get the image we want imported into our project. Just drop a label anywhere on an open space, we'll delete it again later, this is just to get things going.


Right-click on the label & click on the ellipsis button of the 'icon' element. Then click on 'Import to Project' and select an image that's about 36x36 pixels.




 Change the reference to the icon in your code as shown below.


In Ubuntu you don't see any app icons in the top bar, but this is what it looks like in Windows, which also shows that the app works in both Linux and Windows.


The last missing piece is a title for the form in Windows, to do that, you just add frame.setTitle("CRUDDemo");
as shown below, and you're done.



That concludes this little demo, hopefully it helps you to quickly build a CRUD application.

Here's the look-and-feel piece of code, be aware that you should still have one last closing curly bracket at the end.


    public static void main(String[] args) {
        setLookAndFeel();
        /* Create and display the form */
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.setContentPane(new NewMasterDetailForm());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setIconImage(new ImageIcon(getClass().getResource("checkout.png")).getImage());
                frame.setTitle("CRUDDemo");
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
 
    public static void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            System.out.println("Error setting native LAF: " + e);
        }
    }




Happy coding!





Monday, April 29, 2013

Change Netbeans Java Swing Applications Interface Look-and-Feel to System Native Look

For some or other reason people at Oracle/Netbeans want us to use the horrendous (IMHO) Nimbus theme.

You can change that quite easily, this is one of the first things I do.

Alter your main class (don't put an interface on it), so look like the snippet below, which also shows you how to add an icon to your application.

Put the icon.png file in the same folder as the source, this Init class will call the MainForm (or whatever) and show it with the specified icon:
public class Init {
 
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        setLookAndFeel();
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                MainForm m = new MainForm();
                m.setTitle("EncodingConverter");
                m.setIconImage(new ImageIcon(getClass().getResource("icon.png")).getImage());
                m.setVisible(true);
            }
        });
    }
    public static void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            System.out.println("Error setting native LAF: " + e);
        }
    }
}

This does not however make the icon show on Windows, so add this: Right-click Form, Properties, set 'iconImages' to 'none', click 'iconImage'->'Value from existing component', click 'Property' then '...' then 'iconImage'

Now your Java application should look pretty much like other applications that run on the same OS, and yes, I WANT it to look like the other applications. :-)


Sunday, April 28, 2013

iPad & iPhone Viewport Rotate Screw-up

If you've designed a mobile site before (or if you're about to...) you would have seen or used this before:

<meta name="viewport" content="width=device-width, initial-scale=1">
That's all fine & dandy, until someone rotates their screen and then flips it back again. This is one way to solve that little irritating issue:

You can disable scalability with javascript until gesturestart with this script:

if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) {
    var viewportmeta = document.querySelector('meta[name="viewport"]');
    if (viewportmeta) {
        viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0';
        document.body.addEventListener('gesturestart', function () {
            viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=1.6';
        }, false);
    }
}


Saturday, April 27, 2013

Prevent Pinch-zoom on a Div or Whole Body


Sometimes you just don't want people to go pinch-zoom your site into oblivion, luckily, there is a way to do that :-)

     $("body").bind('touchstart', function preventZoom(e) {
        var t2 = e.timeStamp
          , t1 = $(this).data('lastTouch') || t2
          , dt = t2 - t1
          , fingers = e.originalEvent.touches.length;
        $(this).data('lastTouch', t2);
        if (!dt || dt > 500 || fingers > 1) return; // not double-tap
        e.preventDefault(); // double tap - prevent the zoom
        // also synthesize click events we just swallowed up
        $(this).trigger('click').trigger('click');
      });

Mobile Device Detection & Touch Screen Desktops

Not too long ago, I thought that this type of script was a pretty solid way of making sure that you redirect your traffic to a mobile site:

if( ('querySelector' in document && 'localStorage' in window && 'addEventListener' in window && ('ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch) ) || navigator.userAgent.indexOf('IEMobile') > 0){

location.replace('YOUR MOBILE SITE'); }

I originally got it from here: http://roughlybrilliant.com/jquery_mobile_best_practices#9

The question I've been asking myself lately is, with touch interfaces coming to desktop screens, this type of code that detects a touch interface will no longer just apply to mobile screens.

Due to this & the fact that mobile browsing growing exponentially, the best approach I believe is to just go for Responsive Design & one of the easier ways to do that is to use something like Twitter Bootstrap - http://twitter.github.io/bootstrap/scaffolding.html#responsive


Happy Coding!