Переменная вне области действия обработчика событий

У меня возникла ошибка Javascript, которая выходит за рамки моего знания языка.

Я создаю собственный плагин для CKEditor. Плагин представляет собой IFrame, который открывается в DIV, созданном CKEditor.

Внутри IFrame я показываю несколько изображений. Если пользователь выбирает одно из этих изображений, HTML-код, необходимый для отображения этого изображения, вставляется в CKEditor.

Я застрял в динамическом выполнении этого. Я подключаюсь к экземпляру CKEditor из iframe следующим образом:

var CKEDITOR = window.parent.CKEDITOR;    

CKEditor предлагает "прослушивателя OK", который срабатывает при нажатии кнопки OK (отображаемой CKEDitor). Этот слушатель ОК находится за пределами IFrame.

Определение прослушивателя OK, работающего со статическими значениями, работает:

var okListener = function(ev) {
   this._.editor.insertHtml('<img class="symbol" src="my_static_symbol.gif">');
   CKEDITOR.dialog.getCurrent().removeListener("ok", okListener);
};

// Assign OK listener
CKEDITOR.dialog.getCurrent().on("ok", okListener);

Но я еще не знаю возвращаемое значение, когда назначаю прослушиватель OK, поэтому мне нужно сделать что-то вроде этого:

var okListener = function(ev) {
   this._.editor.insertHtml('<img class="symbol" src="'+my_dynamic_value()+'">');
   CKEDITOR.dialog.getCurrent().removeListener("ok", okListener);
};

// Assign OK listener
CKEDITOR.dialog.getCurrent().on("ok", okListener);

Но это не работает, потому что my_dynamic_value находится за пределами области действия функции в то время, когда она запускается кнопкой «OK» CKEditor.

Конечно, я мог бы каждый раз, когда пользователь выбирает другое изображение в списке, обновлять функцию okListener и жестко закодировать текущее значение, используя eval. Но мне кажется, что это ужасная трата ресурсов.

Есть ли какой-нибудь трюк с областью видимости, который я могу использовать, чтобы получить доступ к материалам из моего Iframe изнутри okListener ()?

Надеюсь, это достаточно ясно. Если это не так, прокомментируйте, и я уточню.


person Pekka    schedule 20.12.2009    source источник
comment
Здравствуйте, Пекка, вы можете предоставить доступ к образцу?   -  person Diadistis    schedule 21.12.2009
comment
К сожалению, нет, все это работает локально и потребует огромных усилий для загрузки (редактор встроен в большую CMS). Что я могу сделать, чтобы прояснить ситуацию?   -  person Pekka    schedule 21.12.2009
comment
okListener определен в iframe или в родительском элементе? Создается / посещается iframe только один раз или когда пользователю нужно выбрать изображение?   -  person outis    schedule 21.12.2009
comment
okListener определяется в iframe, а затем назначается экземпляру CKEditor в родительском элементе. Iframe остается, пользователь может переходить от изображения к изображению. Когда он щелкает "ОК", мне нужно указать okListener, какое изображение пользователь щелкнул последним.   -  person Pekka    schedule 21.12.2009


Ответы (2)


Но это не работает, потому что my_dynamic_value находится за пределами области действия функции в то время, когда она запускается кнопкой «OK» CKEditor.

OK. Возможно, это действительно не работает, но объяснение неверное. В JavaScript переменные имеют лексическую область видимости. Это означает, что если my_dynamic_value находится в области видимости при объявлении вашей функции (обработчика), то она остается там навсегда. Какое сообщение об ошибке вы получаете?

person thorn0    schedule 21.12.2009
comment
Ааааарх. Ты прав. Ошибка, которую я совершил, заключалась в том, что я не объявлял переменную до. Я объявил функцию, думая, что не имеет значения, когда я ее объявляю, если это происходит в той же области видимости. Теперь это работает. Спасибо. - person Pekka; 21.12.2009
comment
Странный. Заказ действительно не имеет значения. Например, этот код выводит 5: (function () {setTimeout (function () {alert (a);}, 2000); var a = 5;}) (); - person thorn0; 21.12.2009

Вы можете написать функцию, которая создает слушателя, передавая динамическое значение (как функцию или строку, в зависимости от того, как написана остальная часть скрипта).

function createOKListener(imgURLFunc) {
   return function(ev) {
      this._.editor.insertHtml('<img class="symbol" src="'+imgURLFunc()+'">');
      CKEDITOR.dialog.getCurrent().removeListener("ok", okListener);
   };
};

// Assign OK listener
CKEDITOR.dialog.getCurrent().on("ok", createOKListener(function() {iframeRef.path.to.imageURL}));

Or:

function createOKListener(imgURL) {
   return function(ev) {
      this._.editor.insertHtml('<img class="symbol" src="'+imgURL+'">');
      CKEDITOR.dialog.getCurrent().removeListener("ok", okListener);
   };
};

// Assign OK listener
CKEDITOR.dialog.getCurrent().on("ok", createOKListener(path.to.imageURL));

Я подозреваю, что происходит то, что функция выполняется в контексте окна верхнего уровня; Верно это или нет, зависит от реализации события CKEditor. В этом случае вы можете попробовать получить доступ к глобальным переменным iframe через окно iframe (как указано в версии imgURLFunc) или привязать значение к локальной переменной (как это сделано с createOKListener).

Что происходит, так это то, что глобальные переменные (кроме window) разрешаются как свойства window (представьте, что вокруг блоков кода есть with (window) {...}). Когда CKEditor запускает событие, он делает это в контексте CKEDITOR, который равен window.parent (из iframe).

person outis    schedule 21.12.2009
comment
Приветствую вас и спасибо за ваше время. Оказывается, это была моя ошибка. См. Мой комментарий к ответу выше. - person Pekka; 21.12.2009