📜 ⬆️ ⬇️

Make beautiful input [type = file] with jQuery

Tip or why you need another plugin?


Once upon a time in the thirtieth kingdom in the far-off state when the web was not at all 2.0 to anyone and the thought of stylizing forms did not occur. Now we have a lot of pure CSS solutions that drastically change the appearance of the elements. Unfortunately, for some elements this does not work. Of particular difficulty in this regard is the input [type = file].

With this element, using CSS, we can only change the font size. We all love power. You want to completely control this unyielding file? Here we are come to the aid of a magical bunch of modern Internet - JavaScript + CSS.

Our project uses jQuery, so the first thing I did was start looking for a solution using a ready-made plug-in, but I quickly became disillusioned. The found plug-ins either did not meet the requirements of our customer, or provided additional functionality that we absolutely do not need. What follows from this? That's right - you need to write your bike plugin.

As TK


The form in our project contains a number of checkboxes and an optional file upload field, which, um, stands out a little for its standard look from the corporate style. The customer said: “I want the file download to be using the checkbox!”.
')
We scratched our heads. On the Internet, this functionality was implemented using flash or bundled with ajax file download . The first option is rejected right away - flash'em, we simply have no one to do, and we do not like it. The second option was inconvenient for several reasons:

Developers, developers, developers, develop


The replacement scheme for the standard element is as follows:

“Why is everything so difficult ?!” - you ask. Unfortunately, click-to-input [type = file] emulation does not work very well or not at all, so street magic is needed.

Now actually how it all works:
function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  1. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  2. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  3. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  4. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  5. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  6. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  7. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  8. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  9. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  10. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  11. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  12. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  13. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
  14. function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .
function replace() { $replacement .addClass(config.replacementClass + '-' + currentId) // CSS class name .insertBefore($input) // input'a .bind( 'mouseenter' , function () { toggleVisibility( true ); toggleHoverClass( true ); }) .bind( 'init' , function () { createWrapper(); // createFileName(); // }) .trigger( 'init' ); } * This source code was highlighted with Source Code Highlighter .


Let's take a closer look at creating a wrapper:

  1. function createWrapper () {
  2. var cord = getElementCoordinates ($ replacement); // it is necessary that the wrapper be exactly the same size as the placeholder
  3. var wrap = $ ( '<div />' , {
  4. css: {
  5. position: "absolute" ,
  6. visibility: "hidden" , // the wrapper is hidden by default
  7. overflow: "hidden" ,
  8. zIndex: 10,000,000, // position it "above" all other elements on the page
  9. opacity: 0, // we should not see the standard button for loading
  10. left: cord.left,
  11. top: cord.top,
  12. width: $ replacement.get (0) .offsetWidth,
  13. height: $ replacement.get (0) .offsetHeight,
  14. margin: 0,
  15. padding: 0,
  16. direction: "ltr"
  17. }
  18. })
  19. .addClass (config.wrapperClass)
  20. .bind ( 'mouseout' , function () {
  21. toggleVisibility ( false );
  22. toggleHoverClass ( false );
  23. });
  24. $ input.wrap (wrap) .css (config.inputCss);
  25. }
* This source code was highlighted with Source Code Highlighter .


In addition, in the last line we apply the following CSS styles to the standard element:

  1. inputCss: {
  2. fontSize: '600px' , // make the "Browse" button maximum large
  3. position: "absolute" ,
  4. right: 0, // align it with the right border of the wrapper
  5. margin: 0,
  6. padding: 0
  7. },
* This source code was highlighted with Source Code Highlighter .


This is necessary in order to click on our wrapper, we must fall on the button input [type = file] and call the standard dialog to load the file.

Creating a field to display the file name is very simple:

  1. function createFileName () {
  2. try {
  3. if (! jQuery.contains ( document .body, $ filename.get (0))) {
  4. throw ( "not found" );
  5. }
  6. } catch (e) {
  7. if (! $ filename.length) {
  8. throw ( "filename is empty" );
  9. }
  10. $ replacement.after ($ filename);
  11. }
  12. $ filename.addClass (config.filenameClass + '-' + currentId);
  13. }
* This source code was highlighted with Source Code Highlighter .


In case the element for displaying the name is not present on the page, then we add it immediately after our wrapper.

The basic functionality is ready, but we need to provide the ability to delete the selected file. This is another difficulty - the value of input [type = file] is read-only. We proceed to the next focus - creating new input on the fly, while copying all its characteristics:

  1. function onClear () {
  2. var el = $ input.get (0);
  3. var attrs = {};
  4. // copy all the attributes of the old input'a except for the value
  5. for ( var i = 0; i <el.attributes.length; i + = 1) {
  6. var attrib = el.attributes [i];
  7. if (attrib.specified === true && attrib.name! == 'value' ) {
  8. attrs [attrib.name] = attrib.value;
  9. }
  10. }
  11. attrs.value = "" ;
  12. // create a new input and replace it with the old one
  13. $ input = $ ( '<input />' , attrs);
  14. $ ( this ) .replaceWith ($ input);
  15. // bind events to it
  16. $ input.css (config.inputCss) .bind ( 'change' , onChange) .bind ( 'clear' , onClear) .trigger ( 'change' );
  17. toggleActiveClass ( false );
  18. }
* This source code was highlighted with Source Code Highlighter .


Help me


Using the plugin is very simple - you need to connect the last jQuery, the plugin script itself and write the following lines:
  1. <script type = "text / javascript" >
  2. $ ( function () {
  3. $ ( "# fileupload-1" ) .customInputFile ({
  4. filename: "# filename-1"
  5. });
  6. $ ( "# fileupload-2" ) .customInputFile ();
  7. $ ( '#clear' ) .bind ( 'click' , function () {
  8. $ ( "# fileupload-1, # fileupload-2" ) .trigger ( "clear" );
  9. });
  10. });
  11. </ script>
* This source code was highlighted with Source Code Highlighter .


In this example, we are replacing two standard file loading elements. The difference between the plug-in calls is only in the fact that in the first case we explicitly indicate the element in which the file name should be output. In the second case, this element will be created automatically.

The reset of values ​​is initialized by calling the “clear” event on the replaced inputs. In the parameters it is also possible to specify CSS classes for the following situations:

They are achieved using a combination of three classes:
  1. replacementClass: "customInputFile" ,
  2. replacementClassHover: "customInputFileHover" ,
  3. replacementClassActive: "customInputFileActive" ,
* This source code was highlighted with Source Code Highlighter .

Demonstration and Handouts


The results of the plug-in can be viewed on these two pictures:

work

demo

Source codes of the project are posted on bitbucket , and you can watch a live demo here.

Source: https://habr.com/ru/post/98260/


All Articles