/* * * Реализация шаблона "издатель-подписчик" * */ 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 Мир();