Статьи

31 день Windows 8 для HTML5 | День № 17 Буфер обмена

 

Эта статья посвящена Дню № 17 из 31-й серии Windows 8 . Каждая из статей этой серии будет опубликована XAMLCalloutкак для HTML5 / JS, так и для XAML / C # . Вы можете найти дополнительные ресурсы, загрузки и исходный код на нашем сайте .

Сегодня мы сосредоточимся исключительно на буфере обмена Windows 8. Более конкретно, мы рассмотрим, как мы можем сохранять и извлекать данные из этого общесистемного и интенсивно используемого механизма. Как правило, существует четыре типа данных, которые пользователь собирается скопировать и вставить:

  • Текст
  • HTML
  • Изображений
  • файлы

Они называются стандартными форматами буфера обмена . В этой статье мы напишем некоторый код, который показывает не только, как копировать и вставлять эти значения, но также и как определять, какой тип данных в данный момент содержит буфер обмена. Существуют 4 другие категории форматов буфера обмена :

Мы оставим их на другой день, но приготовьтесь к копированию!

Сохранение данных в буфер обмена

Как мы кратко увидели во вчерашней статье о контекстных меню , мы очень быстро взглянули на сохранение некоторого текста в буфер обмена. На этот раз мы рассмотрим это более подробно, а также включим сохранение изображений и файлов в буфер обмена. Важно отметить, что некоторые элементы управления, такие как абзац, который мы сделали вчера выбираемым, могут копироваться по умолчанию. Элемент ввода типа = «текст» можно читать из буфера обмена. Задача сегодняшнего дня — научиться взаимодействовать с буфером обмена вне сценариев по умолчанию.

Для начала поговорим об объекте DataPackage . DataPackage является то , что мы будем использовать для транспортировки наших данных. Мы создадим DataPackage, когда будем сохранять данные в буфер обмена, и мы будем использовать объект Clipboard для получения содержимого (фактически вызывая метод getContent () ) для извлечения данных при их вставке.

В моем примере проекта (который вы можете загрузить с GitHub ) вы увидите, что я создал кнопку с обработчиком событий для каждого типа данных. Остальную часть этого раздела мы рассмотрим, как мы храним эти различные типы данных в буфере обмена .

Важно отметить, что буфер обмена фактически разделен на несколько разделов, по одному для каждого типа данных. Вы можете сохранить данные в одном или нескольких из этих разделов, и цель для вставки определит, какой тип данных будет отображаться при вставке. Это может звучать очень похоже на то, как работает Договор об обмене акциями , и по большей части это так.

Также вероятно, что вы сталкивались с этим в прошлом: вы копируете контент из одного приложения и пытаетесь вставить его в другое, только чтобы он вставил что-то еще. Это прямой артефакт «разделов» буфера обмена. Давайте посмотрим, как сохранить каждый тип данных:

Текст

Конечно, самый простой пример, текст может быть сохранен в буфер обмена всего за несколько строк кода. Сначала давайте просто возьмем выделенный текст:

var selectedText = window.getSelection();

Конечно, текст, который вы решите захватить, зависит от вас. Теперь, когда у нас есть какой-то текст, нам нужно создать наш DataPackage и установить текст на нем.

var _clipboard = Windows.ApplicationModel.DataTransfer.Clipboard,
    _dataTransfer = Windows.ApplicationModel.DataTransfer;

var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setText(selectedText);

_clipboard.setContent(dataPackage);

Вы увидите форму шаблона по мере продвижения по другим примерам, но это примерно так же просто, как они приходят. Мы создаем новый объект DataPackage , вызываем метод setText () с текстом, который мы хотим сохранить, а затем устанавливаем содержимое буфера обмена в этот DataPackage .

HTML

HTML, хотя и похож на текст, имеет свои особенности и форматирование, и поэтому при добавлении его в DataPackage требует немного другой обработки . В этом примере я просто хватаю innerHtml элемента на нашей странице default.html и использую его в качестве содержимого DataPackage . Давайте это сначала пройти на вещи.

var htmlContent = document.querySelector("#content").innerHTML;
var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setHtmlFormat(htmlContent);

_clipboard.setContent(dataPackage);

