<commit_before># ns.View

## Декларация

### `params`

Если **массив**: в массиве указываются группы параметров, чтобы можно было строить ключ по-разному в зависимости от того, что за параметры пришли в урле.
```js
ns.View.define('super-view', {
  params: [
    { "context": "album", "album-id": null },
    { "context": null }
  ]
});
```

Как строится ключ:
- для каждой группы из массива:
- каждое свойство объекта — это параметр урла, нужный для построения ключа
- если значение свойства `null` — параметр обязателен, но значение его может быть любым
- если значение свойства не `null` — это **фильтр**: параметр из урла должен иметь именно это значение (NOTE сейчас там везде `string`)
- если есть все нужные параметры и выполняются все фильтры — ключ можно строить
- иначе — пытаемся строить по следующей группе параметров

Если **объект** — тоже самое, что массив из одного элемента (см. выше).

Если **не указан** — параметры строятся по параметрам моделей `info.models`:
```js
ns.View.define('super-view', {
  models: [ 'album', 'photo' ]
});
```
- объединяются `model.info.params` в порядке их объявления в `view.info.models` (NOTE: тут получается некоторый приоритет: чем позднее указана модель, тем приоритетнее значения её параметров. Это не специально и это не продумывали отдельно)
- конкретные значения, указанные в `model.params`, становятся **значениями поумолчанию** при построении ключа view.

Если `params` явно заданы — нельзя использовать `params+` / `params-` (о них ниже).

Если ключ view нельзя построить кидается **ошибка**.

### `params+`
В случае, когда набор параметров view строится по параметрам моделей можно добавить в результирующий набор дополнительные параметры:
```js
ns.View.define('super-view', {
  "models": [ 'album', 'photo' ],
  "params+": { page: 23 }
});
```

### `params-`
Для удаления части параметров из ключа можно использовать `params-`:
```js
ns.View.define('super-view', {
  "models": [ 'album', 'photo' ],
  "params-": [ 'album-id' ]
});
```


## Про события

Список событий:
* ```ns-view-hide``` - view был скрыт и больше не виден на странице
* ```ns-view-htmldestroy``` - старая нода у view была заменена на новую
* ```ns-view-htmlinit``` - у view появилась новая нода
* ```ns-view-async``` - у async-view появилась заглушка. Это единственное событие, которое генерируется для заглушки async-view
* ```ns-view-show``` - view был показан и теперь виден на странице
* ```ns-view-repaint``` - view виден и был затронут в процессе обновления страницы

1. События генерируются снизу вверх, т.е. сначала их получают дочерние view, потом родительские.
2. События генерируются пачками, т.е. сначала одно событие у всех view, потом другое событие у всех view.
3. События генерируются в строго определенном порядке:

```
ns-view-hide
ns-view-htmldestroy
ns-view-htmlinit
ns-view-async
ns-view-show
ns-view-repaint
```

Примеры последовательностей событий:
* инициализация view: ```ns-view-htmlinit -> ns-view-show -> ns-view-repaint```
* перерисовка страница, если view валиден: ```ns-view-repaint```
* view был скрыт: ```ns-view-hide``` (без ```ns-view-repaint```)
* view был показан: ```ns-view-show -> ns-view-repaint```
* view был обновлене: ```ns-view-hide -> ns-view-htmldestroy -> ns-view-htmlinit -> ns-view-show -> ns-view-repaint``` (```ns-view-hide``` тут вызывается из тех соображений, что могут быть обработчики, которые вешаются на ```ns-view-show/ns-view-hide``` и при обновлении ноды, они должны быть переинициализированы)

## Subview
`Subview` - это часть `view`, которая отвечает за небольшой кусок интерфейса (флажок важное, метка прочитанности и т.п.).
Главный смысл в том, что при изменении определенных данных не надо перерисовывать весь `view`, а достаточно изменить лишь небольшую часть - `subview`.
`Subview` надо задекларировать свое название, от какой модели он зависит и какие данные важны для него (`jpath`).
Если есть задекларованные `subview`, то `view` реагирует только на них или на полную инвалидацию модели.

Пример
```js
//  Парсим информацию про subview.
//
//  В info.subviews приходит структура такого вида:
//
//      {
//          //  Определяем subview 'labels':
//          'labels': [
//              //  зависящее от поля '.labels' модели 'message',
//              'message .labels',
//              //  и от модели 'labels' целиком.
//              'labels'
//          ],
//          //  Пустая строка в качестве имени subview означает все view целиком.
//          //  Если хоть как-нибудь меняется модель 'folders', то весь блок нужно перерисовать.
//          '': 'folders'
//          ...
//      }
//
```<commit_msg>Дописал про события @show и @init<commit_after># ns.View

## Декларация

### `params`

Если **массив**: в массиве указываются группы параметров, чтобы можно было строить ключ по-разному в зависимости от того, что за параметры пришли в урле.
```js
ns.View.define('super-view', {
  params: [
    { "context": "album", "album-id": null },
    { "context": null }
  ]
});
```

