Создание «клейких» заметок, использующих локальную память

sticky notes

От автора: Локальная память HTML5 – это как cookies на стероидах; ее невероятно легко использовать, и в то же время она очень мощная. В этом учебнике я покажу вам, как создать функциональные «sticky notes» («клейкие заметки»), которые позволят пользователям делать постоянно отображаемые записи во время просмотра вашего сайта.

Перед тем, как мы приступим к практическим шагам, я Вам рекомендую просмотреть демо-результат работы.

Также скачайте исходники себе на компьютер!

sticky notes

Шаг 1: HTML

Поскольку этот проект имеет динамическую природу, нам не потребуется что-либо кодировать в стиле обычной семантической разметки. Мы просто смоделируем веб-страницу, сложив вместе чуть-чуть содержимого:

	<!DOCTYPE html>
<html>
<head>
	<meta charset='utf-8' />
	<title>HTML 5 complete</title>
	<link rel="stylesheet" href="default.css" />
	<link rel="stylesheet" href="stickies/stickies.css" />
	<!--[if IE]>
	<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
	<![endif]-->
</head>
<body>
	<article>
		<header>
			<h1> Sample Article Title</h1>
		</header>
		<p>Lorem ipsum dolor. . . </p>
		<!-- a few lorem-ipsum paragraphs later . . . -->
		<footer>
			<p>Copyright 2010 Andrew Burgess</p>
		</footer>
	</article>

	<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
	<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"></script>
	<script src="json2.js"></script>
	<script src="stickies/stickies.js"></script>
	<script>
	</script>
</body>
</html>

Тут нужно отметить некоторые важные моменты: мы включаем два файла CSS: первый – дизайн простой страницы, названный нами default.css. Затем, у нас есть специальный файл CSS для стилей, касающихся наших «клейких заметок»; он называется stickies.css, и, как можно видеть, находится в папке «stickies». Внизу мы включаем четыре скрипта:

jQuery, из Google CDN (сети доставки контента)

JQuery UI, из Google CDN

JSON2, из Douglas Crockford

Наш собственный stickies.js, находящийся в каталоге «stickies»

Далее, у нас есть пустой тег скрипта, который мы используем чуть позже для запуска движка.

На этом с HTML все!

Шаг 2: CSS

Содержимое файла default.css невероятно простое:

	body {
		margin:0;
		padding:0;
		background:#ccc;
		font:14px/1.5 &quot;Helvetica Neue&quot;, Helvetica, Arial, san-serif;
	}
	article, footer, header { display: block; }
	article {
		width:880px;
		background:#fff;
		margin:auto;
		padding:40px;
	}
	article header {
		color:#474747;
		border-bottom:1px solid #474747
	}
	article footer {
		font-size:90%;
		color:#ccc;
	}

Вот и все; теперь нужно позаботиться о CSS из файла stickies.css… но у нас еще нет этой разметки. Так что давайте возьмемся за JavaScript, а когда закончим, посмотрим CSS для клейких заметок.

Шаг 3: JavaScript

Это основа нашего приложения JavaScript:

	var STICKIES = (function () {
		var initStickies = function () {},
			openStickies = function () {},
			createSticky = function (data) {},
			deleteSticky = function (id) {},
			saveSticky   = function () {},
			markUnsaved  = function () {};

		return {
			open   : openStickies,
			init   : initStickies
		};
	}());

Здесь у нас используются некоторые интересные методики. Первая – это самовызываемая функция: выглядит это таким образом, как будто мы назначаем функцию переменной STICKIES, но если посмотреть внимательно на конец функции, вы увидите, что запускаем мы ее сразу же. В качестве подсказки — чтобы все напоминало нам о том, что это необычная функция — мы обертываем ее целиком в круглые скобки. Таким образом, STICKIES – не функция, это возвращенное значение функции, которая в данном случае является объектом.

Это ведет нас к следующему приему: замыканию (closure). Обратите внимание, что из шести создаваемых нами функций всего две используются пользователем (в действительности для планируемого использования необходима только одна; если бы мы хотели обеспечить создание заметок в своем веб-сайте, мы могли бы показать createSticky и deleteSticky). Хотя самовызываемая функция заканчивает свое выполнение до использования этих методов, мы сможем использовать остальные заданные нами функции.

Так, давайте перейдем к их содержанию.

initStickies

Начнем с рассмотрения функции initStickies:

	var initStickies = function initStickies() {
	$("<div />", {
		text : "+",
		"class" : "add-sticky",
		click : function () { createSticky(); }
	}).prependTo(document.body);
	initStickies = null;
},

