myva v1.0

swaptable.js

Summary

No overview generated for 'swaptable.js'


/**
 * Toteuttaa taulukon, jonka rivejä voi siirtää toiseen taulukkoon.
 */
SwapTable = {

  /**
   * Palauttaa aina false.
   *
   * @return false 
   */
  getFalse: function() {
    return false;
  },
  
  
  /**
   * Palauttaa elementin ensimmäisen vanhemman (tai isovanhemman jne.),
   * joka täsmää parametrina annettuun selektoriin.
   *
   * @param {Element} current_element Elementti, jonka vanhempia haetaan.
   * @param {String} selector Selektori (CSS), jonka mukaan vanhempaa haetaan.
   */
  findParentElement: function(current_element, selector) {
    while (current_element !== null && ! $(current_element).match(selector)) {
      current_element = current_element.parentNode;
    }
    return current_element;
  },
  
  
  /**
   * Palauttaa sen SwapTable-juurielementin (div.swap_table -selektoriin täsmäävän),
   * jonka lapsi (tai lapsenlapsi jne.) parametrina annettu elementti on.
   *
   * @param {Element} current_element Lapsielementti, jonka SwapTable-juurielementtiä haetaan.
   */
  getSwapRoot: function(current_element) {
    return SwapTable.findParentElement(current_element, 'div.swap_table');
  },
  
  
  /**
   * Palauttaa elementin sisältämän tekstin. Elementin tekstisisältöä etsitään
   * elementin nodeValue- ja value-kentistä. Jos elementillä ei ole tekstisisältöä,
   * etsitään sisältöä lapsielementeistä ja palautetaan ensimmäisenä löytynyt tekstisisältö.
   *
   * @param {Element} e Elementti, jonka tekstisisältö halutaan.
   *
   * @return Tekstisisältö tai null, jos tekstisisältöä ei löytynyt.
   */
  getElementText: function(e) {
    var elementText = null;
    if (e.nodeValue !== null) {
      elementText = e.nodeValue;
    } else if (e.value !== undefined) {
      elementText = e.value
    } else {
      var children = e.childNodes;
      for (var i = 0; i < children.length && elementText == null; ++i) {
        elementText = SwapTable.getElementText(children[i]);
      }
    }
    return elementText;
  },
  

  /**
   * Palauttaa selektoriin täsmäävän tekstisisällön. Tekstisisältö kaivetaan
   * getElementText()-funktiolla ensimmäisestä selektoriin täsmäävästä elementistä,
   * joka sisältää tekstisisältöä.
   *
   * @param {Element} base_element Elementti, josta selektoria vastaavaa elementtiä aletaan etsiä.
   * @param {String} selector Selektori, jonka mukaan elementti valitaan.
   *
   * @return Selektoria vastanneen elementin tekstisisältö, tai jos selektoria vastaava elementti
   *         ei sisältänyt tekstisisältöä, ensimmäisen tekstisisältöä sisältäneen lapsielementin
   *         tekstisisältö. 
   */
  getTextBySelector: function(base_element, selector) {
    var elements = $(base_element).getElementsBySelector(selector);
    var text = null
    for (var i = 0; i < elements.length && text === null; ++i) {
      text = SwapTable.getElementText(elements[i]);
    }
    return text;
  },


  /**
   * Käärii parametrina saamansa otuksen taulukkoon.
   * Jos parametrina saatu otus oli jo taulukko, metodi ei tee mitään.
   *
   * @param {Object} Käärittävä otus.
   *
   * @param {Array} Otus taulukossa, jos otus itse ei ollut taulukko.
   */
  wrapInArray: function (arg) {
    if (arg === undefined || arg == null) {
      return [];
    } else if (arg instanceof Array) {
      return arg;
    } else {
      return [arg];
    }
  },


  /**
   * Toteuttaa rivin valitsemiseen liittyvän toiminnallisuuden klikkaustapahtuman yhteydessä.
   * Jos klikkaustapahtuma on normaali klikkaus, valitaan klikattu rivi ja poistetaan valinta muilta riveiltä.
   * Jos klikattiin ctrl pohjassa, valitaan tai poistetaan valinta klikatulta riviltä, muihin ei kosketa.
   * Jos klikattiin shift pohjassa, valitaan kaikki elementit edellä normaalisti klikatun ja nyt klikatun väliltä.
   *
   * @param (Event) e Klikkaustapahtuma.
   */
  selectOnClick: function(e) {
    var swap_root = SwapTable.getSwapRoot(this);
    var clicked_row = $(SwapTable.findParentElement(this, 'tr'));
    if (Myva.is_IE) {
      e = window.event;
    }

    // Suoritetaan beforeClick
    for (var i = 0; i < swap_root.swapOptions.beforeClick.length; ++i) {
      if (! swap_root.swapOptions.beforeClick[i](this, e)) {
        return;
      }
    }

    if (e.ctrlKey) {
      if (clicked_row.hasClassName('selected')) {
        --swap_root.selectedCount;
      } else {
        ++swap_root.selectedCount;
      }
      clicked_row.toggleClassName('selected');
    } else if (e.shiftKey) {
      if (! clicked_row.hasClassName('selected')) {
        clicked_row.addClassName('selected');
        ++swap_root.selectedCount;
      }
      if (clicked_row != swap_root.selectedFirst) {
        var all_rows = $(SwapTable.findParentElement(this, 'tbody')).getElementsBySelector('tr');
        for (var i = 0, found = -1; found < 1 && i < all_rows.length; ++i) {
          if (all_rows[i] == swap_root.selectedFirst
              || all_rows[i] == SwapTable.findParentElement(this, 'tr')) {
            ++found;
          } else if (found == 0 && ! all_rows[i].hasClassName('selected')) {
            $(all_rows[i]).addClassName('selected');
            ++swap_root.selectedCount;
          }
        }
      }
    } else {
      var selected_rows = $(SwapTable.findParentElement(this, 'tbody')).getElementsBySelector('tr.selected');
      for (var i = 0; i < selected_rows.length; ++i) {
        selected_rows[i].removeClassName('selected');
      }
      $(SwapTable.findParentElement(this, 'tr')).addClassName('selected');
      swap_root.selectedCount = 1;
      swap_root.selectedFirst = SwapTable.findParentElement(this, 'tr');
    }
    swap_root.updateCounts(swap_root.selectedCount, swap_root.selectedCountElements, swap_root.swapOptions.selectedCountElements);
    
    // Suoritetaan afterClick
    for (var i = 0; i < swap_root.swapOptions.afterClick.length; ++i) {
      if (! swap_root.swapOptions.afterClick[i](this, e)) {
        return;
      }
    }
  },
 
 
  /**
   * Suorittaa rivin siirtämisen kohdetaulukkoon kaksoisklikkauksen yhteydessä.
   *
   * @param {Event} e Kaksoisklikkaustapahtuma. (Tässä toteutuksessa parametria ei tosin käytetä.)
   */
  swapOnDoubleClick: function(e) {
    var row = $(SwapTable.findParentElement(this, 'tr'));
    SwapTable.getSwapRoot(row).swapRow([row]);
  },


  /**
   * Päivittää parametrina annettujen elementtien sisällöksi parametrina annetun arvon.
   * Tarkoitettu SwapTable:n laskurielementtien päivittämiseen.
   *
   * @param {int} count Luku, joka asetetaan elementtien sisällöksi.
   * @param {Array} elements... Taulukot, jotka sisältävät päivitettävät elementit. Taulukoita voi antaa parametrina useita.
   */
  updateCounts: function(count) {
    for (var i = 1; i < arguments.length; ++i) {
      for (var j = 0; j < arguments[i].length; ++j) {
        $(arguments[i][j]).update('' + count);
      }
    }
    return i;
  },


  /**
   * Päivittää valittujen rivien sekä rivien kokonaismäärän näkyviin laskurielementteihin.
   * Laskurielementit sekä kentät, joista tiedot otetaan, on määritelty SwapTable-oliossa.
   * Valitut rivit täsmäävät selektoriin "tr.selected". Rivien kokonaismäärä saadaan selektoriin
   * "tr" täsmäävistä elementeistä.
   */
  setCounts: function() {
    this.totalCount = this.getElementsBySelector('tr').length;
    this.updateCounts(this.totalCount, this.totalCountElements, this.swapOptions.totalCountElements);
    this.selectedCount = this.getElementsBySelector('tr.selected').length;
    this.updateCounts(this.selectedCount, this.selectedCountElements, this.swapOptions.selectedCountElements);
  },


  /**
   * Aiheuttaa parametrina annetulle rivielementin (tr) ensimmäiseen soluun (td) klikkaustapahtuman.
   *
   * @param {Element} row Rivi, jolle klikkaustapahtuma aiheutetaan.
   */
  clickRow: function(row) {
    target_cells = $(row).getElementsBySelector('td');
    if (target_cells.length > 0) {
      if (Myva.is_IE) {
        target_cells[0].click();
      } else {
        click_event = target_cells[0].ownerDocument.createEvent('MouseEvents');
        click_event.initMouseEvent('click', true, true, target_cells[0].ownerDocument.defaultView,
1, 0, 0, 0, 0, false, false, false, false, 0, null);
        target_cells[0].dispatchEvent(click_event);
      }
    }
  },


  /**
   * Suorittaa rivin/rivien siirtämisen kohteena olevaan SwapTableen.
   * Ennen siirtoa suoritetaan mahdolliset beforeSwap-funktiot ja
   * siirron jälkeen mahdolliset afterSwap-funktiot.
   *
   * @param {Element} row Siirrettävä rivi. Voi olla myös taulukko siirrettävistä riveistä.
   */
  swapRow: function(row) {
    if (! this.swapTarget) {
      return;
    }

    // Sallitaan yksittäinenkin parametri
    row = SwapTable.wrapInArray(row);

    // Suoritetaan beforeSwap
    for (var i = 0; i < this.swapOptions.beforeSwap.length; ++i) {
      if (! this.swapOptions.beforeSwap[i](this, row)) {
        return;
      }
    }

    // Metodin perusmuuttujat
    var target_rows = this.swapTarget.getElementsBySelector('tr');
    var current_target_row_i = 0;
    var target_tbody = this.swapTarget.getElementsBySelector('tbody');
    if (target_tbody.length > 0) {
      target_tbody = target_tbody[0];
    } else {
      return;
    }

    // Käydään läpi kaikki siirrettävät rivit
    for (var row_i = 0; row_i < row.length; ++row_i) {
      // Varmistetaan, että rivi on valittu
      row[row_i].addClassName('selected');

      // Asetetaan solujen näkyvyys
      var source_cells = $(row[row_i]).getElementsBySelector('td');
      if (this.swapOptions.visible !== undefined) {
        for (var i = 0; i < source_cells.length && i < this.swapOptions.visible.length; ++i) {
          if ((this.swapOptions.visible[i] && ! source_cells[i].visible())
              || (! this.swapOptions.visible[i] && source_cells[i].visible())) {
            source_cells[i].toggle();
          }
        }
      }
    
      // Lisätään annettu rivi järjestyksessä oikeaan paikkaan.
      if (current_target_row_i < target_rows.length) {
findSortRow :
        for (; current_target_row_i < target_rows.length; ++current_target_row_i) {
          // Poistetaan samalla mahdollinen kohderivin valinta  -> vain siirretyt jää valituksi.
          target_rows[current_target_row_i].removeClassName('selected');

          var target_cells = $(target_rows[current_target_row_i]).getElementsBySelector('td');
findSortCell :
          for (var j = 0; j < this.swapOptions.orderBy.length; ++j) {
            if (
                (SwapTable.getElementText(target_cells[this.swapOptions.orderBy[j]]) > SwapTable.getElementText(source_cells[this.swapOptions.orderBy[j]]))
                || (isBlankString(SwapTable.getElementText(target_cells[this.swapOptions.orderBy[j]])) && ! isBlankString(SwapTable.getElementText(source_cells[this.swapOptions.orderBy[j]])))
              ) {
              // Lisätään ja siirrytään seuraavaan siirrettävään riviin
              target_rows[current_target_row_i].parentNode.insertBefore(row[row_i], target_rows[current_target_row_i]);
              break findSortRow;
            }
            if (
                (SwapTable.getElementText(target_cells[this.swapOptions.orderBy[j]]) < SwapTable.getElementText(source_cells[this.swapOptions.orderBy[j]]))
                || (! isBlankString(SwapTable.getElementText(target_cells[this.swapOptions.orderBy[j]])) && isBlankString(SwapTable.getElementText(source_cells[this.swapOptions.orderBy[j]])))
              ) {
              // Siirrytään vertaamaan seuraavaan kohderiviin
              break findSortCell;
            }
          }
        }
      }
      // Ei löytynyt paikkaa, lisätään kohteen viimeiseksi
      if (current_target_row_i == target_rows.length) {
        target_tbody.appendChild(row[row_i]);
      }
    }
    
    // Kaikki rivit siirretty; varmistetaan, että loput ovat valitsemattomia
    for (; current_target_row_i < target_rows.length; ++current_target_row_i) {
      target_rows[current_target_row_i].removeClassName('selected');
    }
    
    if (row.length > 0) {
      // Asetetaan ensimmäinen siirretty rivi selectedFirst:iin
      this.swapTarget.selectedFirst = row[0];
    
      // Päivitetään määrälaskurit
      this.totalCount -= row.length;
      this.updateCounts(this.totalCount, this.totalCountElements, this.swapOptions.totalCountElements);
      this.selectedCount -= row.length;
      this.updateCounts(this.selectedCount, this.selectedCountElements, this.swapOptions.selectedCountElements);
      this.swapTarget.totalCount += row.length;
      this.swapTarget.updateCounts(this.swapTarget.totalCount, this.swapTarget.totalCountElements, this.swapTarget.swapOptions.totalCountElements);
      this.swapTarget.selectedCount = row.length;
      this.swapTarget.updateCounts(this.swapTarget.selectedCount, this.swapTarget.selectedCountElements, this.swapTarget.swapOptions.selectedCountElements);
    }
    
    if (this.selectedCount > 0) {
      this.selectedFirst = this.getElementsBySelector('tr.selected')[0];
    } else {
      var rows_left = this.getElementsBySelector('tr');
      if (rows_left.length > 0) {
        this.selectedFirst = rows_left[0];
      } else {
        this.selectedFirst = null;
      }
    }
    
    // Suoritetaan afterSwap
    for (var i = 0; i < this.swapOptions.afterSwap.length; ++i) {
      if (! this.swapOptions.afterSwap[i](this, row)) {
        return;
      }
    }
  },


  /**
   * Siirtää kaikki valittuna olevat rivit kohteena olevaan SwapTable:en.
   * Valitut rivit täsmäävät selektoriin "tr.selected".
   */
  swapSelected: function() {
    this.swapRow(this.getElementsBySelector('tr.selected'));
  },
  
  
/**
 * Alustaa parametrina annetun div-elementin SwapTableksi.
 *
 * @param {Element} swap_root div-elementti, josta tehdään SwapTable. Elementin on sisällettävä table-elementti.
 * @param {Element} swap_target Siirron kohteena oleva SwapTable. Voi olla null.
 * @param {Object} swap_options SwapTable:n optiot. Mahdolliset optiot (olion kentät) ovat:
 * <ul>
 *   <li>orderBy: Array, joka alkiot sisältävät solun järjestysnumeron (alkaen 0:sta), jonka mukaan rivit järjestetään.
 *       Esim. {1, 0} järjestää rivit ensisijaisesti toisen solun perusteella, toissijaisesti ensimmäisen solun.
 *       Esimerkissä mahdollista kolmatta solua ei huomioida järjestämisessä.
 *   <li>visible: Array, jonka alkiot sisältävät boolean arvon jokaista solua kohti, ovatko solut näkyvissä
 *       siirron jälkeen. Arrayn indeksi vastaa rivin solun numeroa alkaen nollasta.
 *   <li>beforeClick: Funktio tai Array funktioista, jotka suoritetaan ennen klikkauksen käsittelyä. Saa parametrina clicked_element, click_event.
 *   <li>afterClick: Funktio tai Array funktioista, jotka suoritetaan klikkauksen käsittelyn jälkeen. Saa parametrina clicked_element, click_event.
 *   <li>beforeSwap: Funktio tai Array funktioista, jotka suoritetaan ennen siirron käsittelyä. Saa parametrina swap_root, row.
 *   <li>afterSwap: Funktio tai Array funktioista, jotka suoritetaan siirron käsittelyn jälkeen. Saa parametrina swap_root, row.
 *   <li>totalCountElements: Elementti tai Array elementeistä, joihin sijoitetaan taulukon rivien kokonaislukumäärä.
 *   <li>selectedCountElements Elementti tai Array elementeistä, joihin sijoitetaan taulukon valittujen rivien lukumäärä.
 * </ul>
 */
  create: function(swap_root, swap_target, swap_options) {
    // Alustetaan SwapTable
    // Parametrit
    swap_root = $(swap_root);
    swap_root.swapTarget = $(swap_target);
    swap_root.swapOptions = swap_options;
    // Funktiot
    swap_root.clickRow = SwapTable.clickRow
    swap_root.setCounts = SwapTable.setCounts;
    swap_root.swapRow = SwapTable.swapRow;
    swap_root.swapSelected = SwapTable.swapSelected;
    swap_root.updateCounts = SwapTable.updateCounts;
    // Options
    if (swap_root.swapOptions.orderBy === undefined) {
      swap_root.swapOptions.orderBy = new Array();
      swap_root.swapOptions.orderBy[0] = 0;
    }
    swap_root.swapOptions.beforeClick = SwapTable.wrapInArray(swap_root.swapOptions.beforeClick);
    swap_root.swapOptions.afterClick = SwapTable.wrapInArray(swap_root.swapOptions.afterClick);
    swap_root.swapOptions.beforeSwap = SwapTable.wrapInArray(swap_root.swapOptions.beforeSwap);
    swap_root.swapOptions.afterSwap = SwapTable.wrapInArray(swap_root.swapOptions.afterSwap);
    swap_root.swapOptions.totalCountElements = SwapTable.wrapInArray(swap_root.swapOptions.totalCountElements);
    for (var i = 0; i < swap_root.swapOptions.totalCountElements.count; ++i) {
      swap_root.swapOptions.totalCountElements[i] = $(swap_root.swapOptions.totalCountElements[i]);
    }
    swap_root.swapOptions.selectedCountElements = SwapTable.wrapInArray(swap_root.swapOptions.selectedCountElements);
    for (var i = 0; i < swap_root.swapOptions.selectedCountElements.count; ++i) {
      swap_root.swapOptions.selectedCountElements = $(swap_root.swapOptions.selectedCountElements);
    }
    // Muut alustukset
    swap_root.addClassName('swap_table');
    var cells = swap_root.getElementsBySelector('td');
    for (var i = 0; i < cells.length; ++i) {
      if (cells[i].getElementsBySelector('input[type="text"]').length == 0) {
        cells[i].onmousedown = SwapTable.getFalse;
        cells[i].onselectstart = SwapTable.getFalse;
        cells[i].onclick = SwapTable.selectOnClick;
        cells[i].ondblclick = SwapTable.swapOnDoubleClick;
      }
    }
    swap_root.totalCountElements = swap_root.getElementsBySelector('.total_count');
    swap_root.selectedCountElements = swap_root.getElementsBySelector('.selected_count');
    if (cells.length > 0) {
      swap_root.selectedFirst = cells[0].parentNode;
    } else {
      swap_root.selectedFirst = null;
    }
    swap_root.setCounts();
  }


};

myva v1.0

Documentation generated by JSDoc on Fri Aug 24 10:02:55 2007