Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgecasar committed May 26, 2017
0 parents commit 8ba8af9
Show file tree
Hide file tree
Showing 12 changed files with 520 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
root = true

[*]
indent_style = space
indent_size = 2
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
bower_components/
node_modules/
coverage/
build/
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/owner/my-element)

# \<app-pages-loader\>

Component to load dinamically pages and keep a reduced DOM in huge apps.

<!--
```
<custom-element-demo>
<template>
<link rel="import" href="app-pages-loader.html">
<link rel="import" href="./bower_components/polymer/lib/elements/dom-bind.html">
<next-code-block></next-code-block>
</template>
</custom-element-demo>
```
-->
```html
<dom-bind id="demo">
<template>
<p>
<label>Max nodes</label>
<input value="{{maxNodes::input}}"/>
</p>
<p>
<label>Max history</label>
<input value="{{maxHistory::input}}"/>
</p>
<p>
<label>Page</label>
<select value="{{selected::input}}">
<option value="view1">View 1</option>
<option value="view2">View 2</option>
<option value="view3">View 3</option>
<option value="view404">View 404</option>
</select>
</p>
<app-pages-loader selected="{{selected}}" fallback-selection="view404" max-nodes="{{maxNodes}}" max-history="{{maxHistory}}">
<link rel="lazy-import" group="view1" href="./demo/components/page-test.html">
<link rel="lazy-import" group="view2" href="./demo/components/page-test.html">
<link rel="lazy-import" group="view3" href="./demo/components/page-test.html">
<link rel="lazy-import" group="view404" href="./demo/components/page-test-404.html">
</app-pages-loader>
</template>
</dom-bind>
<script>
var demo = document.querySelector('#demo');
demo.selected = 'view1';
</script>
```

## Install the Polymer-CLI