Это довольно просто. Мы используем jQuery для создания элементов, и пользуемся специальным синтаксисом версии 1.4: то есть передаем объектную константу спецификациями элемента как второго параметра функции jQuery. Вот, мы делаем кнопку создания новой заметки. Это значит, что нам нужен новый div; мы устанавливаем текст на «+» и присваиваем ему класс «add-sticky»; затем устанавливаем обработчик щелчка на вызов метода createSticky (важно вызывать createSticky из функции, а не заставлять обработчик щелчка обращаться напрямую к createSticky; это оттого, что createSticky может принимать единичный параметр, а нам не нужно, чтобы он был событийным объектом). Наконец, мы вставляем этот div в body. Закончим установкой initStickies в null; да, по существу, мы избавляемся от запускаемой функции. Таким образом убедимся, что эта функция запустится всего один раз; нам не нужно, чтобы пользователь нашего API (приложения) по невнимательности добавил к странице множество кнопок “add note” («добавить заметку»).

openStickies

Давайте перейдем к следующему методу — openStickies:

	openStickies = function openStickies() {
	initStickies && initStickies();
	for (var i = 0; i < localStorage.length; i++) {
		createSticky(JSON.parse(localStorage.getItem(localStorage.key(i))));
	}
},

Начнем с запуска initStickies … но что происходит в этом вычурном синтаксисе? Ну, вы, наверное, знакомы с оператором &&: логическим оператором «и». Обычно им пользуются, чтобы проверить множественные условия в if-предложении. Вот что в действительности он делает: вычисляет первое выражение, и если оно оказывается верным (true), продолжает вычисление второго выражения. В этом случае, если initStickies еще не был установлен на нуль, мы запустим функцию. Таким образом, избежим ошибки, которая произойдет, если попробовать запустить нулевую переменную как функцию.

Далее перебираем по порядку каждый пункт в localStorage. Вот что мы делаем в этом цикле с параметром:

localStorage.key() – отличная функция, возвращающая название ключа значения localStorage; она принимает в качестве параметра число. Прекрасный способ просмотреть по порядку (в виде цикла) все пункты в localStorage.

Как только у нас появляется ключ к хранимому пункту, мы можем передать его в localStorage.getItem() для получения его значения.

Затем передаем это значение в JSON.parse(); его мы получаем из библиотеки Crockford. Так как мы храним по нескольку значений для каждой заметки, с другого конца пользуемся JSON.stringify() для превращения объекта в строку JSON, которую храним. Вот здесь мы преобразуем ее из строки обратно в объект.

Наконец, передаем объект в createSticky(), который превращает его обратно в клейкую заметку.

createSticky

Теперь рассмотрим метод createSticky.

	createSticky = function createSticky(data) {
	data = data || { id : +new Date(), top : "40px", left : "40px", text : "Note Here" }

	return $("<div />", {
		"class" : "sticky",
		'id' : data.id
		 })
		.prepend($("<div />", { "class" : "sticky-header"} )
			.append($("<span />", {
				"class" : "status-sticky",
				click : saveSticky
			}))
			.append($("<span />", {
				"class" : "close-sticky",
				text : "trash",
				click : function () { deleteSticky($(this).parents(".sticky").attr("id")); }
			}))
		)
		.append($("<div />", {
			html : data.text,
			contentEditable : true,
			"class" : "sticky-content",
			keypress : markUnsaved
		}))
	.draggable({
		handle : "div.sticky-header",
		stack : ".sticky",
		start : markUnsaved,
		stop  : saveSticky
	 })
	.css({
		position: "absolute",
		"top" : data.top,
		"left": data.left
	})
	.focusout(saveSticky)
	.appendTo(document.body);
},

Да, длинновато, но не слишком трудно. Во-первых, обратите внимание, что эта функция принимает объект данных; как мы только что видели на примере openStickies, мы передаем сохраненные данные этой функции. Однако если не передается никаких данных (т.е. мы создаем совершенно новую заметку), то нами будет создан объект заметки по умолчанию. Поскольку все заметки создаются в одном месте, они все будут иметь эту конфигурацию. Заметьте, что для id заметки мы пользуемся конструкцией +new Date(), вставляя добавочный унарный оператор, преобразующий дату, получаемую из созданной даты, в число; таким образом, что этот оператор возвращает число, представляющее количество миллисекунд с 1 января 1970г. Очевидно, что оно будет постоянно меняться, потому это прекрасный способ идентифицировать по отдельности каждую заметку.

Остальная функция – это длинная строка выстроенных цепочкой методов jQuery. Перед тем, как заняться ими, обратите внимание, что мы возвращаем результат. Если бы мы публиковали этот метод разработчикам через API, использующий наше микроприложение, они бы упомянули ссылку на элемент div клейкой заметки.

