page-browse.html 11.4 KB
<link rel="import" href="../../bower_components/iron-selector/iron-selector.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/iron-icons/av-icons.html">
<link rel="import" href="../../bower_components/paper-drawer-panel/paper-drawer-panel.html">
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../bower_components/paper-header-panel/paper-header-panel.html">

<link rel="import" href="../app-sidebar/app-sidebar.html">
<link rel="import" href="../app-logo/app-logo.html">
<link rel="import" href="../app-bar/app-bar.html">
<link rel="import" href="../cart-icon/cart-icon.html">
<link rel="import" href="../catalog-data/catalog-data.html">
<link rel="import" href="../catalog-package/catalog-package.html">
<link rel="import" href="../package-symbol/package-symbol.html">
<link rel="import" href="../tag-link/tag-link.html">
<link rel="import" href="../theme-color/theme-color.html">
<link rel="import" href="../element-action-menu/element-action-menu.html">
<link rel="import" href="../element-table/element-table.html">
<link rel="import" href="../element-table-cards/element-table-cards.html">
<link rel="import" href="../responsive-element/responsive-element.html">

<dom-module id="page-browse">
  <link rel="import" type="css" href="page-browse.css">
  <template>
    <catalog-data elements="{{elements}}" packages="{{packages}}"></catalog-data>
    <catalog-package name="[[package]]" data="{{packageInfo}}"></catalog-package>
      <paper-drawer-panel id="drawerPanel" responsive-width="900px" narrow="{{narrowMode}}" drawer-width="272px" disable-edge-swipe>
        <app-sidebar drawer>
          <paper-toolbar>
            <app-logo class="flex" tabindex="1"></app-logo>
            <app-bar class="horizontal layout center end-justified" no-search></app-bar>
          </paper-toolbar>
          <div id="search" class="layout horizontal center">
            <iron-icon icon="search"></iron-icon>
            <input id="query" type="search" autocomplete="off" value="{{q::keyup}}" placeholder="Search Elements" class="flex" on-search="onSearch">
          </div>
          <div class="content">
            <div id="package-tag" hidden$="[[!tag]]">
              <span>[[tag]]</span> <iron-icon icon="clear" on-tap="clearTag"></iron-icon>
            </div>
            <div id="package-list">
              <nav>
                <a class="package" is="app-link" href="/browse?package=" active$="[[_isEqual(package,'')]]" tabindex="1">
                  <div class="layout horizontal center">
                    <div class="all-symbol" aria-hidden="true"><iron-icon icon="apps"></iron-icon></div>
                    <span class="title flex">All Elements</span>
                  </div>
                </a>
                <template is="dom-repeat" items="[[packages]]">
                  <a class="package" is="app-link" href$="[[_packageLink(item.name)]]" active$="[[_isEqual(package,item.name)]]" tabindex="1">
                    <div class="layout horizontal center">
                      <package-symbol aria-hidden="true" symbol="[[item.symbol]]" color="[[item.color]]"></package-symbol>
                      <span class="title flex">[[item.title]]</span>
                    </div>
                  </a>
                </template>
              </nav>
            </div>
            <div hidden$="[[!tag]]" id="current-tag" class="horizontal layout center">
              <b>Tag:</b> <span class="flex">[[tag]]</span> <iron-icon icon="clear" on-tap="clearTag"></iron-icon>
            </div>
          </div>
        </app-sidebar>
        <paper-header-panel id="container" mode="[[_getMode(narrowMode)]]" view$="[[_actualView(view)]]" main>
          <div class="paper-header">
            <paper-icon-button icon="menu" paper-drawer-toggle></paper-icon-button>
            <h2 class="flex">[[pageTitle]]</h2>
            <paper-icon-button class="toggleViewButton" icon="[[viewIcon]]" on-tap="toggleView" hidden$="[[_forceCards]]"></paper-icon-button>
            <cart-icon class="cartButton" id="cart-toggle" icon="stars" on-tap="cartOpen"></cart-icon>
          </div>
          <div id="content">
            <div id="package-heading" hidden$="[[!packageInfo]]">
              <div class="description">[[packageInfo.description]]</div>
            </div>

            <template is="dom-if" if="[[_stampCards(view)]]" restamp>
              <element-table-cards id="element-cards" elements="[[_filteredElements]]"></element-table-cards>
            </template>
            <template is="dom-if" if="[[_stampTable(view)]]" restamp>
              <element-table color="[[_getColor(packageInfo)]]" elements="[[_filteredElements]]" on-tag-selected="updateTag"></element-table>
            </template>
          </div>
        </paper-header-panel>
      </paper-drawer-panel>
  </template>
</dom-module>