Это очень похоже на то, что мы делали ранее. Теперь, если мы запустим это и попробуем вставить что-то вроде Notepad ++ или Visual Studio, вы на самом деле ничего не увидите. Как я кратко упомянул ранее, HTML требует немного отличающегося форматирования. Давайте изменим.

var htmlContent = document.querySelector("#content").innerHTML;
var htmlContentFormated =
    _dataTransfer.HtmlFormatHelper.createHtmlFormat(htmlContent);

var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setHtmlFormat(htmlContentFormated);

_clipboard.setContent(dataPackage);

Теперь этот помощник по формату возьмёт наш html и создаст вокруг него какой-то особый соус, превратив его в нечто вроде этого:

Version:1.0
StartHTML:00000097
EndHTML:00000806
StartFragment:00000153
EndFragment:00000773
<!DOCTYPE><HTML><HEAD></HEAD><BODY><!--StartFragment -->
        <h1>Day #17 - The Clipboard</h1>

        <br>
        <div>
            <button id="btnCopyText">copy text</button>
            <button id="btnCopyHtml">copy html</button>
            <button id="btnCopyImage">copy image</button>
            <button id="btnCopyFile">copy file</button>
            <br>
            <p class="selectable" id="myText">Bacon ipsum dolor sit amet pig jowl filet mignon sirloin ribeye tenderloin. Sausage cow shank jerky pancetta pig biltong corned beef short loin.</p>
            <input id="inputBox">
            <img id="myImage" src="images/smalllogo.png">
        </div>

    <!--EndFragment --></BODY></HTML>

Интересный. Если мы снова запустим этот код, мы на самом деле сможем скопировать и вставить в файл на основе HTML что-то вроде Visual Studio, но если я вернусь и попробую то же самое в Notepad ++, я ничего не получу. Windows достаточно умен, чтобы позволить вам вставлять только те типы контента, которые применимы к месту назначения. Чтобы исправить это, нам нужно несколько типов, я думаю. Все, что нам нужно сделать, это просто вызвать значение SetText () этого DataPackage с исходной неформатированной строкой. Вот завершенная функция:

var _clipboard = Windows.ApplicationModel.DataTransfer.Clipboard,
    _dataTransfer = Windows.ApplicationModel.DataTransfer;

function copyHtmlToClipboard() {
    var htmlContent = document.querySelector("#content").innerHTML;
    var htmlContentFormated =
        _dataTransfer.HtmlFormatHelper.createHtmlFormat(htmlContent);

    var dataPackage = new _dataTransfer.DataPackage();
    dataPackage.setHtmlFormat(htmlContentFormated);
    dataPackage.setText(htmlContent);

    _clipboard.setContent(dataPackage);
}

Как вы можете видеть выше, мы можем установить несколько значений одновременно, и как только вы углубитесь в этот пример, вы начнете замечать, что большинство ваших любимых приложений хранят данные в нескольких форматах «на всякий случай».

Изображений

Наш следующий пример — изображения, и я хочу, чтобы это было действительно ясно. Мы не говорим о файле, который является изображением. Мы говорим, например, о копировании изображения с веб-сайта, а затем о его вставке в файл OneNote или Windows Live Writer . В моем примере я взял изображение из HTML DOM и поместил его в буфер обмена.

var imageSrc = document.getElementById("myImage").src;
var imageUri = new Windows.Foundation.Uri(imageSrc);
var streamRef = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(imageUri);

var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setBitmap(streamRef);

_clipboard.setContent(dataPackage);

Выше мы получаем источник изображения в DOM и создаем из него URI. Получив URI, мы можем создать ссылку на него и передать его в наш DataPackage, вызвав SetBitmap () . Как и во всех примерах в этой статье, мы заканчиваем наш код фактической настройкой буфера обмена с нашим пакетом данных для фактического завершения действия.

файлы

Файлы обрабатываются очень похоже на изображения, но есть одно существенное отличие: мы можем копировать несколько файлов в буфер обмена одновременно и получать файлы асинхронно. Вы делали это раньше, выделите и захватите некоторые файлы, загромождающие ваш рабочий стол, прежде чем перетаскивать их как группу в корзину. Вместо того, чтобы выбрасывать их, вы можете вырезать / скопировать их и вставить их в другое место. Файлы всегда передаются как набор файлов, даже если они есть только один. Коду!

