
//
// Copyright 2011, Kristian Dalgård, Aarhus - http://variousproductions.dk
//
// Dette framework er rygradden i Flexidansk-applikationen og bør ses som en lukket enhed.
// Frameworket gør brug af avanceret funktionalitet i jQuery (http://jquery.com).
// 
// ADVARSEL: Ændring af frameworket kan medføre utilsigtede bivirkninger - ændringer af
// applikationen samt tilføjelse af nye sider og ny funktionalitet bør finde sted i modulerne
//
// For mere information om applikationen læs Teknisk_information.pdf
//



//
// Definerer det globale objekt for applikationen
//

var Flexidansk = {
  
  // Aktiverer frameworket
  init: function () {
    $(window).hashchange(Flexidansk.state.update);
    
    Flexidansk.build();
    
    $.getScript("locales/locales_config.jsonp")
      .pipe(function () { return Flexidansk.locales.change(false); })
      .then(function () {
        Flexidansk.locales.translate();
        
        $(window).hashchange();
      });
  },
  
  // Samler funktioner til styring af oversættelser (samt indeholder oversættelserne)
  locales: {
    
    // (async) Køres af config-jsonp - opbygger sprog-select
    config: function (new_config) {
      var language_sel = $("#language").empty(),
          options = [];
      
      this.primary_code = new_config.primary_code;
      
      $.each(new_config.languages, function (index, elem) {
        options.push('<option value="' + index + '" dir="' + elem.dir + '">' + elem.local + '</option>');
      });
      
      language_sel
        .append(options.join(""))
        .find("option[value='" + new_config.primary_code + "']").prop("selected", true).end()
        .trigger("update");
    },
    
    // (promise) Skifter sprog ved at hente nye sprog-jsonp
    change: function (lang_code) {
      var locales = this;
      lang_code = lang_code || ((locales.current) ? locales.current.lang_code : locales.primary_code);
      
      if (!locales.current || (locales.current && lang_code !== locales.current.lang_code)) {
        var deferred = locales.get(lang_code);
        
        deferred = deferred.pipe(function () {
          var promises = [];
          
          if (locales.current) {
            $.each(Flexidansk.modules, function (key, module) {
              if (module.name) promises.push(locales.get(lang_code, module.name));
            });
          }
          
          return $.when.apply($, promises);
        });
        
        return deferred;
      }
    },
    
    // (promise) Henter nye sprog-jsonp
    get: function (lang_code, module_name) {
      var locales = this;
      
      lang_code = lang_code || ((locales.current) ? locales.current.lang_code : locales.primary_code);
      
      var url = ((module_name) ? "modules/" + module_name + "/locales/" + module_name : "locales/flexidansk") + "_" + lang_code + ".jsonp";
      
      if (module_name) {
        return $.ajax({
          "url": url,
          "dataType": "script",
          "global": false
        }).pipe(null, function () { return $.Deferred().resolve(); });
      }
      else { return $.getScript(url); }
    },
    
    // (async) Køres af nye sprog-jsonp - indlæser oversættelsen med primærsproget som fallback
    load: function (new_locale) {
      var locales = this;
      
      if (!new_locale.is_fragment) {
        if (new_locale.lang_code === locales.primary_code) {
          locales.primary = $.extend({}, new_locale);
          locales.current = $.extend({}, new_locale);
        }
        else locales.current = $.extend(true, {}, locales.primary, new_locale);
      }
      else {
        delete new_locale.lang_code;
        delete new_locale.language;
        
        if (new_locale.lang_code === locales.primary_code) $.extend(true, locales.primary, new_locale);
        
        $.extend(true, locales.current, new_locale);
      }
      
      delete new_locale;
    },
    
    // Oversætter elementer med data-tl-attribut
    translate: function (elems) {
      if (!this.current) return;
      
      var body = $("body").addClass("loading"),
          is_elems = elems instanceof jQuery;
      
      if (!is_elems) {
        elems = body;
        
        $.each(Flexidansk.modules, function (key, module) {
          if (module.name) {
            if (module.elements) {
              $.each(module.elements, function (key, element) {
                if (!element.insertInto) elems = elems.add(element.contents);
              });
            }
          }
        });
        
        var doc_elem = $(document.documentElement),
            new_dir = this.current.language.dir;
        
        doc_elem
          .attr("lang", this.current.lang_code)
          .attr("dir", new_dir);
        
        if ($.cookie("state") && this.current.lang_code !== this.primary_code) Flexidansk.state.cookieParam("lang", this.current.lang_code);
      }
      
      var translation = this.current.translation,
          trans_elems = elems.find("[data-tl]").add(elems.filter("[data-tl]"));
      
      trans_elems.each(function () {
        var self = $(this),
            handle = self.attr("data-tl"),
            suffix = self.attr("data-tl-suffix"),
            trans = translation[handle];
            
        if (trans) {
          $.each(trans, function (key, elem) {
            if (key === "text") self.html(elem + (suffix || ""));
            else if (key === "mouseover") self.attr("title", elem);
            else self.attr(key, elem);
          });
        }
      });
      
      elems.find("select:has(option[data-tl])").trigger("update");
      
      if (elems.find("ul").add(elems.filter("ul")).parent("#navbar").length) {
        $("#navbar").children("ul")
          .trigger("adjust")
          .filter(".current").find("li.selected").first().trigger("moveArrow");
      }
      
      body.removeClass("loading");
    }
    
  },
  // End locales
  
  // Samler funktioner til styring af sidens tilstand
  state: {
    
    // Sekvens af state-typer i hash
    sequence: ["module", "page", "subpage", "step", "params"],
    
    // Sætter en ny location.hash hvorved sidens tilstand opdateres
    change: function (new_state) {
      var body_state = this.getBodyState(),
          hash_state = {},
          missing = [],
          has_new,
          end_new;
      
      $.each(this.sequence, function (index, type) {
        if (type === "params") {
          var hash_params = $.extend(true, {}, body_state.params, new_state.params);
          if (!$.isEmptyObject(hash_params)) hash_state[type] = hash_params;
        }
        else {
          var new_value = new_state[type],
              new_is_present = (typeof new_value !== "undefined" && new_value !== false),
              body_value = body_state[type];
          
          if (!has_new) {
            if (new_is_present) {
              has_new = true;
              
              $.each(missing, function (index, value) {
                hash_state[value] = "";
              });
              
              hash_state[type] = new_value;
            }
            else if (body_value) hash_state[type] = body_value;
            else missing.push(type);
          }
          else if (!end_new) {
            if (!new_is_present) end_new = true;
            else hash_state[type] = new_value;
          }
        }
      });
      
      this.setHashState(hash_state);
    },
    
    // Opdaterer sidens tilstand ved hashchange
    update: function () {
      var deferred = $.Deferred().resolve(),
          body_state = Flexidansk.state.getBodyState(),
          hash_state = Flexidansk.state.getHashState();
      
      hash_state.module = hash_state.module || Flexidansk.modules.defaut;
      hash_state.page = hash_state.page || "";
      
      if (hash_state.params && Flexidansk.state.toggleSerialized(hash_state.params) !== Flexidansk.state.toggleSerialized(body_state.params)) {
        var params = hash_state.params;
        
        if (params.sprog && params.sprog !== Flexidansk.locales.current.lang_code) {
          deferred = deferred.pipe(function () { return Flexidansk.locales.change(params.sprog); });
          deferred = deferred.pipe(function () {
            Flexidansk.locales.translate();
            $("#language").val(params.sprog).trigger("sync");
          });
        }
      }
      
      if (hash_state.module !== body_state.module) {
        var current_module = body_state.module;
        
        deferred = deferred.pipe(function () { return Flexidansk.modules.get(hash_state.module); });
        
        if (current_module) deferred = deferred.pipe(function () { return Flexidansk.modules.uninvoke(current_module); });
        
        deferred = deferred.pipe(function () { return Flexidansk.modules.invoke(hash_state.module); });
        
        body_state = { "params": body_state.params };
      }
      
      if (hash_state.page !== body_state.page) {
        deferred = deferred.pipe(function () {
          var module = Flexidansk.modules[hash_state.module],
              deferred = $.Deferred().resolve();
          
          if (typeof module.changePage === "function") deferred = deferred.pipe(function () { return module.changePage(hash_state); });
          
          deferred = deferred.pipe(function () {
            if (!module.pages) return;
            
            var active_link = $("#navbar").find("[data-clicked]"),
                hash_page = hash_state.page,
                new_page,
                title;
            
            if (hash_page && hash_page in module.pages) new_page = hash_page;
            else {
              $.each(module.pages, function (key, page) {
                if (page.defaut) {
                  new_page = key;
                  return false;
                }
              });
            }
            
            if (new_page) {
              var page = module.pages[new_page];
              
              title = page.title;
              
              if (module.menu) {
                if (!active_link.length || !$.contains(module.menu[0], active_link[0])) {
                  var search_array = [
                    ((page.defaut) ? "a[data-page=''], " : "") + "a[data-page='" + new_page + "']",
                    "select[data-page='" + new_page + "']",
                    "select:has([data-page='']):has(option[value='" + new_page + "'])",
                    "select:has([data-page='']):has(option[value=''])"
                  ];
                  
                  $.each(search_array, function (index, value) {
                    active_link = module.menu.find(value).first();
                    
                    if (active_link.length) {
                      if (index === 1) active_link.find("option:first").prop("selected", true).end().trigger("sync");
                      else if (index === 2) active_link.find("option[value='" + new_page + "']").first().prop("selected", true).end().end().trigger("sync");
                      else if (index === 3) active_link.find("option[value='']").first().prop("selected", true).end().end().trigger("sync");
                      
                      return false;
                    }
                    else if (index === 2 && !page.defaut) return false;
                  });
                }
                
                if (active_link.length) {
                  var parent_li = active_link.closest("li"),
                      prev_selected = module.menu.find("li.selected");
                  
                  Flexidansk.state.updateMenu(module.menu, active_link);
                }
              }
              
              Flexidansk.state.changePage(page.contents);
              
              active_link.removeAttr("data-clicked");
            }
            
            title = title || module.title || Flexidansk.modules[Flexidansk.modules.defaut].title;
            document.title = title;
            $("#title").text(title);
          }, function () { return $.Deferred().resolve(); });
          
          return deferred;
        });
        
        body_state = { "params": body_state.params };
      }
      
      // Kører eventuelle funktioner i modulet efter hinanden (changeSubpage, changeStep og changeParams)
      $.each(Flexidansk.state.sequence, function (index, type) {
        if (index > 1) {
          var body_value = body_state[type],
              hash_value = hash_state[type],
              is_new = (type === "params") ? Flexidansk.state.toggleSerialized(hash_value) !== Flexidansk.state.toggleSerialized(body_value) : hash_value !== body_value;
          
          if (is_new) {
            deferred = deferred.pipe(function () {
              var module = Flexidansk.modules[hash_state.module],
                  fn_name = "change" + type.substr(0, 1).toUpperCase() + type.substr(1);
              
              if (typeof module[fn_name] === "function") return module[fn_name](hash_state);
            });
            
            body_state = { "params": body_state.params };
          }
        }
      });
      
      Flexidansk.state.setBodyState(hash_state);
    },
    
    // Returnerer state-objekt ud fra informationen i body (aktuel state)
    getBodyState: function () {
      var self = this,
          body = $("body"),
          body_state = {};
      
      $.each(self.sequence, function (index, type) {
        var value = body.attr("data-" + type);
        if (typeof value !== "undefined" && value !== false) body_state[type] = (type === "params") ? self.toggleSerialized(value) : value;
      });
      
      return body_state;
    },
    
    // Påfører informationen i state-objekt til body
    setBodyState: function (body_state) {
      var self = this,
          body = $("body");
      
      $.each(self.sequence, function (index, type) {
        body.removeAttr("data-" + type);
        
        var value = body_state[type];
        if (typeof value !== "undefined") body.attr("data-" + type, (type === "params") ? self.toggleSerialized(value) : value);
      });
    },
    
    // Returnerer state-objekt ud fra hash-strengen
    getHashState: function () {
      var self = this,
          hash_state = {},
          hash_split = location.hash.split("#").slice(-1).join("").split("?"),
          hash_path = hash_split[0].split("/").slice(1, -1);
      
      $.each(self.sequence, function (index, type) {
        hash_state[type] = (type === "params") ? self.toggleSerialized(hash_split[1]) : hash_path[index];
      });
      
      return hash_state;
    },
    
    // Påfører informationen i state-objekt til hash-strengen - sidens tilstand opdateres
    setHashState: function (hash_state) {
      var self = this,
          result = [];
      
      $.each(self.sequence, function (index, type) {
        var value = hash_state[type];
        if (value) result.push((type === "params") ? "?" + self.toggleSerialized(value) : value);
        else if (type === "params") result.push("");
      });
      
      if (result[0]) location.hash = "/" + result.join("/");
    },
    
    // Laver state-objekt ud fra informationen i et element (typisk et link) og kører state.change
    parseLink: function () {
      var self = $(this),
          sequence = Flexidansk.state.sequence,
          has_state = false,
          new_state;
      
      $.each(sequence, function (index, type) {
        var self_attr = self.attr("data-" + type);
        if (typeof self_attr !== "undefined" && self_attr !== false) {
          has_state = true;
          return false;
        }
      });
      
      if (has_state) {
        var is_select = self.is("select");
        
        new_state = {};
        
        $.each(sequence, function (index, type) {
          var value = self.attr("data-" + type);
          
          if (typeof value !== "undefined" && value !== false) {
            if (type === "params") value = (is_select && value === "") ? Flexidansk.state.toggleSerialized(self.val()) : (is_select && value) ? Flexidansk.state.toggleSerialized(value + "=" + self.val()) : Flexidansk.state.toggleSerialized(value);
            else if (is_select && value === "") value = self.val();
            
            new_state[type] = value;
            
            if (type === "module" && value === $("body").attr("data-module") && self.parent("li.main").length) return false;
          }
        });
        
        if ($.contains($("#navbar")[0], this)) {
          if (!self.closest("li").hasClass("selected") || is_select) {
            self.attr("data-clicked", true);
            
            Flexidansk.state.change(new_state);
          }
        }
        else Flexidansk.state.change(new_state);
      }
    },
    
    // Fra param-streng til param-objekt eller omvendt (afhænger af input)
    toggleSerialized: function (params) {
      if (typeof params === "string") {
        params = params.split("?").slice(-1).join("");
        
        if (!params.split("=")[1]) return;
        
        var return_obj = {};
        
        $.each(params.split("&"), function (index, value) {
          var key_val = value.split("=");
          return_obj[key_val[0]] = key_val[1];
        });
        
        return return_obj;
      }
      else if (params !== null && typeof params === "object") {
        var return_arr = [];
        
        $.each(params, function (index, value) {
          return_arr.push(index + "=" + value);
        });
        
        return return_arr.join("&");
      }
    },
    
    // Returnerer, tilføjer eller sletter param i state-cookie
    cookieParam: function (name, value) {
      var cookie_obj = this.toggleSerialized($.cookie("state")) || {};
      
      if (typeof value === "undefined") {
        if (name in cookie_obj) return cookie_obj[name];
      }
      else {
        if (value === null && name in cookie_obj) delete cookie_obj[name];
        else cookie_obj[name] = value;
        
        $.cookie("state", this.toggleSerialized(cookie_obj), { "expires": 360 });
      }
    },
    
    // Skifter fokus i menuen
    updateMenu: function (menu, active_link, do_reset) {
      var parent_li = active_link.closest("li"),
          other_selects = parent_li.siblings().find("select");
      
      menu.children("li.selected").removeClass("selected");
      
      if (do_reset !== false) other_selects.val(null).trigger("sync");
      
      parent_li.addClass("selected");
      parent_li.trigger("moveArrow");
    },
    
    // Skifter side ved slide frem eller tilbage
    changePage: function (page) {
      if (!page.hasClass("current")) {
        $("#pages").children("section.current").removeClass("current");
        
        page.addClass("current");
      }
    }
    
  },
  // End state
  
  // Samler funktioner til styring af moduler (samt indeholder selve modulerne)
  modules: {
  
    // Modulet der indlæses som standard
    defaut: "forsiden",
    
    // (promise) Henter nyt modul
    get: function (module_name) {
      if (!(module_name in this)) {
        var module_request = $.getScript("modules/" + module_name + "/" + module_name + ".js");
        
        module_request = module_request.pipe(function () {
          if (module_name in Flexidansk.modules) return Flexidansk.modules.resolve(module_name);
          else return $.Deferred.reject();
        });
        
        module_request = module_request.pipe(function () { return Flexidansk.modules.unpack(module_name); });
        
        return module_request;
      }
    },
    
    // (async) Indsætter modulet i applikationen
    load: function (module) {
      this[module.name] = module;
    },
    
    // (promise) Loader dependencies
    resolve: function (module_name) {
      var dependencies = this[module_name].dependencies;
      
      if (dependencies) {
        if (typeof dependencies === "string") dependencies = [dependencies];
        
        var deferred = $.Deferred().resolve();
        
        $.each(dependencies, function (index, value) {
          deferred = deferred.pipe(function () { return Flexidansk.modules.get(value); });
        });
        
        return deferred;
      }
    },
    
    // (promise) Kører eventuel pre-funktion, henter modulets sprogfiler, udpakker modulet og kører en eventuel init-funktion
    unpack: function (module_name) {
      var module = this[module_name],
          deferred = $.Deferred().resolve(),
          promises = [];
      
      if (typeof module.pre === "function") deferred = deferred.pipe(function () { return module.pre(); });
      
      if (module.images) {
        if (typeof module.images === "string") module.images = [module.images];
        
        $.each(module.images, function (index, value) {
          $.preloadImages("modules/" + module.name + "/images/" + value);
        });
      }
      
      if (module.stylesheets) {
        if (typeof module.stylesheets === "string") module.stylesheets = [module.stylesheets];
        
        $.each(module.stylesheets, function (index, value) {
          var style_request = $.ajax({
            "url": "modules/" + module.name + "/css/" + value,
            "dataType": "text"
          });
          
          style_request = style_request.pipe(function (response) {
            var new_style = $('<style>');
            
            new_style
              .attr("type", "text/css")
              .addClass("mod-" + module.name)
              .appendTo("head");
            
            if (new_style[0].styleSheet) new_style[0].styleSheet.cssText = response;
            else new_style.text(response);
          });
          
          promises.push(style_request);
        });
      }
      
      var new_content = $(),
          element_types = ["menu", "pages", "elements"];
      
      $.each(element_types, function (index, type) {
        var elements = (type === "menu") ? [module[type]] : module[type];
        
        if (elements) {
          $.each(elements, function (key, element) {
            var element_request = $.ajax({
              "url": "modules/" + module.name + "/html/" + ((type === "menu") ? element : element.contents),
              "dataType": "text"
            });
            
            element_request = element_request.pipe(function (response) {
              var new_elem = $(response.replace(/[\n|\r]+\s*/g, "")).addClass("mod-" + module.name);
              
              if (type === "menu") module[type] = new_elem;
              else element.contents = new_elem;
              
              new_content = new_content.add((type === "menu") ? module[type] : element.contents);
            });
            
            promises.push(element_request);
          });
        }
      });
      
      var locale_request = Flexidansk.locales.get(Flexidansk.locales.primary_code, module.name);
      
      if (Flexidansk.locales.current.lang_code !== Flexidansk.locales.primary_code) {
        locale_request = locale_request.pipe(function () { return Flexidansk.locales.get(false, module.name); });
      }
      
      promises.push(locale_request);
      
      deferred = deferred.pipe(function () {
        return $.when.apply($, promises);
      });
      
      deferred = deferred.pipe(function () {
        Flexidansk.build(new_content);
        Flexidansk.locales.translate(new_content);
        
        if (module.menu) {
          module.menu
            .appendTo("#navbar")
            .trigger("adjust");
        }
        
        if (module.pages) {
          $.each(module.pages, function (key, page) {
            page.contents
              .attr("data-name", key)
              .appendTo("#pages");
          });
        }
        
        if (module.elements) {
          $.each(module.elements, function (key, element) {
            if (element.insertInto) {
              if (element.method === "prepend") element.contents.prependTo(element.insertInto);
              else element.contents.appendTo(element.insertInto);
            }
          });
        }
      });
      
      if (module.global && module.events) deferred = deferred.pipe(function () { Flexidansk.modules.toggleEvents(module); });
      
      if (typeof module.init === "function") deferred = deferred.pipe(function () { return module.init(); });
      
      return deferred;
    },
    
    // (promise) Aktiverer modulets events og menu samt kører eventuel invoke-funktion
    invoke: function (module_name) {
      var module = this[module_name],
          navbar = $("#navbar");
      
      if (!module.global && module.events) this.toggleEvents(module);
      
      if (module.menu) {
        navbar.removeClass("hidden");
        
        navbar.children("ul").not(module.menu)
          .removeClass("current parent")
          .find("li.selected, [data-clicked]").removeClass("selected").removeAttr("data-clicked");
        
        module.menu.removeClass("parent").addClass("current");
        
        var addParent = function (menu) {
          var parent_name = menu.attr("data-parent");
          
          if (parent_name) {
            var parent_menu = navbar.children("ul.mod-" + parent_name);
            
            parent_menu
              .addClass("parent")
              .prependTo(parent_menu.parent());
            
            addParent(parent_menu);
          }
        };
        
        addParent(module.menu);
      }
      else navbar.addClass("hidden");
      
      if (module.pages) {
        $.each(module.pages, function (key, page) {
          if (page.fixed) page.contents.addClass("fixed");
        });
      }
      
      if (typeof module.invoke === "function") return module.invoke();
    },
    
    // (promise) Kører eventuel uninvoke-funktion, deaktiverer modulets events og skjuler dets elementer
    uninvoke: function (module_name) {
      var module = this[module_name],
          deferred = $.Deferred().resolve();
      
      if (typeof module.uninvoke === "function") deferred = deferred.pipe(function () { return module.uninvoke(); });
      
      deferred = deferred.pipe(function () {
        if (module.pages) {
          $.each(module.pages, function (key, page) {
            if (page.fixed) page.contents.removeClass("fixed");
          });
        }
        
        if (!module.global && module.events) Flexidansk.modules.toggleEvents(module, false);
      });
      
      return deferred;
    },
    
    // Fjerner modulets elementer og sletter modulet
    unload: function (module_name) {
      var module = this[module_name];
      
      if (!module.global) {
        var element_types = ["menu", "pages", "elements"];
        
        $.each(element_types, function (index, type) {
          var elements = (type === "menu") ? [module[type]] : module[type];
          
          if (elements) {
            $.each(elements, function (key, element) {
              if (type === "menu") element.remove();
              else element.contents.remove();
            });
          }
        });
        
        delete this[module_name];
      }
    },
    
    // Slår et moduls events til eller fra
    toggleEvents: function (module, events_on) {
      $.each(module.events, function (key, event) {
        if (events_on !== false) {
          if (event.delegateTo) $(event.attachTo).delegate(event.delegateTo, event.type + "." + module.name, event.handler);
          else if (event.attachTo) $(event.attachTo).bind(event.type + "." + module.name, event.handler)
        }
        else {
          if (event.delegateTo) $(event.attachTo).undelegate(event.delegateTo, event.type + "." + module.name, event.handler);
          else if (event.attachTo) $(event.attachTo).unbind(event.type + "." + module.name, event.handler);
        }
      });
    }
    
  },
  // End modules
  
  // Opbygger siden eller nye elementer
  build: function (elems) {
    if (!elems) {
      elems = $("body");
      
      $(".crawlers").remove();
      
      $.ajaxSetup({ cache: false });
      
      elems.ajaxStart(function () { $(this).addClass("loading"); });
      elems.ajaxStop(function () { $(this).removeClass("loading"); });
      elems.ajaxError(function (event, jqxhr) {
        if (jqxhr.status === 403) {
          $("body").removeAttr("data-module");
          Flexidansk.state.change({ module: Flexidansk.modules.defaut });
        }
        else $(this).addClass((jqxhr.statusText === "timeout") ? "timeout" : "error");
      });
      
      elems.delegate("aside.modal button.close", clickEvent, function () {
        var self = $(this);
        
        self.closest("aside.modal").removeClass("active");
        
        if (self.closest("#loading").length) $("body").removeClass("error timeout");
      });
      
      $(document).keydown(function (event) {
        var active_modals = $("aside.modal").filter(function () { return $(this).css("display") === "block"; });
        
        if (event.keyCode === 13 && active_modals.length) {
          event.stopPropagation();
          active_modals.find("button.close").click();
          return false;
        }
      });
      
      elems.delegate("a", clickEvent + ".state", Flexidansk.state.parseLink);
      elems.delegate("select", "change.state", Flexidansk.state.parseLink);
      
      var navbar = $("#navbar").disableSelection(),
          arrow = $("#navbar").find("div.arrow");
      
      navbar.delegate("#navbar > ul", "adjust", this.adjustMenu);
      navbar.children("ul").trigger("adjust");
      
      navbar.delegate("#navbar > ul > li", "moveArrow", { "arrow": arrow, "arrow_width": arrow.width(), "navbar_padding": parseInt(navbar.css("padding-left")) }, this.moveArrow);
    }
    
    elems.find("form").add(elems.filter("form")).bind("submit", false);
    
    elems.find("input").keydown(function (event) {
      if (event.keyCode === 13) {
        $(this).blur().closest("form").submit();
        return false;
      }
    });
    
    elems.find("select").add(elems.filter("select")).each(this.buildSelect);
    
    elems.find("aside.modal").add(elems.filter("aside.modal")).disableSelection();
  },
  
  // Opbygger custom select widgets
  buildSelect: function () {
    var select = $(this),
        select_parent = select.parent();
    
    if (select.parent().is("div.select")) {
      select_parent
        .after(select)
        .remove();
    }
    
    var options = select.find("option"),
        new_div = $('<div class="select"><span></span><ul></ul></div>').disableSelection(),
        new_a = new_div.find("span"),
        new_ul = new_div.find("ul");
    
    select.bind("update.select", function () {
      new_div.addClass(select.attr("class"));
      
      var options = $(this).find("option"),
          new_lis = [];
      
      options.each(function () {
        var option = $(this);
        new_lis.push('<li' + ((option.attr("dir")) ? ' dir="' + option.attr("dir") + '"' : '') + '>' + option.text() + '</li>');
      });
      
      new_ul.empty().append(new_lis.join(""));
      
      if (options.first().attr("value") === "") new_ul.addClass("has_label");
      else new_ul.removeClass("has_label");
      
      $(this).trigger("sync");
    });
    
    select.bind("sync.select", function () {
      var new_selected = new_ul.find("li").eq($(this).find("option:selected").index());
      if (!new_selected.length) new_selected = new_ul.find("li").first();
      
      new_selected
        .addClass("selected")
        .siblings("li.selected").removeClass("selected");
      
      new_a.text((new_selected.length) ? new_selected.text() : new_ul.find("li").first().text());
    });
    
    select.trigger("update");
    
    new_a.bind(mousedownEvent + ".select", function (event) {
      event.stopPropagation();
      
      var parent_div = $(this).parent();
      
      parent_div.toggleClass("active");
      
      $("div.select.active").not(parent_div).removeClass("active");
    });
    
    new_ul.bind(mousedownEvent + ".select", function (event) { event.stopPropagation(); });
    
    new_ul.delegate("li", mousedownEvent + ".select", function () {
      var self = $(this),
          parent_div = self.closest("div"),
          has_label = self.parent().hasClass("has_label");
      
      if (!has_label || (has_label && self.index())) {
        var select_option = parent_div.find("option").eq(self.index());
        
        if (!select_option.is(":selected")) {
          select_option.prop("selected", true);
          parent_div.find("select").change();
        }
      }
      
      parent_div.removeClass("active");
    });
    
    select.bind("change.select", function () {
      var self = $(this),
          selected_option = self.find("option:selected"),
          parent_div = self.closest("div"),
          selected_li = parent_div.find("li").eq(selected_option.index());
      
      selected_li
        .siblings("li.selected").removeClass("selected").end()
        .addClass("selected");
      
      parent_div.find("span").text(selected_li.text());
    });
    
    $(document).bind(mousedownEvent + ".select", function () {
      new_div.removeClass("active");
    });
    
    new_div.insertAfter(select).append(select);
  },
  
  // Indstiller bredden på menu-items (giver plads til fed skrift)
  adjustMenu: function () {
    $(this).children("li").each(function () {
      var self = $(this);
      
      self
        .addClass("adjust")
        .reflow()
        .width(self.width() + 30)
        .removeClass("adjust");
    });
  },
  
  // Flytter navbar-pilen
  moveArrow: function (event) {
    var self = $(this),
        is_rtl = Flexidansk.locales.current.language.dir === "rtl",
        arrow = event.data.arrow,
        arrow_width = event.data.arrow_width,
        navbar_padding = event.data.navbar_padding,
        item = self.children("a").first();
    
    if (!item.length) item = self;
    
    var menu = self.closest("ul"),
        offset = navbar_padding + ((item.outerWidth() - arrow_width) / 2) - 1,
        position = (!is_rtl) ? { "left": Math.round(item.offset().left - menu.offset().left + offset) } : { "right": Math.round((menu.offset().left + menu.outerWidth()) - (item.offset().left + item.outerWidth()) + offset) };
    
    arrow.css(position);
  }
  
};


//
// Sætter det hele i gang (jQuerys onload handler)
//

$(Flexidansk.init);


