|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- /*
- *
- * Реализация шаблона "издатель-подписчик"
- *
- */
-
- function Уведомитель()
- {
- function Подписка(id, отклик, уведомитель)
- {
- this.id = id;
- this.отклик = отклик;
- this.уведомитель = уведомитель;
- };
-
- this.уведомить = function()
- {
- // Попутно собираем подписки без отклика.
- var безотклика = [];
- for (var номер in this.подписки)
- {
- var подписка = this.подписки[номер];
- if (подписка.отклик)
- {
- подписка.отклик();
- }
- else
- {
- безотклика.push(подписка);
- }
- }
-
- // И удаляем их.
- if (безотклика.length)
- {
- this._удалитьПодпискиБезОтклика(безотклика);
- }
- };
-
- this.подписать = function(отклик)
- {
- var id = this._сгенерироватьUUID();
- var подписка = new Подписка(id, отклик, this);
- this.подписки.push(подписка);
- return подписка;
- };
-
- this.отписать = function(подписка)
- {
- подписка.отклик = null;
- };
-
- this._удалитьПодпискиБезОтклика = function(удалить)
- {
- var подписка = удалить.shift()
- while (подписка)
- {
- var индекс = this.подписки.indexOf(подписка);
- if (индекс !== -1)
- {
- this.подписки.splice(индекс, 1);
- }
- var подписка = удалить.shift()
- }
- };
-
- this._сгенерироватьUUID = function()
- {
- // https://stackoverflow.com/a/2117523
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
- /[xy]/g,
- function(c)
- {
- var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
- return v.toString(16);
- }
- );
- };
-
- // Конструктор.
- this.подписки = [];
- }
-
- /*
- *
- * Связь событий и реакций в виде последовательности (череды)
- *
- */
-
- function Мир()
- {
- // Разобрать события и реакции, выраженные в тексте.
- this.разобрать = function(череда)
- {
- var соответствия = this._событияРеакции(череда);
- for (var событие in соответствия)
- {
- if (!(событие in this.события))
- {
- this.события[событие] = new Уведомитель();
- }
- var реакции = соответствия[событие];
- for (var номер in реакции)
- {
- const реакция = реакции[номер];
- const название = this._имяФункцииИзРеакции(реакция);
- const функция = eval(название);
- var тут = this;
- this.события[событие].подписать(function(){
- функция(тут);
- });
- }
- }
- };
-
- // Уведомить о событии при его наличии.
- this.уведомить = function(событие)
- {
- if (событие in this.события)
- {
- this.события[событие].уведомить();
- }
- };
-
- // Разобрать текст с событиями и реакциями, вернуть словарь их соответствия.
- this._событияРеакции = function(текст)
- {
- var соответствие = {};
-
- var элементы = текст.split("\n");
- var имяСобытия = null;
- for (var номер in элементы)
- {
- var элемент = элементы[номер];
- // Пропускаем комментарии.
- if (элемент.charAt(0) == "#")
- {
- continue;
- }
- var имя = элемент.trim();
- // Пропускаем пустые строки.
- if (!имя.length)
- {
- continue;
- }
- // Событие.
- if (имя == элемент)
- {
- if (!(имя in соответствие))
- {
- имяСобытия = имя;
- соответствие[имя] = [];
- }
- }
- // Реакция.
- else
- {
- соответствие[имяСобытия].push(имя);
- }
- }
-
- return соответствие;
- };
-
- // Преобразовать имя реакции в название функции.
- this._имяФункцииИзРеакции = function(реакция)
- {
- var имя = "";
-
- var части = реакция.split(" ");
- for (var номер in части)
- {
- var часть = части[номер];
- имя += часть.charAt(0).toUpperCase() + часть.slice(1);
- }
-
- return имя;
- };
-
- // Конструктор.
- this.события = {};
- }
-
- /*
- *
- * Создание глобального мира.
- *
- */
-
- мир = new Мир();
|