Итак, вот что происходит:

Во-первых, мы создаем div, являющийся контейнером для нашей заметки. При помощи полезного синтаксиса jQuery 1.4 присваиваем ему класс «sticky» и id из объекта данных.

Затем вставляем туда еще один div; он получает класс «sticky-header». Div.sticky-header затем получает два прикрепленных к себе диапазона. Первый, span.sticky-status, получает обработчик щелчка, вызывающий функцию saveSticky. Однако в действительности это скрытое свойство: этот диапазон покажет статус заметки: сохраненная или не сохраненная. Заметка будет сохранять свои данные в localStorage несколькими способами; возможно, пользователь сочтет, что сохранит заметку нажатие ‘unsaved’, так что обеспечим его и этой функциональностью. Второй диапазон, span.close-sticky, станет клавишей удаления: когда пользователь нажмет ее, мы удалим заметку из localStorage при помощи метода deleteSticky. Передаем этому методу id заметки.

Далее прикрепляем другой div к основному div.sticky; заметьте, что мы установили свойства html на data.text; при сохранении текста заметки мы используем метод jQuery html(), потому что использование text() избавляет от обрывов строки. Также устанавливаем contentEditable:true для этого div’а, потому что это содержимое заметки. Как таковой, он также получает класс sticky-content. Наконец, когда на этом div’е нажимается клавиша (это означает, что пользователь изменяет содержимое), нам нужно пометить его как несохраненное, так что вызовем функцию (мы ее скоро сделаем).

Теперь воспользуемся свойством перетаскивания jQuery UI, чтобы наша клейкая заметка могла перемещаться. В объектном параметре используем свойство handle, чтобы заметки могли передвигаться из полосы заголовков. Свойство stack – это селектор для элементов, имеющих возможность передвигаться, чтобы они стремились складываться в одно место (stack); после его установки текущая перемещаемая заметка обязательно окажется сверху. Наконец, в начале перетаскивания заметки нам нужно пометить ее как несохраненную («unsaved»), потому что нужно также сохранить ее координаты, а после окончания перетаскивания мы сохраним этот стикер.

Далее определяем стили для своего div.sticky; устанавливаем позиционирование по абсолютным координатам, а затем устанавливаем свойства верха и левого края в соответствии с объектом данных. Таким образом, при обновлении страницы заметка будет сохранять как свою позицию, так и содержимое.

Наконец установим обработчик события focusout на стикере (по существу, щелкаем вне его после щелчка по нему): нам нужно сохранить содержимое стикера. В конце концов, мы прикрепим его к тегу body. Для справки, вот структура html, которая должна была у нас получиться:

<div class="sticky ui-draggable" id="1281194825332" style="position: absolute; top: 40px; left: 40px;">
	<div class="sticky-header">
			<span class="sticky-status"></span>
			<span class="close-sticky">trash</span>
	</div>
	<div contenteditable="true" class="sticky-content">
		Note Here
	</div>
</div>

Вот она, функция createSticky.

deleteSticky

Теперь у нас функция deleteSticky, она действительно простая:

	deleteSticky = function deleteSticky(id) {
	localStorage.removeItem("sticky-" + id);
	$("#" + id).fadeOut(200, function () { $(this).remove(); });
},

Как вы помните, функция deleteSticky принимает id заметки как свой параметр. localStorage.removeItem() – актуальный метод: мы передаем ключ к локально хранимому значению для удаления этой пары ключ-значение (заметьте, что при хранении данных заметки мы вставляем в id «sticky-»). Затем находим элемент с данным id, заставляем его погаснуть и удаляем. Заметка удалена!

saveSticky

Предпоследний на сегодня, возможно, самый важный метод:

	saveSticky = function saveSticky() {
	var that = $(this),  sticky = (that.hasClass("sticky-status") || that.hasClass("sticky-content")) ? that.parents('div.sticky'): that,
	obj = {
		id  : sticky.attr("id"),
		top : sticky.css("top"),
		left: sticky.css("left"),
		text: sticky.children(".sticky-content").html()
	}
	localStorage.setItem("sticky-" + obj.id, JSON.stringify(obj));
	sticky.find(".sticky-status").text("saved");
},

Первая строка – это идентификация: функцию можно вызывать из трех различных элементов. Во-первых, мы «jQuery-фицируем» this в that; затем, если у элемента имеются классы «sticky-status» или «sticky-content», получим родительский div.sticky; если не имеется ни одного из этих классов, тогда это и есть сам div.sticky, так что просто используем его.

