Очень удобно" - подумал я. Следующая мысль была "нифига себе JavaScript и такое умеет?". (читаем дальше)
Сегодня представилась возможность сделать textarea из которой кто-то потом будет копировать. "Непорядок" - подумал я - "для меня сделали удобно, а я не сделаю кому-то так же хорошо?".
После этой мысли взялся я реализовать эту фичу (хотя заказчик о ней не просил). 5 раз хотел все бросить и все потому, что нифига не получалось. Возникала мысль "это невозможно" и я бил себя в ухо, а потом продолжал пробовать. Если не интересны детали - переходим сразу к рабочему варианту.
Если нужна поддержка только одного браузера InternetExplorer, то тут все просто. Пишем код
if (window.clipboardData) { window.clipboardData.setData('Text', yourVariable)} }И все... Проводник ласково спросит, можно ли дать доступ скрипту к буферу и если ответ будет положительный - скопирует...
Не просто оказалось реализовать доступ к буферу для Mozilla Firefox. А все потому, что она, видите ли, секьюрная очень а мануалы, ко всему, пишутся для простых случаев. Я видел в сети, как минимум, три варианта реализации. Перечислю их все, может кому-то и пригодится.
Первый (взят тут)
<script language="javascript"> //To allow paste function to work in firefox you must: //write in url about:config //and change signed.applets.codebase_principal_support = true function init() { try{ window.clipboard = new Clipboard(); } catch (e) { alert("If you are using firefox please do the following :\n 1. Write in your url box : 'about:config'\n2. Change signed.applets.codebase_principal_support = true\n") } } // Must init the clipboard window.onload = init; // Function to return the data in clipboard function getClipboardContents() { return window.clipboard.paste(); } </script>Научил меня докапываться до настроек Firefox с помощью дырки "about:config". Скопировать текст так и не получилось.
Второй (взят тут) оказался платным, но в примере копирование удалось. Значит есть шанс!
Третий способ (описан тут) так же мне не помог.
Был еще один, но и он провалился.
Наконец я нашел одну библиотеку, которая тоже нифига не поддавалась, но через три часа экспериментов (уверенности придавал пример, который заработал под мозилкой!) мне удалось понять в чем дело.
Итак, что надо сделать:
1) Качаем отсюда последнюю версию либы и переписываем ее себе в проект. У меня это 4 файла и один тестовый, с которым я экспериментировал.
2) Дальше создаем тестовый (тот самый test.html) файлик с содержимым
<html> <head> <script src="/js/ZeroClipboard/ZeroClipboard.js" type="text/javascript"></script> <script language="JavaScript"> var clip = null; function init() { clip = new ZeroClipboard.Client(); clip.addEventListener('complete', function(client, text) { alert("Copied text to clipboard: " + text); }); clip.glue('copy_button'); clip.setText(document.getElementById('text_area').value); } </script> </head> <body onLoad="init()"> <textarea onChange="clip.setText(this.value)">Copy me!</textarea> <div class="my_clip_button" id="copy_button"><b>Copy To Clipboard...</b></div> </body> </html>3) Запускаем его у себя и проверяем, что все работает. Должна появиться формочка в которой будет текст, а снизу кнопка. При клике на кнопку выскочит alert, с сообщением из textarea, этот же текст должен содержаться и в буфере обмена.
Когда все заработало мы можем взяться за реальный код.
4) Я создал textarea и div-кнопку
<div id="informer_code"> <textarea id="informer_code_area">Some text</textarea> <div class="js_link" id="copy_to_clipboard">Копировать в буфер обмена</div> </div>5) в момент готовности документа инициализировать компоненту (jQuery код)
$(document).ready(function() { ZeroClipboard.setMoviePath( '/js/ZeroClipboard/ZeroClipboard.swf' ); // указываем где находится swf-файл. clip = new ZeroClipboard.Client(); // создаем инстанс компоненты clip.glue('copy_to_clipboard'); // подключаем кнопку clip.addEventListener('complete', function () { // обработчик сработает после копирования alert('Информер скопирован в буфер обмена...'); }); var copyToClipboard = function () { // метод копирования текста из textarea в компоненту, а при клике на кнопку и в буфер обмена. clip.setText($("#informer_code_area").val()); } $(".informer_code").hide(); // спрятали контейнер с кнопкой после $(".informer_code").css("visibility", "visible"); // делаем его видимым $("#informer_code_area").change(function() { // при изменении содержимого textarea записываем его в компоненту copyToClipboard(); }); copyToClipboard(); // записываем изначальный текст textarea в компоненту }Проблема была в том, что кнопка изначально была скрыта "display:none" и библиотечка не смогла правильно инициализировать себя. Не зная этого, пришлось немного попыхтеть, пока случайно не протестил с видимой кнопкой. Потому если компонента изначально невидима - стоит заменить способ скрытия с "display:none" на "visibility:hidden", после инициализации компоненты поменять его на "visibility:visible" и спрятать как полагается ("display:none"). Либо инициализировать компоненту по принципу Singleton в момент первого доступа, когда компонента уже видна.
Хочу отметить еще один важный момент, с которым столкнулся в ходе отладки. Если выше по дереву DOM на ветках происходят какие-то "спрятали/показали", в результате чего offsetLeft и offsetTop исходного дива-кнопки меняется, то это ведет к рассинхронизации.
Компонента накрывает исходный див-кнопку сверху swf-кой которая и производит копирование в буфер обмена (ей-то можно). Эта swf-ка привязывается к кнопке в момент создания с помощью стилей:
element.style { height:17px; left:610px; position:absolute; top:596px; width:128px; z-index:99; }И больше не меняет своего положения. Если исходный див-кнопка поменял свое положение, то нам придется синхронизировать их так (jQuery код)
// то из за чего происходит смещение // отображаем панельку (исходный див-кнопка сместится ниже) var showInformerCode = function() { $("#show_informer_code").hide(); $("#hide_informer_code").show(); $("#informer_code").show(); $("#informer_width").focus(); fixCopyToClipboardDivPosition(); } // прячем панельку (исходаный див-кнопка сметится выше) var hideInformerCode = function() { $("#show_informer_code").show(); $("#hide_informer_code").hide(); $("#informer_code").hide(); fixCopyToClipboardDivPosition(); } // функция корректировки var fixCopyToClipboardDivPosition = function() { // находим див содержащий swf-ку var parentDiv = $("#ZeroClipboardMovie_1").parent(); // синхронизируем див с swf-кой и исходный див-кнопку parentDiv.css("top", $('#copy_to_clipboard')[0].offsetTop); }
Ну вот вроде как и все...
<!-- Ага! --> <!-- Если интересно как вставлять текст подобным образом - тогда идем --> <a href="http://blog.cartercole.com/2009/10/awesome-syntax-highlighting-made-easy.html">сюда</a>
Ага, флеш имеет доступ к большей функциональности чем джаваскрипт. Интереснее всё-таки на чистом js.
ОтветитьУдалитьИнтересно! Ждем на НеформатеЦ ;)
ОтветитьУдалитьПривет, а вот что то непонятное.
ОтветитьУдалитьможет кто подскажет где я упустил.
код приведенный выше, да и вообще сам оригинал работает без вопросов.
но мне нужно что бы он работал на вкладках, созданных динамически.
И вот пока ставлю на статичных вкладках, все ок, а если вкладка создана
tabs("add","help/index");
то увы, ничего не могу сделать..
есть идеи что я упустил?
"пока ставлю" это я так понимаю вызываете
ОтветитьУдалитьclip = new ZeroClipboard.Client();
clip.glue('div_name');
В этот момент создается к дому подключается тег, который содержит флешку. размеры приобретает те еж что и у дива, накоторый лепится, а позиция его абсолютна. Если дива к этому времени нет или он невидимый, тогда возможны глюки.
Попробуйте создать флеш кнопку (если она еще не создана) сразу после создания динамического табчика. Если Вы так и делаете, тогда посмотрите с помощью FireBug (к примеру) струкутру Dom вашей страничке и найдите где-то в конце тег с флешкой. Если она есть, тогда предстоит ответить на вопрос "почему она не на месте". Если ее нет, тогда вопрос "почему ее нет"...
И опишите, что получилось.
Спасибо Вам за вопрос.
Привет!
ОтветитьУдалитьСпасибо за ответ.
Вопрос с вкладками фактически остался открыт.
Хотя проблему "обошел", просто подключаю JS прямо к загружаемому в вкладку файлу.
На странице есть контекстное меню, к пунктам которого и "привязана" флешка.
В принципе все работает отлично.
Но так как контекстное меню может появляется в любом месте, где "тыкнул" пользователь, и в зависимости от этого меняется и копируемый контент, то я добавил функцию которая при добавлении объекта флеш, запоминает его ID и записывает в строку.
А при определенном условии удаляет все созданные ранее объекты.
в деле посмотреть тут: http://bs-catalog.com/
код тут: http://code.google.com/p/biblequote-online/source/browse/trunk/www/js/bq_add_to_tab.js
Привет. Отличная хау-ту, спасибо! Но вот за употребление слова компонент в женском роде хочется делать очень-очень больно. Не уподобляйся 1сникам ;)
ОтветитьУдалитьПожалуйста. Если я сейчас исправлю, то следующим комментарием будет комментарий 1сницы суфражетки... Но все же согласен с тем, что написано не по русски.
ОтветитьУдалитьУ меня у одного в Chrome криво считает отступ сверху?
ОтветитьУдалитьВ Опере 11.10 не работает кнопка
ОтветитьУдалитьДа, жаль, что сразу не заработало. Как пытаетесь пофиксить?
ОтветитьУдалитьatapin,
ОтветитьУдалитьпопробуйте на функцию создания табы повесить создание нового копиклипбоарда с задержкой в несколько секунд - setTimeout.
У меня в хром всё чётко...
Доброго дня, есть такой скрипт корзины simplecart(js). При нажатии на кнопку checkout происходит отсылка данных корзины на систему оплаты PayPal, то есть данные копируются в буфер, возможно ли внести изменения в код этой кнопки чтобы скопированные данные вставлялись в текстовое поле на странице?
ОтветитьУдалитьДумаю это можно сделать. Вы пробовали?
ОтветитьУдалитьНет, я к сожалению не очень разбираюсь в Java, просто на форумах за это никто не берется ) вот я и подумала, что это невозможно
ОтветитьУдалитьНе выходит это все подключить к динамически создаваемым элементам.
ОтветитьУдалитьКому нибудь удавалось такое?
У меня у одного не получилось?
ОтветитьУдалить