5

I have a simple input:

<input type="date" class="self-select" value="1980-05-04">
<input type="text" class="self-select" value="my birthday">

And I have a listener for all such inputs:

$(document).on('focus', '.self-select', function(){
    $(this).select();
});

The idea is that when user clicks to the input field, its' contents are selected, so he needs just ctrl+c to copy.

But this doesnt work with type="date" in Chrome. There is no selection and basically no way to copy date value from an input field.

Here is the fiddle: https://fiddle.jshell.net/Dmatafonov/s8r9dt6j/

j08691
  • 204,283
  • 31
  • 260
  • 272
Denis Matafonov
  • 2,684
  • 23
  • 30
  • Look at this: http://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript – OscarAkaElvis Dec 16 '16 at 17:06
  • I dont want programmatically copy to clipboard on focusin. Hate this - may be I have something valuebale in clipboard and was not expecting to loose it? I want to copy value after selecting what I want to copy only. Manually. But there is no way to select the value. – Denis Matafonov Dec 16 '16 at 17:16
  • 1
    I can't say for sure, but I'd imagine you need a custom calendar input to achieve what you intend. An alternative might be to capture the CTRL-C event and then use the link provided by @OscarAkaElvis to copy the value of the input instead of what is actually selected graphically. – Xweque Dec 16 '16 at 17:37
  • HTML5 `` isn't really as finalised as it ought to be by now. See this Jan 2016 comment by Ian Devlin: http://html5doctor.com/the-woes-of-date-input/ – Rounin Dec 16 '16 at 18:37

2 Answers2

1

I managed to write some kind of a "hacky" walk around...

The trick is to copy to clipboard (using this other great SO answer) while the date input type is temporarely setted to "text" on CTRL+C keydown...

It's not perfect since only a segment of the date is selected on focus...
And some users will scratch their head a little until they notice that the whole date is copied anyway.
I have no solution for this.

enter image description here

What's important is that copying to clipboard is works.
Try the snippet!

// Your on focus -> select event handler
$(document).on('focus', '.self-select', function(){
    $(this).select();
});



// An on keydown event handler to copy to clipboard when [ctrl]+[C] is pressed
// Exclusively for the "date" inputs.
$(document).on('keydown', 'input[type="date"]', function(e){

    if( e.which == 67 && e.ctrlKey ){
        var copiedDate = $(this).val();
        //console.log( copiedDate );

        // First, get the value and fix the date format from YYYY-MM-DD to MM/DD/YYYY

        var tempDate = copiedDate.split("-");
        var year = tempDate.shift();
        //console.log( year );
        tempDate.push(year);
        var fixedDate = tempDate.join("/");
        console.log( fixedDate );

        // Then temporarly change the input type from "date" to "text"

        $(this).attr("type","text").val(fixedDate);


        // Use the copy to clipboard function
        $(this).select();
        copyToClipboard($(this));

        // Set the input type back to "date" a small delay later
        var that=$(this);
        setTimeout(function(){
            that.attr("type","date").val(copiedDate);  // And restore original value
        },20)
    }
});

// ---------------------------------
// A nice JavaScript "copy to clipboard" function found here : https://stackoverflow.com/a/22581382/2159528
// ---------------------------------

function copyToClipboard(elem) {
    // create hidden text element, if it doesn't already exist
    var targetId = "_hiddenCopyText_";
    var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
    var origSelectionStart, origSelectionEnd;
    if (isInput) {
        // can just use the original source element for the selection and copy
        target = elem;
        origSelectionStart = elem.selectionStart;
        origSelectionEnd = elem.selectionEnd;
    } else {
        // must use a temporary form element for the selection and copy
        target = document.getElementById(targetId);
        if (!target) {
            var target = document.createElement("textarea");
            target.style.position = "absolute";
            target.style.left = "-9999px";
            target.style.top = "0";
            target.id = targetId;
            document.body.appendChild(target);
        }
        target.textContent = elem.textContent;
    }
    // select the content
    var currentFocus = document.activeElement;
    //target.focus();
    target.setSelectionRange(0, target.value.length);

    // copy the selection
    var succeed;
    try {
        succeed = document.execCommand("copy");
    } catch(e) {
        succeed = false;
    }
    // restore original focus
    if (currentFocus && typeof currentFocus.focus === "function") {
        currentFocus.focus();
    }

    if (isInput) {
        // restore prior selection
        elem.setSelectionRange(origSelectionStart, origSelectionEnd);
    } else {
        // clear temporary content
        target.textContent = "";
    }
    return succeed;
}
/* Textarea sizing for this snippet */
#pasteIt{
    width:316px;
    height:150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="date" class="self-select" value="1980-05-04">
<input type="text" class="self-select" value="my birthday">
<br>
<br>
<textarea id="pasteIt" placeholder="Paste here to test your clipboard."></textarea>
Community
  • 1
  • 1
Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
1

I ran into this same issue but also needed to be able to paste to another date field. I did something similar to the above but made it obvious to the user that the full date is being copied.

My use case also included the need to copy from and paste to datetime-local type fields.

https://jsfiddle.net/h444uL45/23/

var control_pressed = false;

function changeInputType(oldObject, oType) {
  var newObject = document.createElement("input");
  newObject.type = oType;
  if(oldObject.size) {newObject.size = oldObject.size;}
  if(oldObject.value) {newObject.value = oldObject.value;}
  if(oldObject.name) {newObject.name = oldObject.name;}
  if(oldObject.id) {newObject.id = oldObject.id;}
  if(oldObject.className) {newObject.className = oldObject.className;}
  oldObject.parentNode.replaceChild(newObject,oldObject);
  newObject.select();
  return newObject;
}

function swapToText(date_type) {
    $('input[type="'+date_type+'"]').on("keydown", function(event) {
    if ((event.keyCode == 17) && (control_pressed != true)) {
      $(this).addClass("revert_date_to_text");
      changeInputType(this, "text");
      swapToDate(date_type);
      control_pressed = true;
    }
  })
}

function swapToDate(date_type) {
  $(".revert_date_to_text").on("keyup", function(event) {
    if ((event.keyCode == 17) && (control_pressed != false)) {
      $(this).removeClass("revert_date_to_text");
      if (date_type == 'datetime-local') {
        $(this).val($.format.date($(this).val().replace(/\//g,"-").replace("T"," ")+':00.000', "yyyy-MM-ddTHH:mm"));
      } else {
        $(this).val($.format.date($(this).val().replace(/\//g,"-"), "yyyy-MM-dd"));
      }
      changeInputType(this, date_type);
      swapToText(date_type);
      control_pressed = false;
    }
  })
}

$(function() {
  $.getScript('https://cdnjs.cloudflare.com/ajax/libs/jquery-dateFormat/1.0/jquery.dateFormat.min.js');
  swapToText('date');
  swapToText('datetime-local');
});
  • Thanks for taking the time to answer this question. Can you simplify the code in order to make it easier to grasp. You already provided a JsFiddle with a working example. Your answer doesn't need the entire code again, maybe just the key elements of the solution. – Camilo Sanchez Jan 06 '18 at 05:19