Как строится ключ:
- для каждой группы из массива:
- каждое свойство объекта — это параметр урла, нужный для построения ключа
- если значение свойства `null` — параметр обязателен, но значение его может быть любым
- если значение свойства не `null` — это **фильтр**: параметр из урла должен иметь именно это значение (NOTE сейчас там везде `string`)
- если есть все нужные параметры и выполняются все фильтры — ключ можно строить
- иначе — пытаемся строить по следующей группе параметров

Если **объект** — тоже самое, что массив из одного элемента (см. выше).

Если **не указан** — параметры строятся по параметрам моделей `info.models`:
```js
ns.View.define('super-view', {
  models: [ 'album', 'photo' ]
});
```
- объединяются `model.info.params` в порядке их объявления в `view.info.models` (NOTE: тут получается некоторый приоритет: чем позднее указана модель, тем приоритетнее значения её параметров. Это не специально и это не продумывали отдельно)
- конкретные значения, указанные в `model.params`, становятся **значениями поумолчанию** при построении ключа view.

Если `params` явно заданы — нельзя использовать `params+` / `params-` (о них ниже).

Если ключ view нельзя построить кидается **ошибка**.

### `params+`
В случае, когда набор параметров view строится по параметрам моделей можно добавить в результирующий набор дополнительные параметры:
```js
ns.View.define('super-view', {
  "models": [ 'album', 'photo' ],
  "params+": { page: 23 }
});
```

### `params-`
Для удаления части параметров из ключа можно использовать `params-`:
```js
ns.View.define('super-view', {
  "models": [ 'album', 'photo' ],
  "params-": [ 'album-id' ]
});
```


### `events`

Список событий:
* ```ns-view-hide``` - view был скрыт и больше не виден на странице
* ```ns-view-htmldestroy``` - старая нода у view была заменена на новую
* ```ns-view-htmlinit``` - у view появилась новая нода
* ```ns-view-async``` - у async-view появилась заглушка. Это единственное событие, которое генерируется для заглушки async-view
* ```ns-view-show``` - view был показан и теперь виден на странице
* ```ns-view-repaint``` - view виден и был затронут в процессе обновления страницы

1. События генерируются снизу вверх, т.е. сначала их получают дочерние view, потом родительские.
2. События генерируются пачками, т.е. сначала одно событие у всех view, потом другое событие у всех view.
3. События генерируются в строго определенном порядке:

```
ns-view-hide
ns-view-htmldestroy
ns-view-htmlinit
ns-view-async
ns-view-show
ns-view-repaint
```

Примеры последовательностей событий:
* инициализация view: ```ns-view-htmlinit -> ns-view-show -> ns-view-repaint```
* перерисовка страница, если view валиден: ```ns-view-repaint```
* view был скрыт: ```ns-view-hide``` (без ```ns-view-repaint```)
* view был показан: ```ns-view-show -> ns-view-repaint```
* view был обновлене: ```ns-view-hide -> ns-view-htmldestroy -> ns-view-htmlinit -> ns-view-show -> ns-view-repaint``` (```ns-view-hide``` тут вызывается из тех соображений, что могут быть обработчики, которые вешаются на ```ns-view-show/ns-view-hide``` и при обновлении ноды, они должны быть переинициализированы)

#### `@show` и `@init`
События с суффиксом `@show` вещаются во время показа view - `view.show()` - и снимаются во время `view.hide()`.
Аналогично, `@init` суффикс означает, что событие будет активировано на `ns-view-htmlinit` и деактивировано на `ns-view-htmldestroy` (это поведение поумолчанию).

## Subview
`Subview` - это часть `view`, которая отвечает за небольшой кусок интерфейса (флажок важное, метка прочитанности и т.п.).
Главный смысл в том, что при изменении определенных данных не надо перерисовывать весь `view`, а достаточно изменить лишь небольшую часть - `subview`.
`Subview` надо задекларировать свое название, от какой модели он зависит и какие данные важны для него (`jpath`).
Если есть задекларованные `subview`, то `view` реагирует только на них или на полную инвалидацию модели.

Пример
```js
//  Парсим информацию про subview.
//
//  В info.subviews приходит структура такого вида:
//
//      {
//          //  Определяем subview 'labels':
//          'labels': [
//              //  зависящее от поля '.labels' модели 'message',
//              'message .labels',
//              //  и от модели 'labels' целиком.
//              'labels'
//          ],
//          //  Пустая строка в качестве имени subview означает все view целиком.
//          //  Если хоть как-нибудь меняется модель 'folders', то весь блок нужно перерисовать.
//          '': 'folders'
//          ...
//      }
//
```
{'fraction_non_alphanumeric': 0.13251623716739996, 'fraction_numerical': 0.001047559187094071, 'mean_word_length': 3.726237623762376, 'pattern_counts': {'":': 14, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3460320', 'n_tokens_mistral': 3747, 'n_tokens_neox': 4287, 'n_words': 1083}