<script>
  (function() {
    var _lastNavigated = null;
    Polymer({
      is: 'page-browse',
      enableCustomStyleProperties: true,
      properties: {
        router: Object,
        pageTitle: {type: String},

        // Query Parameters
        q: {type: String, notify: true, value: '', observer: '_qChanged'},
        tag: {type: String, notify: true, value: ''},
        package: {type: String, notify: true, value: ''},
        view: {type: String, notify: true},

        tagList: {type: Array, computed: 'arrayParam(tag)', value: function() { return []; }},
        packageList: {type: Array, computed: 'arrayParam(package)', value: function() { return []; }},

        viewIcon: {type: String, computed: 'computeViewIcon(view)', value: 'view-module'},
        packages: Array,
        packageInfo: {type: Object, value: {}},
        elements: Array,

        _filteredElements: Array,
        _elementCount: Number,
        _forceCards: {type: Boolean},
      },
      observers: [
        'updateURL(q,package, tag, view, elements)',
        'updateMeta(package, packageInfo)',
        'scrollToTop(package)'
      ],
      listeners: {
        'update-params': '_handleParamsUpdate'
      },

      ready: function() {
        this.view = this._forceCards ? 'cards' : 'table';
      },

      filter: function(element) {
        if (this.q && this.q.length && element.name.indexOf(this.q) < 0) {
          return false;
        }

        if (this.packageList.length && this.packageList.indexOf(element.package) < 0) {
          return false;
        }

        if (this.tagList.length) {
          var match = false;
          for (var i = 0; i < this.tagList.length; i++) {
            if (element.tags.join(' ').indexOf(this.tagList[i]) >= 0) match = true;
          }
          if (!match) return false;
        }

        return true;
      },

      updateTag: function(e, detail) {
        e.stopPropagation();
        e.preventDefault();
        var newTag = detail.name;
        var t = this.tagList.slice(0);
        if (t.indexOf(newTag) < 0) t.push(newTag);
        this.tag = t.join(',');
      },
      clearTag: function() { this.tag = null; },
      updatePackage: function(e) {
        e.stopPropagation();
        e.preventDefault();
        var newPkg = e.currentTarget.name;
        var p = this.packageList.slice(0);
        if (p.indexOf(newPkg) < 0) p.push(newPkg);
        this.package = p.join(',');
      },
      clearPackage: function() { this.package = null; },
      togglePackages: function() {
        if (this.package) {
          this.prevPackage = this.package;
          this.clearPackage();
        } else {
          this.package = this.prevPackage;
        }
      },
      _parseQueryString: function() {
        var query = window.location.search.substring(1);
        var params = query.split('&');
        var results = [];
        for (var i = 0; i < params.length; i++) {
          var pair = params[i].split('=');
          results[pair[0]] = pair[1];
        }
        return results;
      },
      _buildQueryString: function() {
        var out = [];
        if (this.q && this.q.length) out.push("q=" + this.q);
        if (this.tag && this.tag.length) out.push("tag=" + this.tag);
        if (this.package && this.package.length) out.push("package=" + this.package);
        if (this.view !== 'table') out.push("view=" + this.view);

        return out.join("&");
      },
      _handleParamsUpdate: function(_, params) {
        for (var key in params) {
          this[key] = params[key];
        }
      },
      _packageLink: function(name) {
        return "/browse?package=" + name;
      },
      _qChanged: function(q) {
        if (q) {
          this.async(function() {
            this.$.query.focus();

            // make sure to force the cursor to the end of the
            // input. Only an issue in Firefox.
            this.$.query.setSelectionRange(q.length, q.length);
          });
        }
      },
      updateURL: function(q, packageName, packageInfo, tag, view) {
        var qs = this._buildQueryString();
        if (qs !== _lastNavigated && this.router) {
          _lastNavigated = qs;
          this.router.go('/browse' + (qs.length ? '?' + qs : ''), {replace: true});
        }
        this.updateMeta(packageName, this.packageInfo);

        if (this.elements) {
          this._filteredElements = this.elements.filter(this.filter.bind(this));
          this._elementCount = this._filteredElements.length;
        }
        this.scrollToTop();
      },
      updateMeta: function(packageName, packageInfo) {
        if (this.q && this.q.length) {
          var t = "'" + this.q + "' ";
          t += (packageInfo && packageInfo.title) ? packageInfo.title : "Elements";
          this.pageTitle = t;
        } else if (packageInfo && packageInfo.title) {
          this.pageTitle = packageInfo.title;
        } else if (this.tagList.length) {
          this.pageTitle = "Elements Tagged '" + this.tagList.join("' or '") + "'";
        } else {
          this.pageTitle = "All Elements";
        }

        this.fire('page-meta', { title: this.pageTitle });
        this.$.drawerPanel.closeDrawer();
      },
      toggleView: function() {
        if (this.view === 'table') {
          this.view = 'cards';
        } else {
          this.view = 'table';
        }
      },
      computeViewIcon: function(view) {
        if (view === 'table') {
          return 'view-module';
        } else {
          return 'view-list';
        }
      },
      arrayParam: function(param) {
        if (!param || !param.length) { return []; }
        return param.toString().split(',');
      },
      cartOpen: function(e) {
        this.fire('cart-open');
      },
      onSearch: function(e) {
        // when a user clicks on the (x) button we need to be sure to
        // clear the query
        this.q = this.$.query.value;
      },
      scrollToTop: function() {
        this.$.container.scroller.scrollTop = 0;
      },
      _stampCards: function(view) {
        return view === 'cards';
      },
      _stampTable: function(view) {
        return view === 'table';
      },
      closeDrawer: function() {
        this.$.drawerPanel.closeDrawer();
      },
      _actualView: function(view, force) {
        return force ? 'cards' : view;
      },
      _isEqual: function(a,b) {
        return a === b;
      },
      _getColor: function() {
        return this.packageInfo && this.packageInfo.color ? this.packageInfo.color : '';
      },

      _getMode: function(narrow) {
        return narrow ? 'waterfall' : 'scroll';
      }
    });
  })();
</script>