var _clipboard = Windows.ApplicationModel.DataTransfer.Clipboard,
    _dataTransfer = Windows.ApplicationModel.DataTransfer,
    _storageFile = Windows.Storage.StorageFile;

var imageSrc = document.getElementById("myImage").src,
    imageUri = new Windows.Foundation.Uri(imageSrc);

var splashScreenSource = document.getElementById("splashScreen").src,
    splashUri = new Windows.Foundation.Uri(splashScreenSource);

var files = [],
    promises = [];

promises.push(_storageFile.getFileFromApplicationUriAsync(imageUri)
    .then(function (file) {
        files.push(file);
    }));

promises.push(_storageFile.getFileFromApplicationUriAsync(splashUri)
        .then(function (file) {
            files.push(file);
        }));

WinJS.Promise.join(promises)
    .then(function () {
        var dataPackage = new _dataTransfer.DataPackage();
        dataPackage.setStorageItems(files);
        _clipboard.setContent(dataPackage);
    });

Немного отличается от изображения, но на самом деле только из-за WinJS Promise (о котором мы расскажем в другой день). Ядро этого кода действительно то же самое, за исключением того факта, что мы собираемся создать массив файлов, называемый StorageItems, а затем добавить их в dataPackage, вызвав setStorageItems.

Так что, что касается сохранения контента в буфер обмена , это как раз об этом! Наш следующий шаг будет извлекать его из буфера обмена, когда пользователь решит вставить его.

Обнаружение содержимого буфера обмена

Когда дело доходит до «вставки», как я уже говорил, я склонен делать все это одним способом, который получает контент, определяет, какой тип данных доступен, и правильно отображает контент на основе этого определения.

Когда я писал эту статью, я надеялся, что будет какой-то удивительный обработчик событий, такой как OnPastedTo () или что-то такое, что будет распознавать, когда пользователь пытается вставить некоторый контент в приложение, чтобы мы могли предпринять действия по Это. (Я лично живу и умираю с помощью Ctrl + X, Ctrl + C и Ctrl + V). Я еще не нашел это событие, кроме сопоставления команды клавиатуры напрямую. На данный момент я создал свой собственный обработчик событий, который срабатывает при нажатии кнопки.

You’ll see, in the example below, that I call the getContent() method on the Clipboard, and then use a series of if statements to act on the content appropriately.

var dataPackage = _clipboard.getContent(),
    sdFormats = _dataTransfer.StandardDataFormats;

if (dataPackage.contains(sdFormats.text)) {
    dataPackage.getTextAsync().then(function (text) {
        document.querySelector("#pasteResults").innerText = text;
    });
}

if (dataPackage.contains(sdFormats.html)) {
}

if (dataPackage.contains(sdFormats.bitmap)) {
}

if (dataPackage.contains(sdFormats.storageItems)) {
}

Let me quickly discuss each of the if statements.  For text, which is the only one I displayed I am going to just grab the text with a promise and set it as the innerText of a label that I have on my page.  Just like when we put items on the clipboard we will now need to do the reverse. Depending on the data format we will have to do the appropriate thing for what that data type requires. If it’s a collection of files we would need to loop through that collection of files and do something with them.

In all it’s pretty simple, but I was delighted the first time that I copied content from a webpage directly into my app, and it just worked!  The same is true for images, text, and files.  I highly recommend grabbing the source of this project and playing with it.  It will really help you to understand exactly how the clipboard is being used by your other applications.

Summary

Today, we took a deep look at the Clipboard, and how we can save and retrieve data as needed.  It supports several different file types, and I think you’ll be surprised just how redundant most of your favorite applications are when they save data to the Clipboard.

To download the entire code solution for the project discussed in this article, click the icon below:

downloadHTML

Tomorrow, we’re going to add another useful tool to our Windows 8 development tool belt: the FilePicker.  We’ll look at retrieving files from the user’s device, and even filtering them so that we only get our preferred file types.  See you then!

downloadTheTools