DGrid: обработка onDoubleClick на строке
Разбор
Наткнулся на StackOverflow на вопрос, который давно мучил и меня самого: как в dgrid обрабатывать двойной клик по строке? Встроенного обработчика события onDblClick в классах библиотеки не было, поэтому я решил посмотреть, можно ли что-то сделать с помощью подручных средств.
Посмотрев код библиотеки, я обнаружил, что у класса Grid есть методы row() и cell(), возвращающие информацию о строке и ячейке соответственно при передаче в качестве параметра события, которое произошло в таблице. Главная сложность была в определении того, на что ставить обработчик. Понятно, что для тысяч строк нельзя вешать onClick() на каждую строку. В этом случае на контейнер вешают один единственный обработчик, который смотрит на то, от кого пришло событие, и уже тогда что-то делает. Всё оказалось не так уж сложно.
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dgrid/Grid"
], function(declare, lang, Grid){
return declare(Grid, {
onDblClick: function(){
/* Функция-пустышка, которая должна быть заменена на настоящую в классах,
унаследованных от этого. Тут должна быть какая-то работа с переданным
объектом, состоящим из трех полей:
- id - id записи, если есть
- data - полный объект из связанного с таблицей Store
- element - DOM-элемент, на котором случился двойной клик */
},
_onDblClick: function(event){
/* Вызываем onDblClick, передав "чистый" объект с параметрами. Обычно тут
разработчики Dojo Toolkit рекомендуют дополнительно вызывать on.emit с
необходимыми параметрами. На случай, если кто-то ещё должен слушать
события, происходящие в таблице, и как-то на них реагировать */
this.onDblClick(this.row(event));
}, // _onDblClick
postCreate: function(){
// Установка обработчиков на построенную DOM-модель таблицы
this.inherited(arguments);
this.on(".dgrid-content .dgrid-row:dblclick", lang.hitch(this, "_onDblClick"));
} // postCreate
}); // declare
}); //define
Можно пойти дальше и создать класс-расширение, раз уж в Dojo реализовано множественное наследование. Если что, это рекомендуемый способ расширения функционала классов и каноничный подход к написанию плагинов.
Комментарии в исходном коде
Устал искать, в каком месте удалил лишнюю скобку. Устал определять по отступу, где закончился цикл или if. Поэтому сейчас пишу код примерно так:
define([
/*
* Главное меню приложения.
* Обработчики событий должны устанавливаться в классе Application.
*/
"dojo/_base/array", // array.forEach в одном месте
"dojo/_base/declare",
"dijit/DropDownMenu",
"dijit/MenuBar",
"dijit/MenuBarItem",
"dijit/MenuItem",
"dijit/PopupMenuBarItem"
], function(
array,
declare,
DropDownMenu
MenuBar,
MenuBarItem,
MenuItem,
PopupMenuBarItem
){
// Создает пункт главного меню с DropDown'ом
function createMenuBarItem(label){
return new PopupMenuBarItem({
label: label,
popup: new DropDownMenu({})
});
} // createMenuBarItem
return declare(MenuBar, {
buildRendering: function(){
this.inherited(arguments);
// Какой-то код...
this.fileMenu = createMenuBarItem("Файл");
this.editMenu = createMenuBarItem("Правка");
this.dictsMenu = createMenuBarItem("Справочники");
array.forEach([
this.fileMenu,
this.editMenu,
this.dictsMenu
], this.addChild, this); // forEach
} // buildRendering
}); // declare
}); // define
Если вкратце, то я просто пишу после закрывающих скобок, что именно они закрывают - конец цикла, тела функции, массива и т. д. Подсмотрел такое в исходном коде одного сайта, там верстальщик в комментариях указывал границы логических блоков - хедер, футер, тело страницы, панель навигации и т. д.
Grunt
Введение
Надоело мне как-то перепроверять все CSS-файлы при изменении дизайна. Поискав немного, я остановился на LESS. Вместо того, чтобы управлять одним огромным файлом styles.css, LESS позволяет создать множество мелких файлов, каждый из которых отвечает за свою часть общей таблицы стилей. Однако, собирать всё вручную мне было лень, поэтому я решил для своего проекта использовать Grunt. Для него есть множество модулей, которые способны сильно облегчить жизнь Web-разработчика, в частности, компилировать множество LESS файлов автоматически, собирать и сжимать JavaScript'ы и т.д.
В данной статье пойдёт рассказ о том, зачем нужен Grunt, показаны примеры его использования и базовой настройки, а также мимоходом захвачено использование LESS для разработки каскадных таблиц стилей.
Для проекта, над которым я работаю, было принято решение создать в корневом каталоге папку /less, куда поместить следующие файлы:
bootstrap.less- объединяет в себе все остальные файлы. Изменяя содержимое этого файла легко управлять результирующей таблицей стилей.colors.less- содержит переменные, описывающие цвета, используемые на страницах, например,@red: #FF0000;.fonts.less- описывает используемые на страницах шрифты. В своём проекте я решил использовать символьный шрифт FontAwesome вместо того, чтобы рисовать иконки.
а также по одному файлу на каждый отдельный блок, например, визуальный компонент или целую страницу.
Установка
Целевой системой сегодня будет не Debian, а Windows 8. Установка всех средств в Debian, кроме NodeJS, производится аналогично - командами в консоли. Если хотите NodeJS в Debian Wheezy - прочитайте вот эту статью.
Скачиваем установщик с сайта проекта NodeJS и запускаем, при установке не забываем указать, что нам также понадобится менеджер пакетов (Node Package Manager - NPM).
Настройка проекта для использования Grunt
Существует два способа установки Grunt'а - глобально и локально, в проект. Я рекомендую сам Grunt установить глобально, а необходимые модули - в папку проекта. Её всегда можно добавить в исключения вашей СКВ.
Запускаем командную строку от имени администратора и вводим следующие команды:
npm install grunt -g
npm install grunt-cli -g
Первый пакет - это собственно Grunt, второй - утилиты командной строки, позволяющие работать с ним. Ключ -g означает, что установленные пакеты должны быть доступны глобально.
Перейдём в каталог нашего проекта (вместо %project_root_folder% подставьте нужное) и инициализируем его для использования Grunt'а:
cd %project_root_folder%
grunt init
Будет задано несколько вопросов, касающихся проекта, в частности, имя автора, версия, лицензия и т.д. На основе ответов будет составлен файл package.json, который при необходимости всегда можно изменить. например, в моём проекте он выглядит вот так:
{
"name": "tester",
"version": "0.0.0",
"description": "Система тестирования",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Dunaevsky Maxim",
"license": "MIT",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-less": "^0.11.4",
"grunt-contrib-uglify": "^0.5.1"
}
}
Теперь нам нужно будет установить необходимые модули, я ограничусь всего тремя:
concat- собирает несколько указанных файлов в один.less- компилирует LESS-файлы в каскадные таблицы стилей CSS.uglify- оптимизирует и сжимает JavaScript-код.
Установка производится очень просто:
npm install grunt-contrib-concat --save-dev
npm install grunt-contrib-less --save-dev
npm install grunt-contrib-uglify --save-dev
Ключ --save-dev означает, что пакеты должны быть также прописаны в файле package.json.
Пакеты установлены, самое время дать Grunt'у задание - скомпилировать LESS-файлы, склеить вместе все JavaScript'ы из каталога /src/ и сжать итоговый файл. Для этого нам понадобится файл Gruntfile.js. Обратите внимание, первая буква в названии файла должна быть большой. Создать его следует в корневом каталоге проекта.
Рассмотрим Gruntfile.js, которым пользуюсь я сам:
"use strict";
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
less: {
dev: {
files: {
'css/styles.css': 'less/bootstrap.less'
}
},
min: {
options: {
ieCompat: true,
compress: 2,
optimization: true
},
files: {
'css/styles.min.css': 'less/bootstrap.less'
}
}
},
concat: {
js: {
src: [
'src/*.js'
],
dest: 'js/ui.js'
}
},
uglify: {
build: {
src: 'js/ui.js',
dest: 'js/ui.min.js'
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['less:dev', 'concat:js', 'uglify']);
};
Первым делом определяются настройки для задач, а также указывается, откуда брать информацию о проекте (файл package.json).
Задание для сборки CSS из LESS-файлов содержит две секции - настройки для разработки (dev) и для релиза (min), когда важен маленький размер файла и оптимизация кода. В обоих заданиях указано, что нужно на основе файла bootstrap.less из каталога less собрать файл styles.css в каталоге css.
Задание для concat'а небольшое - ему нужно всего навсего взять все js-файлы в каталоге src и склеить в один - ui.js, положив его в каталог js.
Самое последнее задание - оптимизация и сжатие получившегося при склеивании файла с помощью утилиты uglify.
В конце файла производится загрузка необходимых модулей и выполнение их в порядке перечисления аргументов функции grunt.registerTask. Изменяя порядок следования аргументов можно управлять процессом сборки.
Закончив редактирование файла Gruntfile.js, запустите командую строку в текущем каталоге и выполните команду grunt. В случае ошибки в конфигурации или одном из файлов проекта будет выдано соответствующее сообщение. В противном случае вывод на экран будет выглядеть примерно так:
Running "less:dev" (less) task
File css/styles.css created: 0 B → 251 B
Running "concat:js" (concat) task
File js/ui.js created.
Running "uglify:build" (uglify) task
Done, without errors.