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