Как да копирате програмно асинхронно зависимо съдържание в клипборда след щракване?

Опитвам се програмно да използвам execCommand в Chrome (версия 43), за да копирам резултата от асинхронна JSONP заявка в клипборда. Ето фрагмент от логиката:

loadContent()

function loadContent(callback) {
  $.getJSON('http://www.randomtext.me/api/lorem/p-5/10-20?&callback=myFunc',function(result){
    console.log('result=',result.text_out);
    $("#container").html(result.text_out);
    if (callback) {
      callback();
    }
  });
}

function copyAjax() {

 loadContent(copy);

}

function copy() {
  var copyDivText = $('#container').text();
  console.log('copyDivText=',copyDivText);
  executeCopy(copyDivText);
}

document.addEventListener("DOMContentLoaded", function(){
      document.getElementById("copy").onclick = copy;
    });


document.addEventListener("DOMContentLoaded", function(){
      document.getElementById("copyAjax").onclick = copyAjax;
    });


// Copy text as text
function executeCopy(text) {
    var input = document.createElement('textarea');
    document.body.appendChild(input);
    input.value = text;
    input.focus();
    input.select();
    document.execCommand('Copy');
    input.remove();
}

Знам, че стартирайки компилация 43 на Chrome, вие кодирате, като използвате execCommand с клипборда. Проблемът обаче е, че трябва да го направите в рамките на изпълнението на събитие, създадено от потребителя (в което разрешенията са повишени). Това е подобно ограничение, което има базираното на флаш решение ZeroClipboard. С изключение на получаването на отговор, че това не е възможно (за което размишлявам сега), това са другите опции, които мислех да направя като крайна мярка (предупреждение, всички те са Хейл Мери преминава):

  1. Тъй като JSONP не може да бъде синхронен, обърнете го към нещо, което използва редовно AJAX извикване и се уверете, че AJAX извикването е синхронно в контекста на изпълнение на потребителското събитие. Това противоречи на моето дълбоко вкоренено убеждение, че не трябва да правим синхронни XHR повиквания, тъй като това влошава потребителското изживяване.
  2. Когато потребителят се приближи с мишката до бутона за копиране, ние превантивно изпращаме заявката към сървъра и се надяваме, че е достатъчно бързо, преди потребителят да щракне върху бутона. Това е очевидно състояние на състезание, което може да не е част от времето и няма да работи със сигурност, когато потребителят иска да направи Ctrl/Command-C вместо да щракне върху бутона за копиране.
  3. Извършете процес в две стъпки. Едно щракване за задействане на повикването, когато съдържанието е налично, покажете съобщение, че съдържанието е налично и натиснете още едно щракване върху областта за съобщения, за да копирате в клипборда. Не изглежда като най-доброто UX взаимодействие досега. Създадох този пример с тази алтернатива. Програмното задействане на щракване не представлява събитие за потребителски проблеми .
  4. Може да има начин да създадете просто разширение за Chrome и да позволите на потребителя да зададе разрешение за това разширение да копира в клипборда. Това включва, но крайният потребител трябва да инсталира разширение и да промени настройките на локалния браузър. Не съм сигурен, че много потребители ще могат/желаят да го направят.

Вече разгледах въпроси на Stackoverflow като този, но те не адресират асинхронен сценарий. Моля, уведомете ме, ако можете да намерите някакво друго работещо решение (или промяна на съществуващото).


person Gabriel Kohen    schedule 08.06.2015    source източник
comment
Измислихте ли други идеи за това? Имам точната ситуация, при която потребител иска да копира и трябва да направя двупосочно пътуване до сървъра, за да извлека подробности от DB. Използването на вашите 3 предложения изглежда като най-доброто от 4-те злини :( ....   -  person pythonator    schedule 08.07.2016
comment
› 2. Извършете процес в две стъпки. Наскоро внедрих това. Основният UX е, че когато потребителят щракне върху бутона Get Link, вие правите ajax заявка и показвате спинер. След като заявката приключи, вие показвате въвеждане на текст заедно с малък бутон за копиране до него (като икона за въвеждане на css при стартиране). Уверете се, че текстът е избран автоматично при въвеждане. Щракването върху иконата трябва да се копира в клипборда на потребителя. Можете да промените взаимодействията, за да направите това възможно най-хубаво предвид ограниченията (напр. накарах въвеждането да избере целия текст при focusIn).   -  person les2    schedule 21.11.2016


Отговори (1)


Това е работещ подход за изчакване въз основа на вашия фрагмент:

HTML:

<div id="container">
Enter Text To Copy</br>
<textarea id="clipboard"></textarea>
</div>
<input type="button" value="Copy" id="copy"/>

JS:

var timeout = 600; // timeout based on ajax response time
var loaded = false;

function loadContent() {
  loaded = false;
  $.getJSON('http://codepen.io/gkohen/pen/QbvoQW.js',function(result){
    document.getElementById("clipboard").value = result.lorem;
    loaded = true;
  });
}

// Copy text as text
function copy() {
  clipboard = document.getElementById("clipboard");
  if (!loaded || clipboard.value.length == 0) {
    alert("Ajax timeout! TIP: Try to increase timeout value.");
    return;
  }

  clipboard.focus();
  clipboard.select();

  if (document.execCommand('Copy'))
    alert("Successfuly coppied to clipboard!");

  // set defaults
  clipboard.value = "";
  loaded = false;
}

document.addEventListener("DOMContentLoaded", function(){
  document.getElementById("copy").onmousedown = loadContent;
  document.getElementById("copy").onclick = function() {
    setTimeout(copy, timeout); // wait for ajax
  }
});

Основният проблем е спецификацията на execCommand. Има някои ограничения относно сигурността и доверен действия. Така че трябва да направите отделно копиране на извикване на събитие и извикване на ajax. Това може да се направи по мръсен начин - чрез фиксирано време за изчакване (код по-горе) или по правилен начин - чрез прекъсващ сън. Новата функция за заспиване е спомената тук и може би може да бъде модифицирана до разбиваем вариант чрез clearTimeout, но не пробвах.

person bigless    schedule 27.11.2016
comment
Може би бихте могли да направите нещо, което споменах тук: РЕШЕНО: копието на execCommand на документа не работи с AJAX - person Nishanth Matha; 13.04.2017