First, make sure you have the [Polymer CLI](https://www.npmjs.com/package/polymer-cli) installed. Then run `polymer serve` to serve your element locally.

## Viewing Your Element

```
$ polymer serve
```

## Running Tests

```
$ polymer test
```

Your application is already set up to be tested via [web-component-tester](https://github.com/Polymer/web-component-tester). Run `polymer test` to run your application's test suite locally.
162 changes: 162 additions & 0 deletions app-pages-loader.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<link rel="import" href="../polymer/polymer-element.html">
<link rel="import" href="../lazy-imports/lazy-imports-mixin.html">
<link rel="import" href="../iron-selector/iron-selector.html">
<!--
`app-pages-loader`
Component to load dinamically pages and keep a reduced DOM in huge apps.
@demo demo/index.html
-->

<dom-module id="app-pages-loader">
<template>
<style>
:host {
display: block;
}

iron-selector .iron-selected {
@apply --app-pages-loader-page-selected;
}
</style>
<slot id="imports"></slot>
<iron-selector
id="pages"
attr-for-selected="id"
selected="[[selected]]"></iron-selector>
</template>

<script>
/** @polymerElement */
class AppPagesLoader extends Polymer.LazyImportsMixin(Polymer.Element) {
static get is() { return 'app-pages-loader'; }
static get properties() {
return {
selected: {
type: String,
notify: true,
observer: '_selectedChanged'
},
fallbackSelection: String,
history: {
type: Array,
value: () => []
},
/**
* Maximun pages history, if page wasn't visited in the `maxHistory`
* last pages it will be removed from the DOM.
* Setting `0` no remove any pages from the DOM.
*/
maxHistory: {
type: Number,
notify: true,
value: 0
},
/**
* Maximun number of nodes persist on DOM.
* Zero value for infinite.
*/
maxNodes: {
type: Number,
notify: true,
value: 0
}
};
}

constructor() {
super();
this.$ = {};
}

connectedCallback() {
super.connectedCallback();
this.$.pages = this.shadowRoot.querySelector('#pages');
this.$.imports = this.shadowRoot.querySelector('#imports');
}

isPageAttached(page) {
return this.$.pages._valueToIndex(page) !== undefined;
}

existsImport(group) {
var groupAttribute = group ? `[group=${group}]` : ':not([group])';
var query = `link${groupAttribute}[rel=\'lazy-import\'][href]:not([href=\'\'])`;
return this.querySelectorAll(query).length > 0;
}

_selectedChanged(page) {
if (this.isPageAttached(page)) {
this.purgePages();
} else if (this.existsImport(page)) {
this.importLazyGroup(page, this)
.then(this._getComponentNameFromImport.bind(this))
.then(this._attachComponent.bind(this))
.then(this.purgePages.bind(this))
.catch(this.showFallbackSelection.bind(this));
} else {
this.showFallbackSelection();
}
}

_getComponentNameFromImport(result) {
return result.loaded[0].match(/.*\/(.+?)\./)[1];
}

_attachComponent(componentName) {
this.$[this.selected] = document.createElement(componentName);
this.$[this.selected].id = this.selected;
return this.$.pages.appendChild(this.$[this.selected]);
}

purgePages() {
this.initializeSelected();
this.purgeByMaxNodes();
this.purgeByMaxHistory();
this.dispatchEvent(new CustomEvent('page-loaded', {
id: this.selected,
node: this.$.pages.selectedItem
}));
}

showFallbackSelection() {
this.selected = this.fallbackSelection || null;
}

initializeSelected() {
this.$.pages.selectedItem.history = 0;
const index = this.history.indexOf(this.$.pages.selectedItem);
if (index >= 0) {
this.splice('history', index, 1);
}
this.unshift('history', this.$.pages.selectedItem);
}

purgeByMaxNodes() {
if (this.maxNodes > 0) {
const keepNodes = this.maxNodes;
const numToDelete = Math.max(0, this.history.length - keepNodes);
const deletedItems = this.splice('history', keepNodes, numToDelete);
for(const itemToDelete of deletedItems) {
this.$.pages.removeChild(itemToDelete);
}
}
}

purgeByMaxHistory() {
for(let i = this.history.length-1; i >= 0; i--) {
const item = this.history[i];
if (this.maxHistory && item.history >= this.maxHistory) {
this.splice('history', i, 1);
this.$.pages.removeChild(item);
delete this.$[item.id];
} else {
item.history = ++item.history
}
}
}
}

window.customElements.define(AppPagesLoader.is, AppPagesLoader);
</script>
</dom-module>
16 changes: 16 additions & 0 deletions bower.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "app-pages-loader",
"description": "Component to load dinamically pages and keep a reduced DOM in huge apps.",
"main": "app-pages-loader.html",
"license": "MIT",
"dependencies": {
"polymer": "Polymer/polymer#^2.0.0",
"lazy-imports": "Polymer/lazy-imports#^2.0.0",
"iron-selector": "PolymerElements/iron-selector#^2.0.0"
},
"devDependencies": {
"iron-demo-helpers": "PolymerElements/iron-demo-helpers#2.0-preview",
"web-component-tester": "^6.0.0-prerelease.5",
"webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0-rc.5"
}
}
25 changes: 25 additions & 0 deletions demo/components/page-test-404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<link rel="import" href="../../../polymer/polymer-element.html">
<dom-module id="page-test-404">
<template>
<style>
:host {
display: block;
}
</style>
<h1>Page 404 (history: [[history]])</h1>
</template>

<script>
/** @polymerElement */
class PageTest404 extends Polymer.Element {
static get is() { return 'page-test-404'; }
static get properties() {
return {
history: Number
};
}
}

window.customElements.define(PageTest404.is, PageTest404);
</script>
</dom-module>
29 changes: 29 additions & 0 deletions demo/components/page-test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<link rel="import" href="../../../polymer/polymer-element.html">
<dom-module id="page-test">
<template>
<style>
:host {
display: block;
}
</style>
<h1>Page [[id]] (history: [[history]])</h1>
</template>

<script>
/** @polymerElement */
class PageTest extends Polymer.Element {
static get is() { return 'page-test'; }
static get properties() {
return {
history: Number,
id: {
type: String,
reflectToAttribute: true
}
};
}
}

window.customElements.define(PageTest.is, PageTest);
</script>
</dom-module>
62 changes: 62 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">

<title>app-pages-loader demo</title>

<script src="../../webcomponentsjs/webcomponents-lite.js"></script>

<link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
<link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
<link rel="import" href="../app-pages-loader.html">
<link rel="import" href="../../polymer/lib/elements/custom-style.html">

<custom-style>
<style include="demo-pages-shared-styles">
app-pages-loader {
--app-pages-loader-page-selected: {
background: #CCC;
};
}
</style>
</custom-style>
</head>
<body>
<div class="vertical-section-container centered">
<h3>Basic app-pages-loader demo</h3>
<dom-bind id="demo">
<template>
<p>
<label>Max nodes</label>
<input value="{{maxNodes::input}}"/>
</p>
<p>
<label>Max history</label>
<input value="{{maxHistory::input}}"/>
</p>
<p>
<label>Page</label>
<select value="{{selected::input}}">
<option value="view1">View 1</option>
<option value="view2">View 2</option>
<option value="view3">View 3</option>
<option value="view404">View 404</option>
</select>
</p>
<app-pages-loader selected="{{selected}}" fallback-selection="view404" max-nodes="{{maxNodes}}" max-history="{{maxHistory}}">
<link rel="lazy-import" group="view1" href="./demo/components/page-test.html">
<link rel="lazy-import" group="view2" href="./demo/components/page-test.html">
<link rel="lazy-import" group="view3" href="./demo/components/page-test.html">
<link rel="lazy-import" group="view404" href="./demo/components/page-test-404.html">
</app-pages-loader>
</template>
</dom-bind>
<script>
var demo = document.querySelector('#demo');
demo.selected = 'view1';
</script>
</div>
</body>
</html>
16 changes: 16 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0;url=demo/" />
<title>app-pages-loader</title>
</head>
<body>
<!--
ELEMENT API DOCUMENTATION SUPPORT COMING SOON
Visit demo/index.html to see live examples of your element running.
This page will automatically redirect you there when run in the browser
with `polymer serve`.
-->
</body>
</html>
Loading

0 comments on commit 8ba8af9

Please sign in to comment.