text: /*
  Copyright 2011-2016 OCAD University
  Copyright 2011 Lucendo Development Ltd.
  
  Licensed under the Educational Community License (ECL), Version 2.0 or the New
  BSD license. You may not use this file except in compliance with one these
  Licenses.
  
  You may obtain a copy of the ECL 2.0 License and BSD License at
  https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  */
  
  var fluid_3_0_0 = fluid_3_0_0 || {};
  
  (function ($, fluid) {
      "use strict";
  
      fluid.registerNamespace("fluid.dom");
  
      fluid.dom.getDocumentHeight = function (dokkument) {
          var body = $("body", dokkument)[0];
          return body.offsetHeight;
      };
  
      /*******************************************************
       * Separated Panel Preferences Editor Top Level Driver *
       *******************************************************/
  
      fluid.defaults("fluid.prefs.separatedPanel", {
          gradeNames: ["fluid.prefs.prefsEditorLoader", "fluid.contextAware"],
          events: {
              afterRender: null,
              onReady: null,
              onCreateSlidingPanelReady: {
                  events: {
                      iframeRendered: "afterRender",
                      onPrefsEditorMessagesLoaded: "onPrefsEditorMessagesLoaded"
                  }
              },
              templatesAndIframeReady: {
                  events: {
                      iframeReady: "afterRender",
                      templatesLoaded: "onPrefsEditorTemplatesLoaded",
                      messagesLoaded: "onPrefsEditorMessagesLoaded"
                  }
              }
          },
          lazyLoad: false,
          contextAwareness: {
              lazyLoad: {
                  checks: {
                      lazyLoad: {
                          contextValue: "{fluid.prefs.separatedPanel}.options.lazyLoad",
                          gradeNames: "fluid.prefs.separatedPanel.lazyLoad"
                      }
                  }
              }
          },
          selectors: {
              reset: ".flc-prefsEditor-reset",
              iframe: ".flc-prefsEditor-iframe"
          },
          listeners: {
              "onReady.bindEvents": {
                  listener: "fluid.prefs.separatedPanel.bindEvents",
                  args: ["{separatedPanel}.prefsEditor", "{iframeRenderer}.iframeEnhancer", "{separatedPanel}"]
              },
              "onCreate.hideReset": {
                  listener: "fluid.prefs.separatedPanel.hideReset",
                  args: ["{separatedPanel}"]
              }
          },
          invokers: {
              bindReset: {
                  funcName: "fluid.bind",
                  args: ["{separatedPanel}.dom.reset", "click", "{arguments}.0"]
              }
          },
          components: {
              slidingPanel: {
                  type: "fluid.slidingPanel",
                  container: "{separatedPanel}.container",
                  createOnEvent: "onCreateSlidingPanelReady",
                  options: {
                      gradeNames: ["fluid.prefs.msgLookup"],
                      strings: {
                          showText: "{that}.msgLookup.slidingPanelShowText",
                          hideText: "{that}.msgLookup.slidingPanelHideText",
                          showTextAriaLabel: "{that}.msgLookup.showTextAriaLabel",
                          hideTextAriaLabel: "{that}.msgLookup.hideTextAriaLabel",
                          panelLabel: "{that}.msgLookup.slidingPanelPanelLabel"
                      },
                      invokers: {
                          operateShow: {
                              funcName: "fluid.prefs.separatedPanel.showPanel",
                              args: ["{that}.dom.panel", "{that}.events.afterPanelShow.fire"],
                              // override default implementation
                              "this": null,
                              "method": null
                          },
                          operateHide: {
                              funcName: "fluid.prefs.separatedPanel.hidePanel",
                              args: ["{that}.dom.panel", "{iframeRenderer}.iframe", "{that}.events.afterPanelHide.fire"],
                              // override default implementation
                              "this": null,
                              "method": null
                          }
                      },
                      components: {
                          msgResolver: {
                              type: "fluid.messageResolver",
                              options: {
                                  messageBase: "{messageLoader}.resources.prefsEditor.resourceText"
                              }
                          }
                      }
                  }
              },
              iframeRenderer: {
                  type: "fluid.prefs.separatedPanel.renderIframe",
                  container: "{separatedPanel}.dom.iframe",
                  options: {
                      events: {
                          afterRender: "{separatedPanel}.events.afterRender"
                      },
                      components: {
                          iframeEnhancer: {
                              type: "fluid.uiEnhancer",
                              container: "{iframeRenderer}.renderPrefsEditorContainer",
                              createOnEvent: "afterRender",
                              options: {
                                  gradeNames: ["{pageEnhancer}.uiEnhancer.options.userGrades"],
                                  jQuery: "{iframeRenderer}.jQuery",
                                  tocTemplate: "{pageEnhancer}.uiEnhancer.options.tocTemplate"
                              }
                          }
                      }
                  }
              },
              prefsEditor: {
                  createOnEvent: "templatesAndIframeReady",
                  container: "{iframeRenderer}.renderPrefsEditorContainer",
                  options: {
                      gradeNames: ["fluid.prefs.uiEnhancerRelay"],
                      // ensure that model and applier are available to users at top level
                      model: "{separatedPanel}.model",
                      events: {
                          onSignificantDOMChange: null,
                          updateEnhancerModel: "{that}.events.modelChanged"
                      },
                      listeners: {
                          "modelChanged.save": "{that}.save",
                          "onCreate.bindReset": {
                              listener: "{separatedPanel}.bindReset",
                              args: ["{that}.reset"]
                          },
                          "afterReset.applyChanges": "{that}.applyChanges",
                          "onReady.boilOnReady": {
                              listener: "{separatedPanel}.events.onReady",
                              args: "{separatedPanel}"
                          },
                          "onReady.windowResize": {
                              "this": window,
                              method: "addEventListener",
                              args: ["resize", "{that}.events.onSignificantDOMChange.fire"]
                          }
                      }
                  }
              }
          },
          outerEnhancerOptions: "{originalEnhancerOptions}.options.originalUserOptions",
          distributeOptions: [{
              source: "{that}.options.slidingPanel",
              removeSource: true,
              target: "{that > slidingPanel}.options"
          }, {
              source: "{that}.options.iframeRenderer",
              removeSource: true,
              target: "{that > iframeRenderer}.options"
          }, {
              source: "{that}.options.iframe",
              removeSource: true,
              target: "{that}.options.selectors.iframe"
          }, {
              source: "{that}.options.outerEnhancerOptions",
              removeSource: true,
              target: "{that iframeEnhancer}.options"
          }, {
              source: "{that}.options.terms",
              target: "{that > iframeRenderer}.options.terms"
          }]
      });
  
      fluid.prefs.separatedPanel.hideReset = function (separatedPanel) {
          separatedPanel.locate("reset").hide();
      };
      /*****************************************
       * fluid.prefs.separatedPanel.renderIframe *
       *****************************************/
  
      fluid.defaults("fluid.prefs.separatedPanel.renderIframe", {
          gradeNames: ["fluid.viewComponent"],
          events: {
              afterRender: null
          },
          styles: {
              container: "fl-prefsEditor-separatedPanel-iframe"
          },
          terms: {
              templatePrefix: "."
          },
          markupProps: {
              "class": "flc-iframe",
              src: "%templatePrefix/SeparatedPanelPrefsEditorFrame.html"
          },
          listeners: {
              "onCreate.startLoadingIframe": "fluid.prefs.separatedPanel.renderIframe.startLoadingIframe"
          }
      });
  
      fluid.prefs.separatedPanel.renderIframe.startLoadingIframe = function (that) {
          var styles = that.options.styles;
          // TODO: get earlier access to templateLoader,
          that.options.markupProps.src = fluid.stringTemplate(that.options.markupProps.src, that.options.terms);
          that.iframeSrc = that.options.markupProps.src;
  
          // Create iframe and append to container
          that.iframe = $("<iframe/>");
          that.iframe.on("load", function () {
              var iframeWindow = that.iframe[0].contentWindow;
              that.iframeDocument = iframeWindow.document;
              // The iframe should prefer its own version of jQuery if a separate
              // one is loaded
              that.jQuery = iframeWindow.jQuery || $;
  
              that.renderPrefsEditorContainer = that.jQuery("body", that.iframeDocument);
              that.jQuery(that.iframeDocument).ready(that.events.afterRender.fire);
          });
          that.iframe.attr(that.options.markupProps);
  
          that.iframe.addClass(styles.container);
          that.iframe.hide();
  
          that.iframe.appendTo(that.container);
      };
  
      fluid.prefs.separatedPanel.updateView = function (prefsEditor) {
          prefsEditor.events.onPrefsEditorRefresh.fire();
          prefsEditor.events.onSignificantDOMChange.fire();
      };
  
  
      fluid.prefs.separatedPanel.bindEvents = function (prefsEditor, iframeEnhancer, separatedPanel) {
          // FLUID-5740: This binding should be done declaratively - needs ginger world in order to bind onto slidingPanel
          // which is a child of this component
  
          var separatedPanelId = separatedPanel.slidingPanel.panelId;
          separatedPanel.locate("reset").attr({
              "aria-controls": separatedPanelId,
              "role": "button"
          });
  
          separatedPanel.slidingPanel.events.afterPanelShow.addListener(function () {
              fluid.prefs.separatedPanel.updateView(prefsEditor);
          }, "updateView", "after:openPanel");
  
          prefsEditor.events.onPrefsEditorRefresh.addListener(function () {
              iframeEnhancer.updateModel(prefsEditor.model.preferences);
          }, "updateModel");
          prefsEditor.events.afterReset.addListener(function (prefsEditor) {
              fluid.prefs.separatedPanel.updateView(prefsEditor);
          }, "updateView");
          prefsEditor.events.onSignificantDOMChange.addListener(function () {
              // ensure that the panel is open before trying to adjust its height
              if ( fluid.get(separatedPanel, "slidingPanel.model.isShowing") ) {
                  var dokkument = prefsEditor.container[0].ownerDocument;
                  var height = fluid.dom.getDocumentHeight(dokkument);
                  var iframe = separatedPanel.iframeRenderer.iframe;
                  var attrs = {height: height};
                  var panel = separatedPanel.slidingPanel.locate("panel");
                  panel.css({height: ""});
                  iframe.clearQueue();
                  iframe.animate(attrs, 400);
              }
          }, "adjustHeight");
  
          separatedPanel.slidingPanel.events.afterPanelHide.addListener(function () {
              separatedPanel.iframeRenderer.iframe.height(0);
  
              // Prevent the hidden Preferences Editorpanel from being keyboard and screen reader accessible
              separatedPanel.iframeRenderer.iframe.hide();
          }, "collapseFrame");
          separatedPanel.slidingPanel.events.afterPanelShow.addListener(function () {
              separatedPanel.iframeRenderer.iframe.show();
              separatedPanel.locate("reset").show();
          }, "openPanel");
          separatedPanel.slidingPanel.events.onPanelHide.addListener(function () {
              separatedPanel.locate("reset").hide();
          }, "hideReset");
      };
  
      // Replace the standard animator since we don't want the panel to become hidden
      // (potential cause of jumping)
      fluid.prefs.separatedPanel.hidePanel = function (panel, iframe, callback) {
          iframe.clearQueue(); // FLUID-5334: clear the animation queue
          $(panel).animate({height: 0}, {duration: 400, complete: callback});
      };
  
      // no activity - the kickback to the updateView listener will automatically trigger the
      // DOMChangeListener above. This ordering is preferable to avoid causing the animation to
      // jump by refreshing the view inside the iframe
      fluid.prefs.separatedPanel.showPanel = function (panel, callback) {
          // A bizarre race condition has emerged under FF where the iframe held within the panel does not
          // react synchronously to being shown
          fluid.invokeLater(callback);
      };
  
      /**
       * FLUID-5926: Some of our users have asked for ways to improve the initial page load
       * performance when using the separated panel prefs editor / UI Options. One option,
       * provided here, is to implement a scheme for lazy loading the instantiation of the
       * prefs editor, only instantiating enough of the workflow to allow display the
       * sliding panel tab.
       *
       * fluid.prefs.separatedPanel.lazyLoad modifies the typical separatedPanel workflow
       * by delaying the instantiation and loading of resources for the prefs editor until
       * the first time it is opened.
       *
       * Lazy Load Workflow:
       *
       * - On instantiation of the prefsEditorLoader only the messageLoader and slidingPanel are instantiated
       * - On instantiation, the messageLoader only loads preLoadResources, these are the messages required by
       *   the slidingPanel. The remaining message bundles will not be loaded until the "onLazyLoad" event is fired.
       * - After the preLoadResources have been loaded, the onPrefsEditorMessagesPreloaded event is fired, and triggers the
       *   sliding panel to instantiate.
       * - When a user opens the separated panel prefs editor / UI Options, it checks to see if the prefs editor has been
       *   instantiated. If it hasn't, a listener is temporarily bound to the onReady event, which gets fired
       *   after the prefs editor is ready. This is used to continue the process of opening the sliding panel for the first time.
       *   Additionally the onLazyLoad event is fired, which kicks off the remainder of the instantiation process.
       * - onLazyLoad triggers the templateLoader to fetch all of the templates and the messageLoader to fetch the remaining
       *   message bundles. From here the standard instantiation workflow takes place.
       */
      fluid.defaults("fluid.prefs.separatedPanel.lazyLoad", {
          events: {
              onLazyLoad: null,
              onPrefsEditorMessagesPreloaded: null,
              onCreateSlidingPanelReady: {
                  events: {
                      onPrefsEditorMessagesLoaded: "onPrefsEditorMessagesPreloaded"
                  }
              },
              templatesAndIframeReady: {
                  events: {
                      onLazyLoad: "onLazyLoad"
                  }
              }
          },
          components: {
              templateLoader: {
                  createOnEvent: "onLazyLoad"
              },
              messageLoader: {
                  options: {
                      events: {
                          onResourcesPreloaded: "{separatedPanel}.events.onPrefsEditorMessagesPreloaded"
                      },
                      preloadResources: "prefsEditor",
                      listeners: {
                          "onCreate.loadResources": {
                              listener: "fluid.prefs.separatedPanel.lazyLoad.preloadResources",
                              args: ["{that}", {expander: {func: "{that}.resolveResources"}}, "{that}.options.preloadResources"]
                          },
                          "{separatedPanel}.events.onLazyLoad": {
                              listener: "fluid.resourceLoader.loadResources",
                              args: ["{messageLoader}", {expander: {func: "{messageLoader}.resolveResources"}}]
                          }
                      }
                  }
              },
              slidingPanel: {
                  options: {
                      invokers: {
                          operateShow: {
                              funcName: "fluid.prefs.separatedPanel.lazyLoad.showPanel",
                              args: ["{separatedPanel}", "{that}.events.afterPanelShow.fire"]
                          }
                      }
                  }
              }
          }
      });
  
      fluid.prefs.separatedPanel.lazyLoad.showPanel = function (separatedPanel, callback) {
          if (separatedPanel.prefsEditor) {
              fluid.invokeLater(callback);
          } else {
              separatedPanel.events.onReady.addListener(function (that) {
                  that.events.onReady.removeListener("showPanelCallBack");
                  fluid.invokeLater(callback);
              }, "showPanelCallBack");
              separatedPanel.events.onLazyLoad.fire();
          }
  
      };
  
      /**
       * Used to override the standard "onCreate.loadResources" listener for fluid.resourceLoader component,
       * allowing for pre-loading of a subset of resources. This is required for the lazyLoading workflow
       * for the "fluid.prefs.separatedPanel.lazyLoad".
       *
       * @param {Object} that - the component
       * @param {Object} resource - all of the resourceSpecs to load, including preload and others.
       *                            see: fluid.fetchResources
       * @param {Array/String} toPreload - a String or an Array of Strings corresponding to the names
       *                                   of the resources, supplied in the resource argument, that
       *                                   should be loaded. Only these resources will be loaded.
       */
      fluid.prefs.separatedPanel.lazyLoad.preloadResources = function (that, resources, toPreload) {
          toPreload = fluid.makeArray(toPreload);
          var preloadResources = {};
  
          fluid.each(toPreload, function (resourceName) {
              preloadResources[resourceName] = resources[resourceName];
          });
  
          // This portion of code was copied from fluid.resourceLoader.loadResources
          // and will likely need to track any changes made there.
          fluid.fetchResources(preloadResources, function () {
              that.resources = preloadResources;
              that.events.onResourcesPreloaded.fire(preloadResources);
          });
      };
  
  })(jQuery, fluid_3_0_0);
  