Далее требуется получить значения, которые нужно хранить. Как можно видеть, мы получаем id, смещенный сверху и слева, и html дочернего .sticky-content; помните, мы пользуемся html() вместо text(), потому что нужно поддерживать разрывы строк. Теперь мы используем localStorage.setItem для хранения данных. Запомните, что он принимает на хранение два параметра: ключ и значение. Так как localStorage хранит только строки, мы пользуемся JSON.stringify() для преобразования объекта в строку.

В заключение меняем статус стикера на «saved.»

markUnsaved

У нас осталась последняя функция, вспомогательная:

	markUnsaved = function markUnsaved() {
	var that = $(this), sticky = that.hasClass("sticky-content") ? that.parents("div.sticky") : that;
	sticky.find(".sticky-status").text("unsaved");
}

Нам вновь нужно начать с разрешения ссылки на div.sticky; сделав это единожды, можно просто отыскать диапазон статуса и установить текст на «unsaved».

Верите или нет, но с JavaScript мы закончили.

Шаг 4: переработанный CSS

Теперь, когда мы знаем, какова разметка клейкой заметки, можно добавить в нее стилей. Это довольно просто; но тщательно изучите этот процесс, а я в конце немного прокомментирую его:

	:focus {
	outline:0;
}
.add-sticky {
	cursor: default;
	position:absolute;
	top:1px;
	left:1px;
	font-size:200%;
	background:#000;
	color:#fff;
	border:2px solid #fff;
	border-radius:40px;
	-webkit-border-radius:40px;
	-moz-border-radius:40px;
	text-align:center;
	line-height:25px;
	width:30px;
	height:30px;
}
.add-sticky:hover {
	background: #474747;
}
.sticky {
	width:300px;
	background:#fdfdbe;
	box-shadow:3px 3px 10px rgba(0,0,0,0.45);
	-webkit-box-shadow:3px 3px 10px rgba(0,0,0,0.45);
	-moz-box-shadow:3px 3px 10px rgba(0,0,0,0.45);
}
.sticky-content {
	min-height:150px;
	border-left:3px double rgba(238, 150, 122, .75);
	margin-left:30px;
	padding:5px;
}
.sticky-header {
	padding:5px;
	background:#f3f3f3;
	border-bottom:2px solid #fefefe;
	box-shadow:0 3px 5px rgba(0,0,0,0.25);
	-webkit-box-shadow:0 3px 5px rgba(0,0,0,0.25);
	-moz-box-shadow:0 3px 5px rgba(0,0,0,0.25);
}
.sticky-status {
	color:#ccc;
	padding:5px;
}
.close-sticky {
	background:#474747;
	float:right;
	cursor:default;
	color:#ececec;
	padding:1px 5px;
	border-radius:20px;
	-webkit-border-radius:20px;
	-moz-border-radius:20px;
}

Здесь есть несколько интересных моментов:

Некоторые браузеры делают контур вокруг элементов с contenteditable=true при редактировании вами содержимого. Нам так не нужно, так что избавляемся от этого при помощи объявления :focus.

Кнопка «Add Sticky» (добавить стикер) установлена в верхнем левом углу; выглядит смутно напоминающей «Add Dashboard Widget» (добавить виджет инструментальной панели) в Mac OS X.

Мы пользуемся свойствами CSS3 border-radius и box-shadow и соответствующими префиксами для разных реализаций браузеров.

Также мы используем rgba() для оттенков тени. Он принимает четыре параметра: красный, зеленый и синий цвет и значение альфа (прозрачность).

Иначе говоря, это просто стандартный CSS. Вот как должна выглядеть заметка со стилями:

sticky notes

Шаг 5: начинаем делать стикеры

Теперь, когда мы сделали свое приложение, настало время его запустить; это можно сделать из дополнительного пустого тэга script в файле index.html:

STICKIES.open();

Заключение.

Вот и все на сегодня: как вы собираетесь использовать локальную память HTML5 для добавления изюминки в веб-проекты? Дайте мне знать об этом в своих комментариях!

киберсант-вебмастер

Автор: Andrew Burgess

Перевод и редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.

Источник: http://net.tutsplus.com

E-mail: contact@webformyself.com

Проект webformyself.com — Как создать свой сайт. Основы самостоятельного сайтостроения

P.S. Хотите опубликовать интересный тематический материал и заработать? Если ответ «Да», то жмите сюда.

JavaScript&jQuery с нуля до профи

Пройдите пошаговый видеокурс по JavaScript&jQuery

Научиться

Метки: , ,

Комментарии Вконтакте:

Комментарии Facebook:

Комментарии (1)

  1. Сергей

    Я очень доволен.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree