<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">var Pagination = Class.create({
  CLASSDEF: {
      name: 'Pagination'
  },
  
  initialize: function PG_initialize(parent, divId, callback, showEntriesInfo, entryName, pluralizedEntryName, prevLinkName, nextLinkName, showPerPage) {
    this.parent = parent;
    this.container = (typeof divId == "string") ? $(divId) : divId;
    this.totalPages = 0;
    this.totalEntries = 0;
    this.perPage = 0;
    this.currentPage = 1;
    this.offset = 0;
    this.length = 0;
    this.callback = callback;
    this.showEntriesInfo = showEntriesInfo;
    this.showPerPage = (showPerPage) ? true : false;
    this.entryName = (entryName) ? entryName : dnMl("item");
    this.pluralizedEntryName = (pluralizedEntryName) ? pluralizedEntryName : dnMl("items");
    this.prevLinkName = (prevLinkName) ? prevLinkName : dnMl("&amp;laquo; Previous");
    this.nextLinkName = (nextLinkName) ? nextLinkName : dnMl("Next &amp;raquo;");
    this.id = nextPaginationId;
    nextPaginationId ++;
    
    this.update();
  },
  
  reset: function PG_reset(totalPages, totalEntries, perPage, currentPage, offset, length) {
    this.setTotalPages(totalPages);
    this.setTotalEntries(totalEntries);
    this.setPerPage(perPage);
    this.setCurrentPage(currentPage);
    this.setOffset(offset);
    this.setLength(length);
    this.update();
  },
  
  resetFromList: function(currentPage, list, perPage) {
    this.setTotalPages(Math.ceil(parseFloat(list.length) / parseFloat(perPage)));
    this.setTotalEntries(list.length);
    this.setPerPage(perPage);
    this.setCurrentPage(currentPage);
    this.setOffset((currentPage - 1) * perPage);
    var len = list.length - this.offset;
    if(len &gt; perPage) len = perPage;
    this.setLength(len);
    this.update();
    
    var items = [];
    for(var i=this.offset; i &lt; this.offset + this.length; i++) {
      items.push(list[i]);
    }
    return items;
  },
  
  
  
  hide: function PG_hide() {
    this.container.hide();
  },
  
  setTotalPages: function PG_setTotalPages(totalPages) {
    this.totalPages = (totalPages) ? totalPages : 0;
  },
  
  setTotalEntries: function PG_setTotalEntries(totalEntries) {
    this.totalEntries = (totalEntries) ? totalEntries : 0;
  },
  
  setPerPage: function PG_setPerPage(perPage) {
    this.perPage = (perPage) ? perPage : 0;
  },
  
  setCurrentPage: function PG_setCurrentPage(currentPage) {
    this.currentPage = (currentPage) ? currentPage : 1;
  },
  
  setOffset: function PG_setOffset(offset) {
    this.offset = (offset) ? offset : 0;
  },
  
  setLength: function PG_setLength(length) {
    this.length = (length) ? length : 0;
  },
  
  setEntryName: function PG_setEntryName(name) {
    this.entryName = name;
  },
  
  setPluralizedEntryName: function PG_setPluralizedEntryName(name) {
    this.pluralizedEntryName = name;
  },
  
  getTotalPages: function PG_getTotalPages() {
    return this.totalPages;
  },
  
  getTotalEntries: function PG_getTotalEntries() {
    return this.totalEntries;
  },
  
  getPerPage: function PG_getPerPage() {
    return this.perPage;
  },
  
  getCurrentPage: function PG_getCurrentPage() {
    return this.currentPage;
  },
  
  setPerPageSelection: function PG_setPerPageSelection() {
    var perPageEl = $('select_per_page_' + this.id);
    if (perPageEl) {
      for (var i = 0; i &lt; perPageEl.options.length; i++) {
        if (perPageEl.options[i].value == this.perPage) {
          perPageEl.selectedIndex = i;
          return true;
        }
      }  
    }
    return false;
  },

  changePerPage: function PG_changePerPage() {
    var perPageEl = $('select_per_page_' + this.id);
    if (perPageEl) {
      var newPerPage = parseInt(perPageEl.options[perPageEl.selectedIndex].value);
    }
    this.setPerPage(newPerPage);
    this.setCurrentPage(1);
    if (this.callback(this.parent, this.currentPage, this.perPage)) {
      this.update();
    }
    return false;
  },

  nextPage: function PG_nextPage() {
    if (this.totalPages &gt; this.currentPage) {
      if (this.callback(this.parent, this.currentPage + 1)) {
        this.currentPage += 1;
        this.update();
      }
    }
    return false;
  },
  
  prevPage: function PG_prevPage() {
    if (this.currentPage &gt; 1) {
      if (this.callback(this.parent, this.currentPage - 1)) {
        this.currentPage -= 1;
        this.update();
      }
    }
    return false;
  },
  
  toPage: function PG_toPage(page) {
    if (typeof page != "number") {
      var element = Event.element(page);
      page = parseInt(element.innerHTML);
    }
    if (page &gt; 0 &amp;&amp; page &lt;= this.totalPages) {
      if (this.callback(this.parent, page)) {
        this.currentPage = page;
        this.update();
      }
    }
    return false;
  },
  
  update: function PG_update() {
    if(this.container == null) return;
    if (this.totalPages == 0 || (this.totalPages == 1 &amp;&amp; !this.showEntriesInfo) ) {
      this.container.style.display = "none";
    } else {
      var clzPrefix = dnInDnm() ? 'dnm-' : '';
      
      var html = "";
      var links = {};
    
      // page entries info
      if (this.showEntriesInfo) {
        html += '&lt;span class="' + clzPrefix + 'page_entries_info"&gt;';
        if(this.showPerPage) {
          html += '&lt;span&gt;';
          html += dnMl(" Per Page ");
          html += '&lt;/span&gt;';
          html += '&lt;span class="select w_auto"&gt;&lt;select id="select_per_page_' + this.id + '" class="change_per_page ' + clzPrefix + ' pagination_' + this.id +'"&gt;';
          html += '&lt;option value="10"&gt;10&lt;/option&gt;';
          html += '&lt;option value="15"&gt;15&lt;/option&gt;';
          html += '&lt;option value="20"&gt;20&lt;/option&gt;';
          html += '&lt;option value="25"&gt;25&lt;/option&gt;';
          html += '&lt;option value="30"&gt;30&lt;/option&gt;';
          html += '&lt;option value="40"&gt;40&lt;/option&gt;';
          html += '&lt;option value="50"&gt;50&lt;/option&gt;';
          html += '&lt;option value="60"&gt;60&lt;/option&gt;';
          // html += '&lt;option value="100"&gt;100&lt;/option&gt;';
          html += '&lt;/select&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp';
        }
        if (this.totalPages &lt; 2) {
          switch(this.totalEntries) {
            case 0:
              html += dnMl("No %s found", this.pluralizedEntryName);
              break;
            case 1:
              html += dnMl("Displaying &lt;b&gt;1&lt;\/b&gt; %s", this.entryName);
              break;
            default:
              html += dnMl("Displaying &lt;b&gt;all %1s&lt;\/b&gt; %2s", [this.totalEntries, this.pluralizedEntryName]);
          }
        } else {
          html += dnMl("Displaying &lt;b&gt;%1s&lt;\/b&gt; to &lt;b&gt;%2s&lt;\/b&gt; of &lt;b&gt;%3s&lt;\/b&gt; %4s", [this.offset + 1, this.offset + this.length, this.totalEntries, this.pluralizedEntryName]);
        }
        html += '&lt;/span&gt;&lt;/span&gt;';
      }
      
      // prev link
      if (this.currentPage != 1) {
        html += '&lt;a rel="prev" class="' + clzPrefix + 'prev_page ' + clzPrefix + 'pagination_' + this.id + '" href="#" onclick="return false;"&gt;' + this.prevLinkName + '&lt;/a&gt;';
      } else {
        html += '&lt;span class="' + clzPrefix + 'disabled ' + clzPrefix + 'prev_page"&gt;' + this.prevLinkName + '&lt;/span&gt;';
      }
      
      // pages
      var startPage = (this.currentPage - 4 &lt; 1) ? 1 : this.currentPage - 4;
      var endPage = (startPage + 8 &gt; this.totalPages) ? this.totalPages : startPage + 8
      
      var preEndPage = (startPage - 1 &lt; 2) ? startPage - 1 : 2;
      for (var i=1; i&lt;=preEndPage; i++) {
        html += '&lt;a href="#" class="' + clzPrefix + 'pagination_' + this.id + '" onclick="return false;"&gt;' + i + '&lt;/a&gt;';
      }
      if (startPage &gt; 3) html += '&lt;span class="' + clzPrefix + 'gap"&gt;...&lt;/span&gt;';
      
      for (var i=startPage; i&lt;=endPage; i++) {
        if (i == this.currentPage) {
          html += '&lt;span class="' + clzPrefix + 'current"&gt;' + i + '&lt;/span&gt;';
        } else {
          html += '&lt;a href="#" class="' + clzPrefix + 'pagination_' + this.id + '" onclick="return false;"&gt;' + i + '&lt;/a&gt;';
        }
      }
      
      if (this.totalPages - endPage &gt; 2) html += '&lt;span class="' + clzPrefix + 'gap"&gt;...&lt;/span&gt;';
      startPage = (this.totalPages - 2 &gt; endPage) ? this.totalPages - 1 : endPage + 1;
      for (var i=startPage; i&lt;=this.totalPages; i++) {
        html += '&lt;a href="#" class="' + clzPrefix + 'pagination_' + this.id + '" onclick="return false;"&gt;' + i + '&lt;/a&gt;';
      }
      
      // next link
      if (this.currentPage != this.totalPages) {
        html += '&lt;a rel="next" class="' + clzPrefix + 'next_page ' + clzPrefix + 'pagination_' + this.id + '" href="#" onclick="return false;"&gt;' + this.nextLinkName + '&lt;/a&gt;';
      } else {
        html += '&lt;span class="' + clzPrefix + 'disabled ' + clzPrefix + 'next_page"&gt;' + this.nextLinkName + '&lt;/span&gt;';
      }
      this.container.innerHTML = html;
      this.container.style.display = "";

      this.setPerPageSelection();
      
      // bind events
      var self = this;

      $$('.' + clzPrefix + 'pagination_' + this.id).each(function(item) {
          if (item.hasClassName(clzPrefix + "change_per_page")) {
            Event.observe(item, "change", self.changePerPage.bindAsEventListener(self));
          } else if (item.hasClassName(clzPrefix + "prev_page")) {
            Event.observe(item, "click", self.prevPage.bindAsEventListener(self));
          } else if (item.hasClassName(clzPrefix + "next_page")) {
            Event.observe(item, "click", self.nextPage.bindAsEventListener(self));
          } else {
            Event.observe(item, "click", self.toPage.bindAsEventListener(self));
          }
      });
    }
  }
});

var nextPaginationId = 1;



var SPCategory = Class.create({
  CLASSDEF: {
    name: 'SPCategory'
  },
  
  initialize: function(manager, options) {
    this.categories = null;
    this.id = options.id;
    this.name = options.n;
    this.directProductCount = options.pc;
    this.descProductCount = options.dc;
    this.directDecoratableProductCount = options.dpc;
    this.descDecoratableProductCount = options.ddc;
    this.onlyBHAreasProductCount = options.obhac;
    this.pos = options.p;
    this.expanded = false;
    this.manager = manager;
    
    this.products = null;
  },
  
  compare: function(other) {
    return this.pos - other.pos;
  },
  
  resort: function() {
    if(this.categories != null) {
      this.categories.resort();
      for(var i=0; i &lt; this.categories.list.length; i++) {
        this.categories.list[i].resort();  
      }
    }
  },
  
  removeNonDec: function() {
    if(this.categories != null) {
      var filteredCats = new MapList(this);
      for(var i=0; i &lt; this.categories.list.length; i++) {
        var cat = this.categories.list[i];
        if(cat.descDecoratableProductCount &gt; 0) {
          filteredCats.add(cat);
          cat.removeNonDec();
        }
      }
      this.categories = filteredCats;
    }
  },
  
  removeDec: function() {
    if(this.categories != null) {
      var filteredCats = new MapList(this);
      for(var i=0; i &lt; this.categories.list.length; i++) {
        var cat = this.categories.list[i];
        if(cat.descDecoratableProductCount &gt; 0 &amp;&amp; cat.descDecoratableProductCount == cat.descProductCount) {
          cat.removeDec();
        } else {
          filteredCats.add(cat);
          cat.removeDec();
        }
      }
      this.categories = filteredCats;
    }
  },

  removeOnlyBHAreas: function() {
    if(this.categories != null) {
      var filteredCats = new MapList(this);
      for(var i=0; i &lt; this.categories.list.length; i++) {
        var cat = this.categories.list[i];
        if(cat.onlyBHAreasProductCount &gt; 0 &amp;&amp; cat.onlyBHAreasProductCount == cat.descProductCount) {
          cat.removeOnlyBHAreas();
        } else {
          filteredCats.add(cat);
          cat.removeOnlyBHAreas();
        }
      }
      this.categories = filteredCats;
    }
  },

  addCategory: function(cat) {
    if(this.categories == null) this.categories = new MapList(this);
    this.categories.add(cat);
    cat.parent = this;
  },
  
  registerProduct: function(prod) {
    if(this.products == null) {
      this.products = new MapList(this);
    }
    if(this.products.byId[prod.id] == null) {
      this.products.add(prod);
    }
    if(this.parent != null) {
      this.parent.registerProduct(prod);
    }
  },
  
  hasChildren: function() {
    return (this.categories != null &amp;&amp; this.descProductCount &gt; 0);
  },
  
  shouldRender: function() {
    if(this.manager.system || this.manager.includeEmpty) return true;
    return this.hasChildren();
  },
  
  shouldRenderChildren: function() {
    if(this.manager.system || this.manager.includeEmpty) return (this.categories != null);
    return this.hasChildren();
  },
  
  buildHierarchyHtml: function(buffer) {
    var expandClass = this.shouldRenderChildren() ? 'open' : 'null';
    
    var addHtml = '';
    if(this.manager.allowAdd) {
      addHtml = ' &lt;a class="' +  cclz('add' , 'dn-add') + '" href="#" id="sp_cat_add_' + this.id + '"&gt;+&lt;/a&gt;'; 
    }
    if(dnSiteSystemVersion &lt; 3.0) {
      buffer.push('&lt;li id="sp_cat_' + this.id + '" class="cat_node" data-name="' + this.name.escapeQuotes() + '" data-id="' + this.id + '"&gt;&lt;span&gt;&lt;a href="#" class="' + expandClass + '" id="sp_cat_e_' + this.id + '"&gt;&amp;nbsp;&lt;/a&gt;&lt;a href="#" class="link" id="sp_cat_n_' + this.id + '"&gt;' + this.getCaption() + '&lt;/a&gt;' + addHtml + '&lt;/span&gt;');
      if(this.shouldRenderChildren()) {
        buffer.push('&lt;ul class="cat_children" style="display:none;" id="sp_cat_c_' + this.id + '" style="padding-left: 20px;"&gt;');
        for(var i=0; i &lt; this.categories.list.length; i++) {
          this.categories.list[i].buildHierarchyHtml(buffer);
        }
        buffer.push('&lt;/ul&gt;');
      }
      buffer.push('&lt;/li&gt;');
    } else {
      var clazzes = ["dn-hierarchy-node"];
      if(this.expanded) {
        clazzes.push('dn-expanded');
      }
      if(this.thumb != null) {
        clazzes.push('dn-thumb');
      }
      var expander = '';
      if(this.shouldRenderChildren()) {
        expander = '&lt;span id="sp_cat_e_' + this.id + '" class="dn-hierarchy-expander"&gt;&lt;/span&gt;';  
      }
      buffer.push('&lt;li id="sp_cat_' + this.id + '" class="' + clazzes.join(" ") + '" data-name="' + this.name.escapeQuotes() + '" data-id="' + this.id + '"&gt;' +
      expander +
      '&lt;span&gt;&lt;a href="Javascript://" id="sp_cat_n_' + this.id + '" class="link"&gt;' + this.getCaption() + '&lt;/a&gt;' + addHtml + '&lt;/span&gt;');
      if(this.shouldRenderChildren()) {
        buffer.push('&lt;ul class="dn-hierarchy-children" id="sp_cat_c_' + this.id + '"&gt;');
        for(var i=0; i &lt; this.categories.list.length; i++) {
          this.categories.list[i].buildHierarchyHtml(buffer);
        }
        buffer.push('&lt;/ul&gt;');
      }
      buffer.push('&lt;/li&gt;');
    }
    return buffer;
  },
  
  bindHierarchyHtml: function() {
    this.nodeEl = $('sp_cat_' + this.id);
    this.expandEl = $('sp_cat_e_' + this.id);         
    this.captionEl = $('sp_cat_n_' + this.id);
    if(this.shouldRenderChildren()) {
      this.childrenEl = $('sp_cat_c_' + this.id);
      for(var i=0; i &lt; this.categories.list.length; i++) {
        this.categories.list[i].bindHierarchyHtml();
      }
    }
    var self = this;
    if(this.expandEl != null) {
      this.expandEl.onclick=function() {
        self.toggleExpand(self.expanded==false);
        return false;
      };
    }
    if(this.captionEl != null) {
      this.captionEl.onclick=function() {
        log("captionEl.onclick start");
        self.select();
        log("captionEl.onclick end");
        return false;
      };
    }
    if(this.manager.allowAdd) {
      this.addChildEl = $('sp_cat_add_' + this.id); 
      if(this.addChildEl != null) {
        this.addChildEl.onclick = function() {
          self.addChild();  
          return false;
        }
      }
    }
  },
  
  refreshHtml: function() {
    var html = this.buildHierarchyHtml([]).join("\n");
    $('sp_cat_' + this.id).replace(html);
    this.bindHierarchyHtml();
  },
  
  buildDropdownHtml: function() {
    if(!this.hasChildren()) return null;
    var opts = [];
    
    opts.push('&lt;option value=""&gt;' + dnMl('Select Category') + '&lt;/option&gt;');
    
    for(var i=0; i &lt; this.categories.list.length; i++) {
      var cat = this.categories.list[i];
      opts.push('&lt;option value="' + cat.id + '"&gt;' + cat.name + '&lt;/option&gt;');
    }
    
    return '&lt;select id="sp_cat_' + this.id + '"&gt;' + opts.join("\n") + '&lt;/select&gt; &lt;div id="sp_cat_c_' + this.id + '"&gt;&lt;/div&gt;';
  },
  
  bindDropdownHtml: function() {
    this.nodeEl = $('sp_cat_' + this.id);
    this.childrenEl = $('sp_cat_c_' + this.id);
    var self = this;
    if(this.nodeEl != null) {
      this.nodeEl.onchange = function() {
        self.selectChildCategory(self.nodeEl.value, true);
      };
    }
  },
  
  selectChildCategory: function(childId, selectProducts) {
    if(childId == '' || childId == null) {
      this.childrenEl.update('');
      this.manager.setSelectedCategory(this);
      if(selectProducts) this.paginate(1);
    } else {
      var childCat = this.categories.byId[parseInt(childId, 10)];
      if(childCat == null) {
        alert("Unable to get category " + childId);
        return;
      }
      this.manager.setSelectedCategory(childCat);
      if(this.childrenEl != null) {
        var html = childCat.buildDropdownHtml();
        if(html == null) {
          this.childrenEl.update('');
        } else {
          this.childrenEl.update(html);
          childCat.bindDropdownHtml();
        }
      }
      if(selectProducts) childCat.paginate(1);
    }
  },
  
  //make sure the category is selected in ther hierarchy/dropdowns..
  checkSelected: function() {
    if(this.parent != null) {
      this.parent.checkSelected();
      if(this.manager.useDropdowns) {
        if(this.parent.nodeEl != null) {
          this.parent.nodeEl.value = this.id;
        }
        this.parent.selectChildCategory(this.id, false);
      } else {
        this.toggleExpand(true); //make sure its expanded...
        this.manager.setSelectedCategory(this);
      }
    }
    
  },
  
  toggleExpand: function(expand) {
    if(this.shouldRenderChildren()) {
      if(this.expandEl == null || this.expandEl.className=="null") return false;
      
      if(expand) {
        if(dnSiteSystemVersion &lt; 3.0) {
          if(this.childrenEl != null) this.childrenEl.show();
          this.expandEl.className = 'close';
        } else {
          this.nodeEl.addClassName("dn-expanded");
        }
      } else {
        if(dnSiteSystemVersion &lt; 3.0) {
          if(this.childrenEl != null) this.childrenEl.hide();
          this.expandEl.className="open";
        } else {
          this.nodeEl.removeClassName("dn-expanded");
        }
      }
      this.expanded = expand;
      this.manager.updatePScrollbars();
    }
  },
  
  select: function(selectFirstProduct) {
    if(this.manager.selectCategoryOnClick) {
      this.manager.categorySelected(this);
      return;
    }
    if(!this.manager.useDropdowns) {
      this.toggleExpand(true); //make sure its expanded...
    }
    this.manager.setSelectedCategory(this);
    this.manager.resetSearchField();
    this.paginate(1, selectFirstProduct);
  },
  
  paginate: function(page, selectFirstProduct, fromSearch) {
    if(this.manager.productsPreloaded &amp;&amp; !fromSearch) {
      var productList = this.products ? this.products.list : [];
      var list = this.manager.paginator.resetFromList(page, productList, this.manager.perPage);
      this.updateProductList(list);
    } else {
      params = {}
      if(this.manager.getSearchField() != '') params.filter_search = this.manager.getSearchField();
      if(this.manager.getVendorSearchField()) params.filter_vendor_search = this.manager.getVendorSearchField();
      if(this.manager.noFilter) params.nofilter=1;
      if(this.manager.all) params.all=1;
      if(this.manager.highDetail) params.high_detail = 1;
      if(this.manager.excludeNonVis) params.exclude_non_vis = 1;
      if(this.manager.campaignVis) params.campaign_vis = 1;
      if(this.manager.availableProcessIds) params.available_process_ids = this.manager.availableProcessIds;
      if(!this.manager.allowDec) params.allow_decorate = 0;
      if(dnInOM()) params.oms = 1;
      params.tn_size = this.manager.thumbnailSize;
      params.tn_crop = (this.manager.thumbnailCropped ? 1 : 0);
      params.tn_type = this.manager.thumbnailType;
      params.dnsv = dnSiteSystemVersion;
      
      params.page = page;
      params.per_page = this.manager.perPage;
      if(this.manager.allowAll &amp;&amp; this.id == this.manager.rootCategory.id) {
        params.cat_id = 0;
      } else {
        params.cat_id = this.id;
      }
      params.exclude_asi = true;
      params.exclude_free_form = true;
      params.requesting_quote = this.manager.requestingQuote;
      var asyncKey = this.manager.asyncStart(this.manager.productListContainerEl);
      var self = this;
      var t2 = new Ajax.Request(this.manager.ajaxUrl("/shared/lookups/idx_products"), {parameters:params, asynchronous:true, evalScripts:true,
        onFailure: function() {
          self.manager.asyncFinish(asyncKey);
          alert("Error calling server");
        },
        onComplete: function D_onComplete(transport) {
          self.manager.asyncFinish(asyncKey);
          var response = transport.responseText.evalJSON();
          if (response.error) {
            alert(response.error); 
          } else {
            self.manager.paginator.reset(response.total_pages, response.total_entries, response.per_page, response.current_page, response.offset, response.length);
            self.updateProductList(response.products);
            if (selectFirstProduct) {
              self.manager.callback(response.products[0]);
              self.manager.setSelectedProductId(response.products[0].id);
            }
          }
        }
      });
    }
  },
 
  updateProductList: function(products) {
    this.currentProductList = products;
    var html = '';
    for(var i=0; i &lt; products.length; i++) {
      var product = products[i];
      if(this.manager.highDetail) {
        html += product.html;
      } else {
        var imgUrl = this.manager.tnUrl(product);
        if(dnSiteSystemVersion &gt;= 3.0) {
          var selClazz = product.id == this.manager.selectedProductId ? ' dn-selected' : '';
          var nameParts = [];
          if(this.manager.displayName) {
            nameParts.push(product.name);
          }
          if(this.manager.displayCode) {
            nameParts.push(product.code);
          }
          if(this.manager.displayBrand) {
            nameParts.push(product.manufacturer_name);
          }
          var captionHtml = nameParts.length &gt; 0 ? '&lt;div class="dn-grid-text"&gt;&lt;span id="sp_prodn_' + this.manager.elId + '_' + product.id + '"&gt;' + nameParts.join(' ') + '&lt;/span&gt;&lt;/div&gt;' : ''; 
          
          html +=  '&lt;div id="sp_prod_' + this.manager.elId + '_' + product.id + '" class="dn-grid-item' + selClazz + '" style="max-width:' + this.manager.thumbnailDim + 'px;" data-code="' + product.code.escapeHTML() + '"&gt;' +
            '&lt;div class="dn-grid-item-container" style="max-width:' + this.manager.thumbnailDim + 'px;"&gt;' +
              '&lt;div class="dn-grid-image" style="max-height:' + this.manager.thumbnailDim + 'px;"&gt;' +
                '&lt;img src="' + imgUrl + '" id="sp_prodi_' + this.manager.elId + '_' + product.id + '" /&gt;'+
              '&lt;/div&gt;' + captionHtml +
            '&lt;/div&gt;' +
          '&lt;/div&gt;';
        } else {
      
          var clz = product.id == this.manager.selectedProductId ? 'product selected' : 'product';
          var codeHtml = this.manager.displayCode ? '&lt;p class="sp_prodc_"&gt;&lt;span id="sp_prodc_' + this.manager.elId + '_' + product.id + '"&gt;' + product.code + '&lt;/span&gt;&lt;/p&gt;' : '';
          var captionHtml = this.manager.displayName ? '&lt;p class="sp_prodn_' + (this.manager.displayCode ? '' : 'margin') + '"&gt;&lt;span id="sp_prodn_' + this.manager.elId + '_' + product.id + '"&gt;' + product.name + '&lt;/span&gt;&lt;/p&gt;' : ''; 
  
          var itemHtml = '&lt;li id="sp_prod_' + this.manager.elId + '_' + product.id;
          itemHtml += '" class="' + clz + '" data-code="' + product.code.escapeHTML() + '"&gt;&lt;div class="thumb_border"&gt;&lt;img src="' + imgUrl + '" id="sp_prodi_' + this.manager.elId + '_' + product.id + '"&gt;&lt;/div&gt;';
          itemHtml += codeHtml + captionHtml +'&lt;/li&gt;';
          html += itemHtml;
        }
      }
    }
    //html += '';
    this.manager.productListEl.update(html);
    if(this.productHeadingEl != null) {
      this.manager.productHeadingEl.update(dnMl('Products - ') + this.name );
    }
        
    for(var i=0; i &lt; products.length; i++) {
      this.bindProduct(products[i]);
    }

    // Hide pagination if only 1 page
    if(this.manager.paginatorContainerEl != null) {
      if(this.manager.paginator.totalPages &lt; 2) { 
        this.manager.paginatorContainerEl.hide();
      } else {
        this.manager.paginatorContainerEl.show();
      }
    }  

  },
  
  refreshProductList: function() {
    if(this.currentProductList != null) {
      this.updateProductList(this.currentProductList);
    }
  },
  
  bindProduct: function(product) {
    var self = this;
    if(this.manager.highDetail) {
      var prodEl = $('prod_link_' + product.sp_id);
      if(prodEl != null) {
        prodEl.onclick = function() {
          self.manager.productClicked(product);  
        };
        this.manager.callbacks.onRenderThumbnail(prodEl, product);
      }
    } else {
      if(dnSiteSystemVersion &lt; 3.0) {
        if(this.manager.displayName) {
          var capEl = $('sp_prodn_' + this.manager.elId + '_' + product.id);
          if(capEl != null) {
            var len = product.name.length - 1;
            //make sure the product caption fits in the cutoff height...
            while(capEl.offsetHeight &gt; 35 &amp;&amp; len &gt; 2) {
              len -= 2;
              capEl.update(product.name.substr(0,len) + "...");
            }
          }
        }
      }
      var prodEl = $('sp_prod_' + this.manager.elId + '_' + product.id);
      if(prodEl != null) {
        if(dnSiteSystemVersion &lt; 3.0) {
          var t = new Tooltip(prodEl, product.name);
        }
        prodEl.onclick = function() {
          self.manager.productClicked(product);  
        };
        this.manager.callbacks.onRenderThumbnail(prodEl, product);
      }
    }
  },
    
  markSelectedInHierachy: function(isSelected) {
    if(this.captionEl) {
      if(isSelected) {
        this.captionEl.addClassName(cclz('alt', 'dn-alt'));
        this.captionEl.parentNode.addClassName(cclz("selected", 'dn-selected'));
        this.nodeEl.addClassName(cclz("selected", 'dn-selected'));
      } else {
        this.captionEl.removeClassName(cclz('alt', 'dn-alt'));
        this.captionEl.parentNode.removeClassName(cclz("selected", 'dn-selected'));
        this.nodeEl.removeClassName(cclz("selected", 'dn-selected'));
      }
    }
  },
  
  getCaption: function() {
    return this.name;  
  },
  
  getHierarchyCaption: function() {
    if(this.parent != null) {
      var pCaption = this.parent.getHierarchyCaption(); 
      return pCaption + '&lt;span class="dn-hierarchy-selected-node-separator"&gt;&lt;/span&gt;' + this.name;
    } else {
      return this.name;  
    }
  },
  
  getFullName: function(separator, highlight) {
    if(separator == null) separator = "&gt;";
    
    var thisName = '';
    if(highlight) {
      thisName = "&lt;strong&gt;" + this.getCaption() + "&lt;/strong&gt;";
    } else {
      thisName = this.getCaption();
    }
    
    if(this.parent != null) {
      var parentName = this.parent.getFullName(separator, false);
      if(parentName != '') {
        return parentName + " " + separator + " " + thisName;
      } else {
        return thisName;
      }
    } else {
      return thisName;
    }
  },
  
  addChild: function(caption, callback) {
    if(caption == null) caption = prompt("Enter name of new category");
    if(caption == null || caption == "") return;
    
    var params = {}
    if(this.manager.system) params.system=1;
    params.parent_cat_id = this.id;
    params.name = caption;
    params.sc_manager = true;
    var self = this;
    var t2 = new Ajax.Request(this.manager.ajaxUrl("/manage/p_categories/add_category"), {parameters:params, asynchronous:true, evalScripts:true,
      onFailure: function() {
        alert("Error calling server");
      },
      onComplete: function D_onComplete(transport) {
        var response = transport.responseText.evalJSON();
        if (response.error) {
          alert(response.error); 
        } else {
          //add the category
          var newCat = new SPCategory(self.manager, { id:response.id, n:caption, pid:self.id, pc:0, dc:0, pos:response.pos, div:false});
          self.addCategory(newCat);
          self.manager.addCategory(newCat);
          self.refreshHtml();
          self.toggleExpand(true);
          if(callback != null) {
            callback(newCat); 
          }
        }
      }
    });
  }
});


var SPRootCategory = Class.create({
  CLASSDEF: {
    name: 'SPRootCategory',
    parent: SPCategory
  },
  
  initialize: function(manager, options) {
    SPRootCategory.parentClass.constructor().call(this, manager, options);
  },
  
  buildHierarchyHtml: function(buffer) {
    var style=' style="padding-left:0px;"';
    var addHtml = '';
    buffer.push('&lt;div&gt;');
    if(this.manager.allowAdd) {
      addHtml = ' &lt;a class="' +  cclz('add' , 'dn-add') + '" href="#" id="sp_cat_add_' + this.id + '"&gt;+&lt;/a&gt;'; 
    }
    if(this.manager.allowAll == true) {
      style = '';
      buffer.push('&lt;ul class="' + cclz('cat_children', 'dn-hierarchy-children') + '" id="sp_cat_c_' + (this.shouldRenderChildren() ? 0 : this.id) + '" style="padding-left:0px;"&gt;');
      if(dnSiteSystemVersion &lt; 3.0) {
        buffer.push('&lt;li id="sp_cat_' + this.id + '" class="cat_node"&gt;&lt;span&gt;&lt;a href="#" id="sp_cat_e_' + this.id + '"&gt;&amp;nbsp;&lt;/a&gt;&lt;a href="#" class="link" id="sp_cat_n_' + this.id + '"&gt;' + ml('All') + '&lt;/a&gt;' + addHtml + '&lt;/span&gt;');
      } else {
        var clazzes = ["dn-hierarchy-node"];
        if(this.expanded) {
          clazzes.push('dn-expanded');
        }
        if(this.thumb != null) {
          clazzes.push('dn-thumb');
        }
        var expander = '';
        if(this.shouldRenderChildren()) {
          expander = '&lt;span id="sp_cat_e_' + this.id + '" class="dn-hierarchy-expander"&gt;&lt;/span&gt;';
        }
        buffer.push('&lt;li id="sp_cat_' + this.id + '" class="' + clazzes.join(" ") + '"&gt;' +
        expander +
        '&lt;span&gt;&lt;a href="#" class="link" id="sp_cat_n_' + this.id + '"&gt;' + ml('All') + '&lt;/a&gt;' + addHtml + '&lt;/span&gt;');
      }
    } else if(this.manager.allowAdd) {
      style = '';
      buffer.push('&lt;a class="dnm-btn" style="margin-bottom: 15px; margin-left: 8px" href="#" id="sp_cat_add_' + this.id + '"&gt;+Add Category&lt;/a&gt;&lt;br/&gt;');
    }
    if(this.shouldRenderChildren()) {
      buffer.push('&lt;ul class="' + cclz('cat_children', 'dn-hierarchy-children') + '" id="sp_cat_c_' + this.id + '"' + style + '&gt;');
      for(var i=0; i &lt; this.categories.list.length; i++) {
        this.categories.list[i].buildHierarchyHtml(buffer);
      }
      buffer.push('&lt;/ul&gt;');
    }
    if(this.manager.allowAll == true || this.manager.allowAdd == true) {
      buffer.push('&lt;/ul&gt;');
    }
    buffer.push('&lt;/div&gt;');
    return buffer;
  },
  
  bindHierarchyHtml: function() {
    var self = this;
    this.nodeEl = $('sp_cat_' + this.id);
    if(this.shouldRenderChildren()) {
      this.childrenEl = $('sp_cat_c_' + this.id);
      for(var i=0; i &lt; this.categories.list.length; i++) {
        this.categories.list[i].bindHierarchyHtml();
      }
    }
    if(this.manager.allowAdd) {
      this.addChildEl = $('sp_cat_add_' + this.id); 
      if(this.addChildEl != null) {
        this.addChildEl.onclick = function() {
          self.addChild();  
          return false;
        }
      }
    }
    
    if(this.manager.allowAll == true) {
      this.captionEl = $('sp_cat_n_' + this.id);
      if(this.captionEl != null) {
        this.captionEl.onclick=function() {
          self.select();
          return false;
        };
      }
      
      this.expandEl = $('sp_cat_e_' + this.id);
      if(this.expandEl != null) {
        this.expandEl.onclick=function() {
          self.toggleExpand(self.expanded==false);
          return false;
        };
      }
    
    }
  },
  
  toggleExpand: function(expand) {
    if(this.shouldRenderChildren()) {
      if(this.expandEl == null || this.expandEl.className=="null") return false;

      if(expand) {
        if(dnSiteSystemVersion &lt; 3.0) {
          if(this.childrenEl != null) this.childrenEl.show();
          this.expandEl.className = 'close';
        } else {
          this.nodeEl.addClassName("dn-expanded");
        }
      } else {
        if(dnSiteSystemVersion &lt; 3.0) {
          if(this.childrenEl != null) this.childrenEl.hide();
          this.expandEl.className="open";
        } else {
          this.nodeEl.removeClassName("dn-expanded");
        }
      }
      this.expanded = expand;
      this.manager.updatePScrollbars();
    }
  }

});

var SPManager = Class.create({
  CLASSDEF: {
    name: 'SPManager'
  },
  
  initialize: function(options) {
    var self = this;
    this.inline = (options.inline == true);
    this.popupId = options.popupId;
    this.containerId = options.containerId;
    // DNM
    this.useDnmPopups = (options.dnmPopups == true);
    this.useDnmInnerMenu = (options.dnmInnerMenu == true);
    this.dnmInnerMenuId = options.dnmInnerMenuId;
    
    this.highDetail = (options.highDetail == true);
    this.thumbnailSize = options.thumbnailSize == null ? 3 : options.thumbnailSize;
    this.thumbnailDim = this.tnSizeToDim(this.thumbnailSize);
    this.thumbnailCropped = options.thumbnailCropped == null ? true : options.thumbnailCropped;
    this.thumbnailType = options.thumbnailType == null ? 1 : options.thumbnailType;
    this.displayCode = (options.displayCode == true);
    this.displayName = (options.displayName == true);
    this.displayBrand = (options.displayBrand == true);
    this.noFilter = (options.noFilter == true);
    this.all = (options.all == true);
    this.allowAll = (options.allowAll == true);
    this.allowAdd = (options.allowAdd == true);
    this.allowNonDec = (options.allowNonDec != false);
    this.allowDec = (options.allowDec != false);
    this.useDropdowns = (options.useDropdowns == true);
    this.excludeNonVis = (options.excludeNonVis == true);
    this.campaignVis = (options.campaignVis == true);
    this.width = options.width == null ? "840px" : options.width;
    
    this.useExistingElements = (options.useExistingElements == true);
    this.requestingQuote = options.requestingQuote;
    this.elements = options.elements;
    
    if(options.categories) {
      this.loadCategories(options.categories);
    }
    if(options.products) {
      this.preloadProducts(options.products);
    }
    this.elId = options.id != null ? options.id : '';
    
    //allow override of how the image url is generated
    this.tnUrlCallback = options.tnUrlCallback; 
    
    this.show = options.show == null ? function() { self.useDnmPopups ? dnmPopup(self.popupId, {autoResize:"height"}) : dnPopup(self.popupId, {alreadySized:true} );} : options.show;  
    this.reposition = options.reposition == null ? function() { self.useDnmPopups ? false : repositionPopup(self.popupId);} : options.reposition;
    this.hide = options.hide == null ? function() { self.useDnmPopups ? dnmClosePopup(self.popupId) : closePopup(self.popupId); self.isOpen = false;} : options.hide;
    
    this.asyncStart = options.asyncStart == null ? function(id) { return asyncStart(id);} : options.asyncStart;
    this.asyncFinish = options.asyncFinish == null ? function(id) { asyncFinish(id);} : options.asyncFinish;
    
    this.selectedProductId = null;
    
    this.isOpen = false;
    this.includeSearch = options.includeSearch == null ? true : options.includeSearch;
    this.includeVendorFilter = options.includeVendorFilter == null ? false : options.includeVendorFilter;
    if(options.vendorNames) {
      this.vendorNames = options.vendorNames;
    }
    this.perPage = options.perPage == null ? 15 : options.perPage;
    
    this.callbacks = options.callbacks;
    if(this.callbacks == null) this.callbacks = {};
    if(this.callbacks.onRenderThumbnail == null) {
      this.refreshProductListOnSelect = false;  
      this.callbacks.onRenderThumbnail = function() { };
    } else {
      this.refreshProductListOnSelect = true;  
    }

    this.availableProcessIds = options.availableProcessIds;

  },
                                                                                            
  tnSizeToDim: function(tnSize) {
    switch(tnSize) {
    case 1:
      return 400;
    case 2:
    case 9:
      return 150;
    case 3:
      return 100;
    case 4:
      return 50;
    case 5:
      return 300;
    case 6:
      return 250;
    case 7:
      return 200;
    case 8:
      return 175;
    case 10:
      return 125;
    case 11:
      return 75;
    }
    return 400;
  },
  
  tnUrl: function(product_data) {
    if(this.tnUrlCallback != null) {
      return this.tnUrlCallback(product_data, this.thumbnailSize, this.thumbnailCropped);
    }
    return product_data.listimg_img;
  },
  
  hasDesigner: function() {
    try {
      if(d != null) {
        return true;
      }
    } catch(e) {} 
    return false;
  },
  
  ajaxUrl: function spm_ajaxUrl(url) {
    if(this.translateParams != null) {
      url = addUrlParam(url, "translate=" + this.translateParams);
    }
    
    if(this.hasDesigner() &amp;&amp; d.debugAjax &amp;&amp; d.debugAjax != 0) {
      return addUrlParam(url, "email_request_log=" + d.debugAjax);
    } else {
      return url;  
    }
  },
  
  selectProduct: function(currentProductId, callback) {
    log("SPManager.selectProduct");
    this.setSelectedProductId(currentProductId);
    var self = this;
    if(!this.isSetup) {
      this.setup(function() { 
        log("SPManager.selectProduct.setup.callback");
        self.selectProduct(currentProductId, callback);
      });
      return;
    }
    this.callback = callback;
    if(!self.inline) {
      if(!this.isOpen) {
        if(dnSiteSystemVersion &lt; 3) {
          $(this.popupId).style.width = this.width;
        }
        this.show();
        this.isOpen = true;
      } else {
        this.reposition();
      }
    }
    if(this.selectedCategory == null) {
      if(this.allowAll) {
        var cat = null;
      } else {
        var cat = this.getDefaultCategory();
      }
      if(cat != null) {
        cat.checkSelected();
        cat.select((currentProductId == -2));
      } else {
        this.rootCategory.select((currentProductId == -2));
      }
    } else if(this.refreshProductListOnSelect) {
      this.selectedCategory.refreshProductList(); 
    }
  },

  searchProducts: function() {
    if(this.selectedCategory != null) {
      this.selectedCategory.paginate(1, false, true)
    }
  },

  getSearchField: function() {
    var searchField = $('filter_search');
    if (searchField != null) {
      return searchField.value;
    } else {
      return '';
    }  
  },

  resetSearchField: function() {
    var searchField = $('filter_search');
    if (searchField != null) {
      searchField.value = '';
    }  
  },

  getVendorSearchField: function() {
    var vendorSearchField = $('vendor_filter_search');
    if (vendorSearchField) {
      if(vendorSearchField.value == 'All') {
        return ''
      } else {
        return vendorSearchField.value;
      }  
    } else {
      return '';
    }  
  },

  //get a category with products in it..
  getDefaultCategory: function() {
    if(this.rootCategory.categories != null &amp;&amp; this.rootCategory.categories.list.length &gt; 0) {
      for(var i=0; i &lt; this.rootCategory.categories.list.length; i++) {
        if(this.rootCategory.categories.list[i].descProductCount &gt; 0) return this.rootCategory.categories.list[i];
      }
    } 
    return null;
  },
  
  setSelectedProductId: function(productId) {
    if(this.selectedProductId != null) {
       var el = $('sp_prod_' + this.elId + '_' + this.selectedProductId);
       if(el != null) {
         el.removeClassName(cclz('active', 'dn-selected'));
       }
    }
    this.selectedProductId = productId;
    if(this.selectedProductId != null) {
       var el = $('sp_prod_' + this.elId + '_' + this.selectedProductId);
       if(el != null) {
         el.addClassName(cclz('active', 'dn-selected'));
       }
    }
  },
  
  productClicked: function(productData, prodEl) {
    if (typeof(prodEl) == "undefined") prodEl = $('sp_prod_' + this.elId + '_' + productData.id);

    if(this.callbacks.onProductClicked != null) {
      if(!this.callbacks.onProductClicked(prodEl, productData)) {
        return;  
      }
    }
    
    if(!this.inline) {
      //closePopup(this.popupId);
      this.hide();
      this.isOpen = false;
    }
    this.callback(productData);
    this.setSelectedProductId(productData.id);
  },
  
  setup: function(callback) {
    if(this.useExistingElements) {
      this.popupEl = this.elements.popupSelectProduct;
      this.containerEl = this.elements.selectProductContainer;
    } else {
      this.containerEl = $(this.containerId);
      if(this.containerEl == null) {
        alert("Unable to select products: missing container element: " +  this.containerId);
        return false;
      }
      this.containerEl.update("loading...");
    }
    
    if (this.useDnmInnerMenu) {
      this.dnmInnerMenuEl = $(this.dnmInnerMenuId);
      if(this.dnmInnerMenuEl == null) {
        alert("Unable to select products: missing inner menu element: " +  this.dnmInnerMenuId);
        return false;
      }
    }

    if(this.categories == null) {
      if(!this.inline) {
        if(dnSiteSystemVersion &lt; 3) {
          $(this.popupId).style.width = this.width;
        }
        this.show();
        this.isOpen = true;
      }
      var params = {}
      if(this.noFilter) params.nofilter=1;
      if(this.campaignVis) params.campaign_vis = 1;
      if(this.all) params.all=1;
      var self = this;
      var t2 = new Ajax.Request(self.ajaxUrl("/shared/lookups/product_categories"), {parameters:params, asynchronous:true, evalScripts:true,
        onFailure: function() {
          alert("Error calling server");
          if(!self.inline) {
            //closePopup(self.popupId);
            self.hide();
            this.isOpen = false;
          }
        },
        onComplete: function D_onComplete(transport) {
          var response = transport.responseText.evalJSON();
          if (response.error) {
            if(!self.inline) {
              self.hide();
              this.isOpen = false;
            }
            alert(response.error); 
          } else {
            self.loadCategories(response);
            self.initContainer();
            self.isSetup=true;
            callback();
          }
        }
      });
    } else {
      this.initContainer();
      this.isSetup=true;
      callback();
    }
  },
  
  //categories are in a flat form with hierachial references that may be out of order
  loadCategories: function(categoryData) {
    this.categories = new MapList(this);

    var lastRemainingSize = 0;
    var catsLeft = categoryData;
    categoryData = [];
    while(catsLeft.length &gt; 0 &amp;&amp; lastRemainingSize != catsLeft.length) {
      lastRemainingSize = catsLeft.length;
      categoryData = catsLeft;
      catsLeft = [];
      for(var i=0; i &lt; categoryData.length; i++) {
        var catData = categoryData[i];
        if(catData.div != true) { //just drop the dividers for now
          if(catData.pid == null || catData.pid == 0) { //root category
            if(this.rootCategory == null) {
              this.rootCategory = new SPRootCategory(this, catData);
              this.addCategory(this.rootCategory);
            }
          } else if(this.categories.byId[catData.pid] == null) { //parent not registered yet...
            catsLeft.push(catData);
          } else {
            var newCat = new SPCategory(this, catData);
            this.categories.byId[catData.pid].addCategory(newCat);
            this.addCategory(newCat);
          }
        }
      }
    }
    
    if(catsLeft.length &gt; 0) {
      //cats left over...
      log("Not all categories added:" + catsLeft.length);
    } else if(this.rootCategory == null) { //no cats at all...
      this.rootCategory = new SPRootCategory(this, {id:0});
      this.addCategory(this.rootCategory);
    }
    if(!this.allowNonDec) {
      //trim all categories that dont have decoratable products in them....
      this.rootCategory.removeNonDec();
    }
    if(!this.allowDec) {
      //trim all categories that only have decoratable products in them....
      this.rootCategory.removeDec();
    }
    if(!dnInOM()) {
      //trim all categories that only have products with 'only BH areas' in them....
      this.rootCategory.removeOnlyBHAreas();
    }
    this.rootCategory.resort();
  },
  
  preloadProducts: function(products) {
    this.productsPreloaded = true;
    for(var i=0; i &lt; products.length; i++) {
      var p = products[i];
      for(var j =0; j &lt; p.cats.length; j++) {
        var cat =  this.categories.byId[p.cats[j]];
        if(cat != null) {
          cat.registerProduct(p);  
        }
      }
    }
  },
  
  //inject the html into the containerEl
  initContainer: function() {
    if(this.useExistingElements) {
      this.bindExistingElements();  
      return;
    }
    var hierarchy = '';
    var listingClass = (this.useDnmInnerMenu) ? 'dnm-select-products-listing' : 'library_listing span9';
    if(!this.useDropdowns) {
      var treeHtml = this.rootCategory.buildHierarchyHtml([]).join('');
      hierarchy = '';
      var hierarchySubClass = (this.useDnmPopups) ? 'dnm-select-products-hierarchy-popup' : 'span3';
      if (!this.useDnmInnerMenu) {
        hierarchy += '' +
        '&lt;div class="select_product_hierarchy hierarchy ' + hierarchySubClass + '"&gt;' +
          '&lt;div class="section"&gt;' +
            '&lt;h3&gt;' + dnMl('Categories') + '&lt;/h3&gt;' +
            '&lt;div&gt;' +
                '&lt;div class="select_product_categories product_categories" id="library_categories_scroll' + this.elId + '"&gt;' + treeHtml + '&lt;/div&gt;' +
            '&lt;/div&gt;' +
          '&lt;/div&gt;' +
        '&lt;/div&gt;';
      } else {
        hierarchy += '' +
        '&lt;h3&gt;' + dnMl('Categories') + '&lt;/h3&gt;' +
        '&lt;div class="dnm-innermenu-scroll-container"&gt;' +
            '&lt;div class="select_product_categories product_categories dnm-innermenu-scroll" id="library_categories_scroll' + this.elId + '"&gt;' + treeHtml + '&lt;/div&gt;' +
        '&lt;/div&gt;';
      }
    } else {
      listingClass = 'library_listing full';
      hierarchy = '' +
      '&lt;div class="section"&gt;' +
        '&lt;div class="int"&gt;' +
          '&lt;h3&gt;' + dnMl('Filter') + '&lt;/h3&gt;' +
          '&lt;div class="cont" id="select_product_categories' + this.elId + '"&gt;' + this.rootCategory.buildDropdownHtml() +
          '&lt;/div&gt;' +
        '&lt;/div&gt;' +
      '&lt;/div&gt;';
    }
    
    var productListClass = (this.highDetail) ? 'prod_list' : 'decoration_list';

    var vendorFilterHtml = '';
    if (this.includeVendorFilter) {
      vendorFilterHtml += '&lt;label&gt;Supplier&lt;/label&gt;';
      vendorFilterHtml += '&lt;select name="vendor_filter" id="vendor_filter_search" /&gt;';
      vendorFilterHtml += '&lt;option value="All"&gt;All&lt;/option&gt;';
      for(var i=0; i &lt; this.vendorNames.length; i++) {
        var vendorName = this.vendorNames[i];
        vendorFilterHtml += '&lt;option value="' + vendorName + '"&gt;' + vendorName + '&lt;/option&gt;';
      }
      vendorFilterHtml += '&lt;/select&gt;'; 
    }

    var searchHtml = '';
    if (this.includeSearch &amp;&amp; !this.useDnmInnerMenu) {
      searchHtml += '&lt;input type="text" placeholder="' + dnMl('Search products') + '" name="filter" id="filter_search" /&gt;';
      searchHtml += '&amp;nbsp&lt;a id="filter_search_btn" href="#" class="' + cclz('btn dnm-btn', 'dn-btn') + '" /&gt;' + dnMl('Search') + '&lt;/a&gt;'; 
    }
    
    var paddingStyle = '';
    var headingDisplay = '';
    var headingTitle = (this.useDnmPopups) ? '' : dnMl('Products');
    var productSearchFilterClass = (this.useDnmPopups) ? '' : 'product_search_filter';

    var html = '';
    if (this.useDnmInnerMenu) {
      this.dnmInnerMenuEl.innerHTML = hierarchy;
      this.dnmInnerMenuEl.id = this.dnmInnerMenuId + this.elId;
      paddingStyle = 'padding: 0px !important;';
      headingDisplay = (vendorFilterHtml != '') ? '' : ' display: none;';

      html +=
      '&lt;div class="sp_manager"&gt;' +
        '&lt;div class="' + listingClass + '" id="select_product_listing' + this.elId + '" &gt;' +
           '&lt;h3 id="products_heading" style="' + paddingStyle + headingDisplay + '"&gt;' + dnMl('Products') +
             '&lt;div class="' + productSearchFilterClass + '"&gt;' + vendorFilterHtml +
             '&lt;/div&gt;' +
           '&lt;/h3&gt;' +
           '&lt;div class="int"&gt;' +
             '&lt;div id="select_product_list_container' + this.elId + '" style="' + paddingStyle + '"&gt;' +
               '&lt;ul id="select_product_list' + this.elId + '" class="' + productListClass + '"&gt;&lt;/ul&gt;' +
             '&lt;/div&gt;' +
             '&lt;div id="select_product_list_paginator_container' + this.elId + '" class="pagination" style="display:none;"&gt;' +
             '&lt;/div&gt;' +
           '&lt;/div&gt;' +
         '&lt;/div&gt;' +
      '&lt;/div&gt;';
    } else {
      html +=
      '&lt;div class="sp_manager"&gt;'+
        '&lt;div class="library_browser dnm-list-with-hierarchy-on-left" id="library_browser' + this.elId + '"&gt;' +
          '&lt;div class="interior dnm-list-with-hierarchy-on-left-interior"&gt;' +
             hierarchy +
             '&lt;div class="' + listingClass + '" id="select_product_listing' + this.elId + '" &gt;' +
               '&lt;div class="section"&gt;' +
                 '&lt;h3 id="products_heading" style="' + paddingStyle + '"&gt;' + headingTitle +
                '&lt;div class="' + cclz(productSearchFilterClass, 'dn-product-search-filter') + '"&gt;' + vendorFilterHtml + searchHtml +
                   '&lt;/div&gt;' +
                 '&lt;/h3&gt;' +
                 '&lt;div class="int"&gt;' +
                   '&lt;div id="select_product_list_container' + this.elId + '" class="section-content" style="' + paddingStyle + '"&gt;' +
                     '&lt;ul id="select_product_list' + this.elId + '" class="' + productListClass + '"&gt;&lt;/ul&gt;' +
                   '&lt;/div&gt;' +
                   '&lt;div id="select_product_list_paginator_container' + this.elId + '" class="pagination" style="display:none;"&gt;' +
                   '&lt;/div&gt;' +
                 '&lt;/div&gt;' +
               '&lt;/div&gt;' +
             '&lt;/div&gt;' +
          '&lt;/div&gt;' +
        '&lt;/div&gt;' +
      '&lt;/div&gt;';
    }

    this.containerEl.update(html);
    
    this.categoriesEl = $('select_product_categories' + this.elId);
    this.productListEl = $('select_product_list' + this.elId);
    this.productListContainerEl = $('select_product_list_container' + this.elId);
    this.productHeadingEl = $('products_heading' + this.elId);
    this.paginatorContainerEl = $('select_product_list_paginator_container');
    
    if(!this.useDropdowns) {
      this.rootCategory.bindHierarchyHtml();
    } else {
      this.rootCategory.bindDropdownHtml();
    }
    //if(this.productsPreloaded != true) {
      this.paginator = new Pagination(this, 'select_product_list_paginator_container' + this.elId, function(manager, page) { manager.selectedCategory.paginate(page); }, true);
    //}
    var self = this;
    if (this.includeSearch) {
      $('filter_search_btn').onclick= function() {
        self.searchProducts();
        return false;
      };
      $('filter_search').onkeydown = function (e) {
        if (e.keyCode == 13) {
          self.searchProducts();
          return false;
        }
      };
    }
  },
  
  bindExistingElements: function() {

    this.categoriesEl = this.elements.productCategories;
    this.productListEl = this.elements.productList;
    this.productListContainerEl = this.elements.productListContainer;
    this.productHeadingEl = this.elements.productListHeading;
    this.paginatorContainerEl = this.elements.productListPaginatorContainer;
    this.productCategoryContainerEl = this.elements.productCategoryContainer;
    this.productCategorySelectedEl = this.elements.productCategorySelected;
    
    var treeHtml = this.rootCategory.buildHierarchyHtml([]).join('');
    this.categoriesEl.update(treeHtml);
    this.rootCategory.bindHierarchyHtml();
    
    this.paginator = new Pagination(this, this.elements.productListPaginatorPages, function(manager, page) { manager.selectedCategory.paginate(page); }, true);

    var self = this;
    if(this.productCategoryContainerEl  != null) {
      this.productCategoryContainerEl.onclick=function() {
        self.toggleSlimCategory(true);
      }
    }
    this.updateProductCategorySelected(this.selectedCategory);
  },
  
  isInSlimMode: function() {
    if(dnSiteSystemVersion &gt;= 3.0) {
      var bp = this.containerEl.getAttribute("data-slimmode-breakpoint");
      if(bp != null) {
        return (this.containerEl.getAttribute("data-breakpoint-" + bp) != "true");
      } else {
        return false;
      }
    } else {
      return false;
    }
  },
  
  toggleSlimCategory: function(open) {
    if(open == null) {
      if(!this.containerEl.hasClassName("dn-selecting-category")) {
        this.containerEl.addClassName("dn-selecting-category");
      } else {
        this.containerEl.removeClassName("dn-selecting-category");
      }
    } else if(open == true) {
      this.containerEl.addClassName("dn-selecting-category");
    } else {
      this.containerEl.removeClassName("dn-selecting-category");
    }
  },
  
  cancel: function() {
    log("SPManager.cancel");
    if(this.isInSlimMode() &amp;&amp;  this.containerEl.hasClassName("dn-selecting-category")) {
      this.toggleSlimCategory(false);
    } else {
      this.hide();  
    }
  },
  
  
  addCategory: function(category) {
    this.categories.add(category);
  },
  
  setSelectedCategory: function(category) {
    if(this.selectedCategory != null) {
      this.selectedCategory.markSelectedInHierachy(false);
    }
    this.selectedCategory = category;
    if(this.selectedCategory != null) {
      this.selectedCategory.markSelectedInHierachy(true);
    }
    this.updateProductCategorySelected(category);
    if(this.isInSlimMode()) {
      this.toggleSlimCategory(false); 
    }
  },
  
  updateProductCategorySelected: function(category) {
    if(this.productCategorySelectedEl != null &amp;&amp; category!= null) {
      this.productCategorySelectedEl.update('&lt;span class="dn-hierarchy-selected-node-label"&gt;' + category.getHierarchyCaption() + '&lt;/span&gt;');
    }
  },

  updatePScrollbars: function() {
    if(this.elements &amp;&amp; this.elements.pScrollbarContainer) {
      if(typeof(this.elements.pScrollbarContainer) == 'string') {
        var container = $dnj("#"+this.elements.pScrollbarContainer);
      } else {
        var container = $dnj("#"+this.elements.pScrollbarContainer.id);
      }
      if(container &amp;&amp; container.perfectScrollbar) {
        if (container.hasClass('ps-container')) {
          container.perfectScrollbar('update');
        } else {
          container.perfectScrollbar({ suppressScrollX: true });
        }
        var cw = container.width();
        var ch = container.height();
        container.find('.ps-scrollbar-y-rail').css({transform: "scaleY("+(ch-20)/ch+")", "z-index": 1002});
        container.find('.ps-scrollbar-x-rail').css({transform: "scaleX("+(cw-20)/cw+")", "z-index": 1002});
      }
    }
  }
});


var SCManager = Class.create({
  CLASSDEF: {
    name: 'SCManager',
    parent: SPManager
  },
  
  initialize: function(options) {
    var self = this;
    this.inline = false;
    this.selectCategoryOnClick = true;
    this.system = (options.system == true);
    this.templates = (options.templates == true);
    this.systemTemplates = (options.systemTemplates == true);
    this.includeEmpty = this.templates || (options.includeEmpty == true);
    this.allowAll = (options.allowAll == true);
    this.allowAdd = (options.allowAdd == true);
    this.allowNonDec = (options.allowNonDec != false);
    this.allowDec = (options.allowDec != false);
    this.excludeNonVis = (options.excludeNonVis == true);
    this.campaignVis = (options.campaignVis == true);
    this.noSelectIndicator = (options.noSelectIndicator == true);
    this.defaultToRoot = (options.defaultToRoot == true);
    
    this.zIndex = options.zIndex == null ? 1000 : options.zIndex;
    if(options.categories) {
      this.loadCategories(options.categories);
    }
    
    this.elId = options.id != null ? options.id : '';
    
    this.asyncStart = options.asyncStart == null ? function(id) { return asyncStart(id);} : options.asyncStart;
    this.asyncFinish = options.asyncFinish == null ? function(id) { asyncFinish(id);} : options.asyncFinish;

    this.isOpen = false;
    
    this.bgClickedEvent = this.backgroundClicked.bindAsEventListener(this);

    this.clazz = (this.noSelectIndicator ? "dnm-sc-manager dnm-sc-manager-noselect" : "dnm-sc-manager");
  },
  
  backgroundClicked: function(event) {
    var el = Event.element(event);
    
    
    if(el ==this.element || el == this.containerEl || el.descendantOf(this.containerEl)) {
      log("backgroundClicked: inside");
      //do nothing
    } else {
      log("backgroundClicked: outside");
      log(el);
      this.hide();  
    }
  },
  
  getCategoryUrl: function() {
    if(this.templates) {
      return "/shared/lookups/product_categories?templates=1";
    } else if(this.system) {
      return "/shared/lookups/product_categories?system=1";
    } else {
      return "/shared/lookups/product_categories?all=1";
    }
  },

  hasDesigner: function() {
    try {
      if(d != null) {
        return true;
      }
    } catch(e) {} 
    return false;
  },
  
  ajaxUrl: function spm_ajaxUrl(url) {
    if(this.translateParams != null) {
      url = addUrlParam(url, "translate=" + this.translateParams);
    }
    
    if(this.hasDesigner() &amp;&amp; d.debugAjax &amp;&amp; d.debugAjax != 0) {
      return addUrlParam(url, "email_request_log=" + d.debugAjax);
    } else {
      return url;  
    }
  },
  
  selectCategory: function(element, currentCategoryId, callback) {
    this.element = $(element);
    var self = this;
    if(!this.isSetup) {
      this.setup(function() { self.selectCategory(element, currentCategoryId, callback);});
      return;
    }
    this.callback = callback;
    var cat = this.categories.byId[currentCategoryId];
    if(cat == null) {
      var cat = this.getDefaultCategory();
      if(cat != null) {
        cat.checkSelected();
      } 
    } else {
      cat.checkSelected();
    }
    if(!this.isOpen) {
      this.show(cat);
    } else {
      this.ensureVisible(cat);
    }
  },
  
  //get a category with products in it..
  getDefaultCategory: function() {
    if(this.defaultCategory == null &amp;&amp; this.defaultToRoot) {
      return this.rootCategory;
    } else if(this.defaultCategory == null) {
      if(this.rootCategory.categories != null &amp;&amp; this.rootCategory.categories.list.length &gt; 0) {
        for(var i=0; i &lt; this.rootCategory.categories.list.length; i++) {
          if(this.rootCategory.categories.list[i].descProductCount &gt; 0) return this.rootCategory.categories.list[i];
        }
      } 
    } else {
      return this.defaultCategory;
    }
    return null;
  },


  setup: function(callback) {
    
    var el = document.createElement("div");
    el.className = "popup";
    el.style.display = "none";
    el.style.width = "400px";
    el.style.zIndex = this.zIndex;
    
    document.body.appendChild(el);

    this.containerEl = $(el);
    
    this.containerEl.update("&lt;div class='"+this.clazz+"'&gt;loading...&lt;/div&gt;");
    
    if(this.categories == null) {
      this.show();
      var self = this;
      var t2 = new Ajax.Request(self.ajaxUrl(this.getCategoryUrl()), {asynchronous:true, evalScripts:true,
        onFailure: function() {
          alert("Error calling server");
          self.hide();
        },
        onComplete: function D_onComplete(transport) {
          var response = transport.responseText.evalJSON();
          if (response.error) {
            self.hide();
            alert(response.error); 
          } else {
            self.loadCategories(response);
            self.initContainer();
            self.isSetup=true;
            self.ensureVisible();
            callback();
          }
        }
      });
    } else {
      this.initContainer();
      this.isSetup=true;
      callback();
    }
  },
  
 
  
  //inject the html into the containerEl
  initContainer: function() {
    var hierarchy = '';
    var treeHtml = this.rootCategory.buildHierarchyHtml([]).join('');
    hierarchy = '&lt;div class="hierarchy"&gt;' +
              '&lt;div class="product_categories" id="library_categories_scroll' + this.elId + '" style="max-height: 500px;overflow-y: auto;"&gt;' + treeHtml + '&lt;/div&gt;' +
            '&lt;/div&gt;';
    
    var self = this;     
    var html = '&lt;div class="'+this.clazz+'"&gt;' +
      '&lt;div class="interior"&gt;' +
        hierarchy +
      '&lt;/div&gt;' +
      '&lt;div class="foot"&gt;' +
        '&lt;a href="#" id="cancel' + this.elId + '" class="dnm-btn dnm-btn-cancel"&gt;Cancel&lt;/a&gt;' +
      '&lt;/div&gt;' +
    '&lt;/div&gt;&lt;/div&gt;';
    
    this.containerEl.update(html);
    this.scrollContainer = $('library_categories_scroll' + this.elId);
    this.rootCategory.bindHierarchyHtml();
    $('cancel' + this.elId).onclick= function() {
        self.hide();
        return false;
    }
    
  },
  
  
  addCategory: function(category) {
    this.categories.add(category);
  },
  
  setSelectedCategory: function(category) {
    if(this.selectedCategory != null) {
      this.selectedCategory.markSelectedInHierachy(false);
    }
    this.selectedCategory = category;
    if(this.selectedCategory != null) {
      this.selectedCategory.markSelectedInHierachy(true);
    }
  },
  
  getWindowSize: function() {
   
    var myWidth = 0, myHeight = 0;
    if( typeof( window.innerWidth ) == 'number' ) {
      //Non-IE
      myWidth = window.innerWidth;
      myHeight = window.innerHeight;
    } else if( document.documentElement &amp;&amp; ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
      //IE 6+ in 'standards compliant mode'
      myWidth = document.documentElement.clientWidth;
      myHeight = document.documentElement.clientHeight;
    } else if( document.body &amp;&amp; ( document.body.clientWidth || document.body.clientHeight ) ) {
      //IE 4 compatible
      myWidth = document.body.clientWidth;
      myHeight = document.body.clientHeight;
    }
    return { w: myWidth, h: myHeight };
  },
  
  getWindowScrolling: function() {
    var scrOfX = 0, scrOfY = 0;
    if( typeof( window.pageYOffset ) == 'number' ) {
      //Netscape compliant
      scrOfY = window.pageYOffset;
      scrOfX = window.pageXOffset;
    } else if( document.body &amp;&amp; ( document.body.scrollLeft || document.body.scrollTop ) ) {
      //DOM compliant
      scrOfY = document.body.scrollTop;
      scrOfX = document.body.scrollLeft;
    } else if( document.documentElement &amp;&amp; ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
      //IE6 standards compliant mode
      scrOfY = document.documentElement.scrollTop;
      scrOfX = document.documentElement.scrollLeft;
    }
    return { l: scrOfX,  t: scrOfY };
  },
  
  ensureVisible: function(curCat) {
    var windowSize = this.getWindowSize();
    var scrolling = this.getWindowScrolling();
    var pos = Position.cumulativeOffset(this.containerEl);
    var dims = Element.getDimensions(this.containerEl);
    if(pos[0] + dims.width &gt; windowSize.w + scrolling.l) {
      this.containerEl.style.left = ( windowSize.w + scrolling.l - dims.width - 20) + "px";
    }
    if(pos[1] + dims.height &gt; windowSize.h + scrolling.t) {
      var top = (windowSize.h + scrolling.t - dims.height - 20);
      if(top &lt; scrolling.t) top = scrolling.t;
      this.containerEl.style.top = top + "px";
    }
    
    //scroll to position
    if(curCat != null) {
      this.scrollContainer.scrollTop = 0;
      var pos2 = Position.cumulativeOffset(curCat.captionEl);
      var dims2 = Element.getDimensions(curCat.captionEl);
      var delta = pos[1] - pos2[1] + dims2.height;
      this.scrollContainer.scrollTop = (0-delta);
    } 
  },
  
  show: function(curCat) {
    log("SPManager.show");
    if(dnSiteSystemVersion &gt;= 3) {
      this.popupEl.addClassName("dn-alt");  
    } else {
      var pos = Position.cumulativeOffset(this.element);
      var dims = Element.getDimensions(this.element);
      
      this.containerEl.style.left = pos[0] + "px";
      this.containerEl.style.top = (pos[1] + dims.height + 5) + "px";
      
      this.containerEl.show();
      this.ensureVisible(curCat);
      this.isOpen = true;
    }
    var self = this;
    //needs to be in timeout so it does not grab any event that opens this (a button click etc)
    window.setTimeout( function() { 
        if(self.isOpen) {
          log("Assigning event");
          Event.observe(document.body, 'click', self.bgClickedEvent);
        } else {
          log("Skipping Assigning event");
        }
    }, 250);
  },
  
  hide: function() {
    if(dnSiteSystemVersion &gt;= 3) {
      this.popupEl.removeClassName("dn-alt");  
    } else {
      this.containerEl.hide();
    }
    Event.stopObserving(document.body, 'click', this.bgClickedEvent);
    log("Removing event");
    this.isOpen = false;
    this.returnDropdownElement();
  },
  
  categorySelected: function(category) {
    if(!this.inline) {
      //closePopup(this.popupId);
      this.hide();
    }
    this.callback(category);
  },
  
  dropDown: function(el, callback) {
    log("dropDown start");
    if(this.isOpen) this.hide();
    //el is the probably the overlay... need to get the select...
    while(el != null &amp;&amp; el.tagName != 'SELECT') {
      el = el.previousSibling;  
    }
    if(el == null) {
      alert("Unable to get select box");
      return false;
    }
    var curVal = parseInt(el.value, 10);
    if(!this.pullDropdownElement(el)) return;
    var self = this;
    this.selectCategory(el.id, curVal, function(categoryData) {
      el.options[0].value = categoryData.id;
      el.options[0].text = categoryData.getFullName();
      if (el.options[0].text == "" &amp;&amp; self.allowAll) el.options[0].text = "All categories";
      if(callback != null) {
        callback(categoryData);  
      }
    });
    log("dropDown end");
    return false;
  },
  
  pullDropdownElement: function(el) {
    if(el.options.length == 0) return false;
    this.dropDownElement = el;
    this.dropDownOption = el.options[0];
    el.options[0].remove();
    return true;
  },
  
  returnDropdownElement: function() {
    if(this.dropDownOption != null) {
      this.dropDownElement.appendChild(this.dropDownOption);
      this.dropDownOption = null;
      this.dropDownElement = null;
    }
  }
});


</pre></body></html>