From eca1aacfa3db0db3bddf48d43de848aa5a4b0d2e Mon Sep 17 00:00:00 2001 From: Max Lynch Date: Sat, 30 May 2015 10:44:32 -0500 Subject: [PATCH 1/6] Action Menu Improvements --- ionic/components/action-menu/action-menu.js | 79 +++++--- ionic/components/action-menu/action-menu.scss | 176 ++++++++++++++++++ .../action-menu/test/basic/index.js | 19 +- ionic/components/app/app.js | 4 +- 4 files changed, 247 insertions(+), 31 deletions(-) diff --git a/ionic/components/action-menu/action-menu.js b/ionic/components/action-menu/action-menu.js index 5358a399bd..f70d97bef2 100644 --- a/ionic/components/action-menu/action-menu.js +++ b/ionic/components/action-menu/action-menu.js @@ -1,4 +1,4 @@ -import {DynamicComponentLoader, ComponentLaoder, ElementRef, ComponentRef, onDestroy, DomRenderer} from 'angular2/angular2'; +import {NgIf, NgFor, DynamicComponentLoader, ComponentLaoder, ElementRef, ComponentRef, onDestroy, DomRenderer} from 'angular2/angular2'; import {bind, Injector} from 'angular2/di'; import {Promise} from 'angular2/src/facade/async'; import {isPresent, Type} from 'angular2/src/facade/lang'; @@ -11,6 +11,7 @@ import {Item, Icon} from 'ionic/ionic' import {Ionic} from 'ionic/components/app/app' import {IonicComponent} from 'ionic/config/component' import {raf, ready} from 'ionic/util/dom' +import * as util from 'ionic/util' import {Animation} from 'ionic/animations/animation'; @@ -20,51 +21,71 @@ import {Animation} from 'ionic/animations/animation'; }) @View({ template: ` -
-
-
- -
Action Menu List Header
-
- - +
+
+
+
+
{{titleText}}
+ + +
+
+ +
- -
Action Menu Label
-
- - -
- -
- -
-
`, - directives: [Item,Icon] + directives: [Item,Icon, NgIf, NgFor] }) export class ActionMenu { constructor(elementRef: ElementRef) { this.domElement = elementRef.domElement this.config = ActionMenu.config.invoke(this) + + this.wrapperEl = this.domElement.querySelector('.action-menu-wrapper'); + console.log('ActionMenu: Component Created', this.domElement); } + close() { + var backdrop = this.domElement.children[0].classList.remove('active'); + var slideOut = Animation.create(this.wrapperEl, 'slide-out'); + return slideOut.play(); + } + + open() { + var backdrop = this.domElement.children[0].classList.add('active'); + var slideIn = Animation.create(this.wrapperEl, 'slide-in'); + return slideIn.play(); + } + + setOptions(opts) { + util.extend(this, opts); + } + + // Overridden by options + destructiveButtonClicked() {} + buttonClicked(index) {} + cancel() {} + static open(opts) { console.log('Opening menu', opts, Ionic); - ActionMenu._inject(); + var promise = new Promise(resolve => { + ActionMenu._inject().then((actionMenu) => { + actionMenu.setOptions(opts); + setTimeout(() => { + actionMenu.open(); + }) + resolve(actionMenu); + }); + }) + + return promise; } static _inject() { - Ionic.appendToRoot(ActionMenu).then(() => { - console.log('Action Menu appended'); - }) + return Ionic.appendToRoot(ActionMenu); } } diff --git a/ionic/components/action-menu/action-menu.scss b/ionic/components/action-menu/action-menu.scss index 949dce0c03..9a3e3b24b2 100644 --- a/ionic/components/action-menu/action-menu.scss +++ b/ionic/components/action-menu/action-menu.scss @@ -7,7 +7,16 @@ $action-menu-max-width: 520px !default; $action-menu-background-color: rgba(243,243,243,.95) !default; $action-menu-button-text-color: #007aff !default; +$sheet-margin: 8px !default; +$sheet-border-radius: 4px !default; +$sheet-options-bg-color: #f1f2f3 !default; +$sheet-options-bg-active-color: #e4e5e7 !default; +$sheet-options-text-color: #007aff !default; +$sheet-options-border-color: #d1d3d6 !default; + + +/* .action-menu-container { position: absolute; z-index: $z-index-action-menu; @@ -24,4 +33,171 @@ $action-menu-button-text-color: #007aff !default; } } +*/ +.action-menu-backdrop { + transition: background-color 150ms ease-in-out; + position: fixed; + top: 0; + left: 0; + z-index: $z-index-action-menu; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0); + + &.active { + background-color: rgba(0,0,0,0.4); + } +} + +.action-menu-wrapper { + //transform: translate3d(0, 100%, 0); + //transition: all cubic-bezier(.36, .66, .04, 1) 500ms; + + position: absolute; + bottom: 0; + left: 0; + right: 0; + width: 100%; + max-width: 500px; + margin: auto; +} + +.action-menu-up { + transform: translate3d(0, 0, 0); +} + +.action-menu { + margin-left: $sheet-margin; + margin-right: $sheet-margin; + width: auto; + z-index: $z-index-action-menu; + overflow: hidden; + + .button { + display: block; + padding: 1px; + width: 100%; + border-radius: 0; + border-color: $sheet-options-border-color; + background-color: transparent; + + color: $sheet-options-text-color; + font-size: 21px; + + &:hover { + color: $sheet-options-text-color; + } + &.destructive { + color: #ff3b30; + &:hover { + color: #ff3b30; + } + } + } + + .button.active, .button.activated { + box-shadow: none; + border-color: $sheet-options-border-color; + color: $sheet-options-text-color; + background: $sheet-options-bg-active-color; + } +} + +.action-menu-has-icons .icon { + position: absolute; + left: 16px; +} + +.action-menu-title { + padding: $sheet-margin * 2; + color: #8f8f8f; + text-align: center; + font-size: 13px; +} + +.action-menu-group { + margin-bottom: $sheet-margin; + border-radius: $sheet-border-radius; + background-color: #fff; + overflow: hidden; + + .button { + border-width: 1px 0px 0px 0px; + } + .button:first-child:last-child { + border-width: 0; + } +} + +.action-menu-options { + background: $sheet-options-bg-color; +} + +.action-menu-cancel { + .button { + font-weight: 500; + } +} + +.action-menu-open { + pointer-events: none; + + &.modal-open .modal { + pointer-events: none; + } + + .action-menu-backdrop { + pointer-events: auto; + } +} + + +.platform-android { + + .action-menu-backdrop.active { + background-color: rgba(0,0,0,0.2); + } + + .action-menu { + margin: 0; + + .action-menu-title, + .button { + text-align: left; + border-color: transparent; + font-size: 16px; + color: inherit; + } + + .action-menu-title { + font-size: 14px; + padding: 16px; + color: #666; + } + + .button.active, + .button.activated { + background: #e8e8e8; + } + } + + .action-menu-group { + margin: 0; + border-radius: 0; + background-color: #fafafa; + } + + .action-menu-cancel { + display: none; + } + + .action-menu-has-icons { + + .button { + padding-left: 56px; + } + + } + +} diff --git a/ionic/components/action-menu/test/basic/index.js b/ionic/components/action-menu/test/basic/index.js index 3e17188dec..38207bd45a 100644 --- a/ionic/components/action-menu/test/basic/index.js +++ b/ionic/components/action-menu/test/basic/index.js @@ -19,8 +19,25 @@ class IonicApp { openMenu() { console.log('Opening ActionMenu') + ActionMenu.open({ - title: 'Do you really want to?' + buttons: [ + { text: 'Share This' }, + { text: 'Move' } + ], + destructiveText: 'Delete', + titleText: 'Modify your album', + cancelText: 'Cancel', + cancel: function() { + // add cancel code.. + console.log('Canceled'); + }, + buttonClicked: function(index) { + console.log('Button clicked', index); + return true; + } + }).then(actionMenu => { + this.actionMenu = actionMenu; }) } } diff --git a/ionic/components/app/app.js b/ionic/components/app/app.js index 1b1ece2973..48ec0c1970 100644 --- a/ionic/components/app/app.js +++ b/ionic/components/app/app.js @@ -37,7 +37,9 @@ class IonicAppRoot { document.body.querySelector('ion-app').appendChild(newEl); - resolve(newEl); + console.log('Injected and created', containerRef); + + resolve(containerRef.instance, containerRef.location); }); }); From 4e2b77092b1c2b0b04810f86340cb2372101b31b Mon Sep 17 00:00:00 2001 From: Max Lynch Date: Sat, 30 May 2015 11:02:31 -0500 Subject: [PATCH 2/6] Updated menu --- ionic/components/action-menu/action-menu.js | 48 ++++++++++++++++--- ionic/components/action-menu/action-menu.scss | 4 +- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/ionic/components/action-menu/action-menu.js b/ionic/components/action-menu/action-menu.js index f70d97bef2..b193665892 100644 --- a/ionic/components/action-menu/action-menu.js +++ b/ionic/components/action-menu/action-menu.js @@ -16,6 +16,30 @@ import * as util from 'ionic/util' import {Animation} from 'ionic/animations/animation'; +class ActionMenuSlideIn extends Animation { + constructor(element) { + super(element); + this + .easing('cubic-bezier(.36, .66, .04, 1)') + .duration(500) + .from('translateY', '100%') + .to('translateY', '0%'); + } +} +Animation.register('action-menu-slide-in', ActionMenuSlideIn); + +class ActionMenuSlideOut extends Animation { + constructor(element) { + super(element); + this + .easing('cubic-bezier(.36, .66, .04, 1)') + .duration(500) + .from('translateY', '0%') + .to('translateY', '100%'); + } +} +Animation.register('action-menu-slide-out', ActionMenuSlideIn); + @Component({ selector: 'ion-action-menu' }) @@ -23,7 +47,7 @@ import {Animation} from 'ionic/animations/animation'; template: `
-
+
{{titleText}}
@@ -48,15 +72,25 @@ export class ActionMenu { } close() { - var backdrop = this.domElement.children[0].classList.remove('active'); - var slideOut = Animation.create(this.wrapperEl, 'slide-out'); - return slideOut.play(); + raf(() => { + var backdrop = this.domElement.children[0].classList.remove('active'); + var slideOut = Animation.create(this.wrapperEl, 'action-menu-slide-out'); + + return slideOut.play().then(() => { + this.wrapperEl.classList.remove('action-menu-up'); + }) + }); } open() { - var backdrop = this.domElement.children[0].classList.add('active'); - var slideIn = Animation.create(this.wrapperEl, 'slide-in'); - return slideIn.play(); + raf(() => { + var backdrop = this.domElement.children[0].classList.add('active'); + var slideIn = Animation.create(this.wrapperEl, 'action-menu-slide-in'); + + return slideIn.play().then(() => { + this.wrapperEl.classList.add('action-menu-up'); + }) + }); } setOptions(opts) { diff --git a/ionic/components/action-menu/action-menu.scss b/ionic/components/action-menu/action-menu.scss index 9a3e3b24b2..2c2e01f177 100644 --- a/ionic/components/action-menu/action-menu.scss +++ b/ionic/components/action-menu/action-menu.scss @@ -51,7 +51,7 @@ $sheet-options-border-color: #d1d3d6 !default; } .action-menu-wrapper { - //transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); //transition: all cubic-bezier(.36, .66, .04, 1) 500ms; position: absolute; @@ -67,7 +67,7 @@ $sheet-options-border-color: #d1d3d6 !default; transform: translate3d(0, 0, 0); } -.action-menu { +.action-menu-container { margin-left: $sheet-margin; margin-right: $sheet-margin; width: auto; From 6ebb29d445511e7ac80d5d0399bd90432d5fc81c Mon Sep 17 00:00:00 2001 From: Max Lynch Date: Sat, 30 May 2015 11:46:01 -0500 Subject: [PATCH 3/6] Action Menu nice --- ionic/components/action-menu/action-menu.js | 239 +++++++++++------- .../action-menu/test/basic/index.js | 4 + ionic/components/app/app.js | 9 +- ionic/util/dom.js | 2 + 4 files changed, 165 insertions(+), 89 deletions(-) diff --git a/ionic/components/action-menu/action-menu.js b/ionic/components/action-menu/action-menu.js index b193665892..9d81e94d13 100644 --- a/ionic/components/action-menu/action-menu.js +++ b/ionic/components/action-menu/action-menu.js @@ -1,3 +1,11 @@ +/** +* @ngdoc service +* @name ActionMenu +* @module ionic +* @description +* The ActionMenu is a modal menu with options to select based on an action. +*/ + import {NgIf, NgFor, DynamicComponentLoader, ComponentLaoder, ElementRef, ComponentRef, onDestroy, DomRenderer} from 'angular2/angular2'; import {bind, Injector} from 'angular2/di'; import {Promise} from 'angular2/src/facade/async'; @@ -10,12 +18,153 @@ import {Parent} from 'angular2/src/core/annotations_impl/visibility'; import {Item, Icon} from 'ionic/ionic' import {Ionic} from 'ionic/components/app/app' import {IonicComponent} from 'ionic/config/component' -import {raf, ready} from 'ionic/util/dom' +import {raf, rafPromise, ready} from 'ionic/util/dom' import * as util from 'ionic/util' import {Animation} from 'ionic/animations/animation'; +@Component({ + selector: 'ion-action-menu' +}) +@View({ + template: ` +
+
+
+
+
{{options.titleText}}
+ + +
+
+ +
+
+
+
`, + directives: [Item,Icon, NgIf, NgFor] +}) +export class ActionMenu { + constructor(elementRef: ElementRef) { + this.domElement = elementRef.domElement + this.config = ActionMenu.config.invoke(this) + this.wrapperEl = this.domElement.querySelector('.action-menu-wrapper'); + + this.options = { + destructiveButtonClicked: util.noop, + buttonClicked: util.noop, + cancel: util.noop + }; + + console.log('ActionMenu: Component Created', this.domElement); + } + + /** + * Close the ActionMenu. + * + * @return Promise that resolves when the action menu is closed. + */ + close() { + return new Promise(resolve => { + raf(() => { + var backdrop = this.domElement.children[0].classList.remove('active'); + var slideOut = Animation.create(this.wrapperEl, 'action-menu-slide-out'); + + slideOut.play().then(() => { + this.wrapperEl.classList.remove('action-menu-up'); + this._clean(); + resolve(); + }) + }); + }); + } + + /** + * Open the Action Menu + * + * @return Promise that resolves when the action menu is open. + */ + open() { + return new Promise(resolve => { + raf(() => { + var backdrop = this.domElement.children[0].classList.add('active'); + var slideIn = Animation.create(this.wrapperEl, 'action-menu-slide-in'); + + slideIn.play().then(() => { + this.wrapperEl.classList.add('action-menu-up'); + resolve(); + }) + }); + }); + } + + /** + * Set the options (as in show()) + * + * @param opts the options to set + */ + setOptions(opts) { + util.extend(this.options, opts); + } + + /** + * Create and open a new Action Menu. This is the + * public API, and most often you will only use ActionMenu.open() + * + * @return Promise that resolves when the action menu is open. + */ + static open(opts) { + console.log('Opening menu', opts, Ionic); + + var promise = new Promise(resolve => { + ActionMenu._inject().then((ref) => { + let actionMenu = ref.instance; + actionMenu.ref = ref; + actionMenu.setOptions(opts); + actionMenu.open(); + resolve(actionMenu); + }); + }) + + return promise; + } + + static _inject() { + return Ionic.appendToRoot(ActionMenu); + } + + _clean() { + this.ref.dispose(); + } + + _cancel() { + this.options.cancel(); + this.close().then(() => { + }); + } + + + _destructiveButtonClicked() { + let shouldClose = this.options.destructiveButtonClicked(); + if(shouldClose === true) { + return this.close() + } + } + + _buttonClicked(index) { + let shouldClose = this.options.buttonClicked(index); + if(shouldClose === true) { + return this.close() + } + } +} + +new IonicComponent(ActionMenu, {}) + +/** + * Animations for action sheet + */ class ActionMenuSlideIn extends Animation { constructor(element) { super(element); @@ -38,90 +187,4 @@ class ActionMenuSlideOut extends Animation { .to('translateY', '100%'); } } -Animation.register('action-menu-slide-out', ActionMenuSlideIn); - -@Component({ - selector: 'ion-action-menu' -}) -@View({ - template: ` -
-
-
-
-
{{titleText}}
- - -
-
- -
-
-
-
`, - directives: [Item,Icon, NgIf, NgFor] -}) -export class ActionMenu { - constructor(elementRef: ElementRef) { - this.domElement = elementRef.domElement - this.config = ActionMenu.config.invoke(this) - - this.wrapperEl = this.domElement.querySelector('.action-menu-wrapper'); - - console.log('ActionMenu: Component Created', this.domElement); - } - - close() { - raf(() => { - var backdrop = this.domElement.children[0].classList.remove('active'); - var slideOut = Animation.create(this.wrapperEl, 'action-menu-slide-out'); - - return slideOut.play().then(() => { - this.wrapperEl.classList.remove('action-menu-up'); - }) - }); - } - - open() { - raf(() => { - var backdrop = this.domElement.children[0].classList.add('active'); - var slideIn = Animation.create(this.wrapperEl, 'action-menu-slide-in'); - - return slideIn.play().then(() => { - this.wrapperEl.classList.add('action-menu-up'); - }) - }); - } - - setOptions(opts) { - util.extend(this, opts); - } - - // Overridden by options - destructiveButtonClicked() {} - buttonClicked(index) {} - cancel() {} - - static open(opts) { - console.log('Opening menu', opts, Ionic); - - var promise = new Promise(resolve => { - ActionMenu._inject().then((actionMenu) => { - actionMenu.setOptions(opts); - setTimeout(() => { - actionMenu.open(); - }) - resolve(actionMenu); - }); - }) - - return promise; - } - - static _inject() { - return Ionic.appendToRoot(ActionMenu); - } - -} - -new IonicComponent(ActionMenu, {}) +Animation.register('action-menu-slide-out', ActionMenuSlideOut); diff --git a/ionic/components/action-menu/test/basic/index.js b/ionic/components/action-menu/test/basic/index.js index 38207bd45a..e1d17a2ec4 100644 --- a/ionic/components/action-menu/test/basic/index.js +++ b/ionic/components/action-menu/test/basic/index.js @@ -32,8 +32,12 @@ class IonicApp { // add cancel code.. console.log('Canceled'); }, + destructiveButtonClicked: () => { + console.log('Destructive clicked'); + }, buttonClicked: function(index) { console.log('Button clicked', index); + if(index == 1) { return false; } return true; } }).then(actionMenu => { diff --git a/ionic/components/app/app.js b/ionic/components/app/app.js index 48ec0c1970..3d30f4a2f3 100644 --- a/ionic/components/app/app.js +++ b/ionic/components/app/app.js @@ -22,6 +22,13 @@ class IonicAppRoot { return this.rootElementRef; } + /** + * Create and append the given component into the root + * element of the app. + * + * @param Component the ComponentClass to create and insert + * @return Promise that resolves with the ContainerRef created + */ appendToRoot(Component: Type) { var appRef = Ionic.getAppRef(); var injector = appRef.injector; @@ -39,7 +46,7 @@ class IonicAppRoot { console.log('Injected and created', containerRef); - resolve(containerRef.instance, containerRef.location); + resolve(containerRef);//containerRef.instance, containerRef.location); }); }); diff --git a/ionic/util/dom.js b/ionic/util/dom.js index 083f52f611..951f084dd8 100644 --- a/ionic/util/dom.js +++ b/ionic/util/dom.js @@ -1,3 +1,5 @@ +// Use Angular's promise which doesn't swallow exceptions +import {Promise} from 'angular2/src/facade/async'; const nativeRaf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || From f8f8145818779be192789d91bce75b385b95cf18 Mon Sep 17 00:00:00 2001 From: Max Lynch Date: Sat, 30 May 2015 12:46:20 -0500 Subject: [PATCH 4/6] Toolbar, view, kitchen sink --- ionic/components.js | 2 + ionic/components/app/structure.scss | 19 - .../app/test/sink/firebase-debug.js | 13050 ++++++++++++++++ ionic/components/app/test/sink/firebase.js | 263 + ionic/components/app/test/sink/hn.js | 33 + ionic/components/app/test/sink/index.js | 23 + ionic/components/app/test/sink/main.html | 29 + .../app/test/sink/pages/single.html | 6 + .../components/app/test/sink/pages/single.js | 25 + ionic/components/app/test/sink/pages/top.html | 9 + ionic/components/app/test/sink/pages/top.js | 93 + ionic/components/content/content.js | 10 +- ionic/components/toolbar/toolbar.js | 104 + ionic/components/toolbar/toolbar.scss | 63 + ionic/components/view/view.js | 15 + ionic/components/view/view.scss | 20 + ionic/ionic.scss | 4 +- 17 files changed, 13747 insertions(+), 21 deletions(-) create mode 100644 ionic/components/app/test/sink/firebase-debug.js create mode 100644 ionic/components/app/test/sink/firebase.js create mode 100644 ionic/components/app/test/sink/hn.js create mode 100644 ionic/components/app/test/sink/index.js create mode 100644 ionic/components/app/test/sink/main.html create mode 100644 ionic/components/app/test/sink/pages/single.html create mode 100644 ionic/components/app/test/sink/pages/single.js create mode 100644 ionic/components/app/test/sink/pages/top.html create mode 100644 ionic/components/app/test/sink/pages/top.js create mode 100644 ionic/components/toolbar/toolbar.js create mode 100644 ionic/components/toolbar/toolbar.scss create mode 100644 ionic/components/view/view.js create mode 100644 ionic/components/view/view.scss diff --git a/ionic/components.js b/ionic/components.js index e3a5d5851b..307f47ca71 100644 --- a/ionic/components.js +++ b/ionic/components.js @@ -24,5 +24,7 @@ export * from 'ionic/components/radio/radio' // export * from 'ionic/components/split-view/split-view' export * from 'ionic/components/segment/segment' export * from 'ionic/components/switch/switch' +export * from 'ionic/components/toolbar/toolbar' +export * from 'ionic/components/view/view' //export * from 'ionic/components/tabs/tabs' //export * from 'ionic/components/tabs/tab' diff --git a/ionic/components/app/structure.scss b/ionic/components/app/structure.scss index af24c56770..7514120f3f 100644 --- a/ionic/components/app/structure.scss +++ b/ionic/components/app/structure.scss @@ -62,25 +62,6 @@ ion-navbar { } -ion-view, -.ion-view { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - - // by default this is display: none; - // and the transition animation will display it - display: none; - flex-direction: column; - - &.show-view { - display: flex; - } - -} - ion-toolbar { display: flex; min-height: 4.4rem; diff --git a/ionic/components/app/test/sink/firebase-debug.js b/ionic/components/app/test/sink/firebase-debug.js new file mode 100644 index 0000000000..f3b7c8dde5 --- /dev/null +++ b/ionic/components/app/test/sink/firebase-debug.js @@ -0,0 +1,13050 @@ +/*! @license Firebase v2.2.4 + License: https://www.firebase.com/terms/terms-of-service.html */ +var CLOSURE_NO_DEPS = true; +var COMPILED = false; +var goog = goog || {}; +goog.global = this; +goog.global.CLOSURE_UNCOMPILED_DEFINES; +goog.global.CLOSURE_DEFINES; +goog.isDef = function(val) { + return val !== void 0; +}; +goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) { + var parts = name.split("."); + var cur = opt_objectToExportTo || goog.global; + if (!(parts[0] in cur) && cur.execScript) { + cur.execScript("var " + parts[0]); + } + for (var part;parts.length && (part = parts.shift());) { + if (!parts.length && goog.isDef(opt_object)) { + cur[part] = opt_object; + } else { + if (cur[part]) { + cur = cur[part]; + } else { + cur = cur[part] = {}; + } + } + } +}; +goog.define = function(name, defaultValue) { + var value = defaultValue; + if (!COMPILED) { + if (goog.global.CLOSURE_UNCOMPILED_DEFINES && Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) { + value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name]; + } else { + if (goog.global.CLOSURE_DEFINES && Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_DEFINES, name)) { + value = goog.global.CLOSURE_DEFINES[name]; + } + } + } + goog.exportPath_(name, value); +}; +goog.define("goog.DEBUG", true); +goog.define("goog.LOCALE", "en"); +goog.define("goog.TRUSTED_SITE", true); +goog.define("goog.STRICT_MODE_COMPATIBLE", false); +goog.define("goog.DISALLOW_TEST_ONLY_CODE", COMPILED && !goog.DEBUG); +goog.provide = function(name) { + if (!COMPILED) { + if (goog.isProvided_(name)) { + throw Error('Namespace "' + name + '" already declared.'); + } + } + goog.constructNamespace_(name); +}; +goog.constructNamespace_ = function(name, opt_obj) { + if (!COMPILED) { + delete goog.implicitNamespaces_[name]; + var namespace = name; + while (namespace = namespace.substring(0, namespace.lastIndexOf("."))) { + if (goog.getObjectByName(namespace)) { + break; + } + goog.implicitNamespaces_[namespace] = true; + } + } + goog.exportPath_(name, opt_obj); +}; +goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/; +goog.module = function(name) { + if (!goog.isString(name) || !name || name.search(goog.VALID_MODULE_RE_) == -1) { + throw Error("Invalid module identifier"); + } + if (!goog.isInModuleLoader_()) { + throw Error("Module " + name + " has been loaded incorrectly."); + } + if (goog.moduleLoaderState_.moduleName) { + throw Error("goog.module may only be called once per module."); + } + goog.moduleLoaderState_.moduleName = name; + if (!COMPILED) { + if (goog.isProvided_(name)) { + throw Error('Namespace "' + name + '" already declared.'); + } + delete goog.implicitNamespaces_[name]; + } +}; +goog.module.get = function(name) { + return goog.module.getInternal_(name); +}; +goog.module.getInternal_ = function(name) { + if (!COMPILED) { + if (goog.isProvided_(name)) { + return name in goog.loadedModules_ ? goog.loadedModules_[name] : goog.getObjectByName(name); + } else { + return null; + } + } +}; +goog.moduleLoaderState_ = null; +goog.isInModuleLoader_ = function() { + return goog.moduleLoaderState_ != null; +}; +goog.module.declareTestMethods = function() { + if (!goog.isInModuleLoader_()) { + throw new Error("goog.module.declareTestMethods must be called from " + "within a goog.module"); + } + goog.moduleLoaderState_.declareTestMethods = true; +}; +goog.module.declareLegacyNamespace = function() { + if (!COMPILED && !goog.isInModuleLoader_()) { + throw new Error("goog.module.declareLegacyNamespace must be called from " + "within a goog.module"); + } + if (!COMPILED && !goog.moduleLoaderState_.moduleName) { + throw Error("goog.module must be called prior to " + "goog.module.declareLegacyNamespace."); + } + goog.moduleLoaderState_.declareLegacyNamespace = true; +}; +goog.setTestOnly = function(opt_message) { + if (goog.DISALLOW_TEST_ONLY_CODE) { + opt_message = opt_message || ""; + throw Error("Importing test-only code into non-debug environment" + (opt_message ? ": " + opt_message : ".")); + } +}; +goog.forwardDeclare = function(name) { +}; +if (!COMPILED) { + goog.isProvided_ = function(name) { + return name in goog.loadedModules_ || !goog.implicitNamespaces_[name] && goog.isDefAndNotNull(goog.getObjectByName(name)); + }; + goog.implicitNamespaces_ = {"goog.module":true}; +} +goog.getObjectByName = function(name, opt_obj) { + var parts = name.split("."); + var cur = opt_obj || goog.global; + for (var part;part = parts.shift();) { + if (goog.isDefAndNotNull(cur[part])) { + cur = cur[part]; + } else { + return null; + } + } + return cur; +}; +goog.globalize = function(obj, opt_global) { + var global = opt_global || goog.global; + for (var x in obj) { + global[x] = obj[x]; + } +}; +goog.addDependency = function(relPath, provides, requires, opt_isModule) { + if (goog.DEPENDENCIES_ENABLED) { + var provide, require; + var path = relPath.replace(/\\/g, "/"); + var deps = goog.dependencies_; + for (var i = 0;provide = provides[i];i++) { + deps.nameToPath[provide] = path; + deps.pathIsModule[path] = !!opt_isModule; + } + for (var j = 0;require = requires[j];j++) { + if (!(path in deps.requires)) { + deps.requires[path] = {}; + } + deps.requires[path][require] = true; + } + } +}; +goog.define("goog.ENABLE_DEBUG_LOADER", true); +goog.logToConsole_ = function(msg) { + if (goog.global.console) { + goog.global.console["error"](msg); + } +}; +goog.require = function(name) { + if (!COMPILED) { + if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) { + goog.maybeProcessDeferredDep_(name); + } + if (goog.isProvided_(name)) { + if (goog.isInModuleLoader_()) { + return goog.module.getInternal_(name); + } else { + return null; + } + } + if (goog.ENABLE_DEBUG_LOADER) { + var path = goog.getPathFromDeps_(name); + if (path) { + goog.included_[path] = true; + goog.writeScripts_(); + return null; + } + } + var errorMessage = "goog.require could not find: " + name; + goog.logToConsole_(errorMessage); + throw Error(errorMessage); + } +}; +goog.basePath = ""; +goog.global.CLOSURE_BASE_PATH; +goog.global.CLOSURE_NO_DEPS; +goog.global.CLOSURE_IMPORT_SCRIPT; +goog.nullFunction = function() { +}; +goog.identityFunction = function(opt_returnValue, var_args) { + return opt_returnValue; +}; +goog.abstractMethod = function() { + throw Error("unimplemented abstract method"); +}; +goog.addSingletonGetter = function(ctor) { + ctor.getInstance = function() { + if (ctor.instance_) { + return ctor.instance_; + } + if (goog.DEBUG) { + goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor; + } + return ctor.instance_ = new ctor; + }; +}; +goog.instantiatedSingletons_ = []; +goog.define("goog.LOAD_MODULE_USING_EVAL", true); +goog.define("goog.SEAL_MODULE_EXPORTS", goog.DEBUG); +goog.loadedModules_ = {}; +goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER; +if (goog.DEPENDENCIES_ENABLED) { + goog.included_ = {}; + goog.dependencies_ = {pathIsModule:{}, nameToPath:{}, requires:{}, visited:{}, written:{}, deferred:{}}; + goog.inHtmlDocument_ = function() { + var doc = goog.global.document; + return typeof doc != "undefined" && "write" in doc; + }; + goog.findBasePath_ = function() { + if (goog.global.CLOSURE_BASE_PATH) { + goog.basePath = goog.global.CLOSURE_BASE_PATH; + return; + } else { + if (!goog.inHtmlDocument_()) { + return; + } + } + var doc = goog.global.document; + var scripts = doc.getElementsByTagName("script"); + for (var i = scripts.length - 1;i >= 0;--i) { + var script = (scripts[i]); + var src = script.src; + var qmark = src.lastIndexOf("?"); + var l = qmark == -1 ? src.length : qmark; + if (src.substr(l - 7, 7) == "base.js") { + goog.basePath = src.substr(0, l - 7); + return; + } + } + }; + goog.importScript_ = function(src, opt_sourceText) { + var importScript = goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_; + if (importScript(src, opt_sourceText)) { + goog.dependencies_.written[src] = true; + } + }; + goog.IS_OLD_IE_ = !goog.global.atob && goog.global.document && goog.global.document.all; + goog.importModule_ = function(src) { + var bootstrap = 'goog.retrieveAndExecModule_("' + src + '");'; + if (goog.importScript_("", bootstrap)) { + goog.dependencies_.written[src] = true; + } + }; + goog.queuedModules_ = []; + goog.wrapModule_ = function(srcUrl, scriptText) { + if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) { + return "" + "goog.loadModule(function(exports) {" + '"use strict";' + scriptText + "\n" + ";return exports" + "});" + "\n//# sourceURL=" + srcUrl + "\n"; + } else { + return "" + "goog.loadModule(" + goog.global.JSON.stringify(scriptText + "\n//# sourceURL=" + srcUrl + "\n") + ");"; + } + }; + goog.loadQueuedModules_ = function() { + var count = goog.queuedModules_.length; + if (count > 0) { + var queue = goog.queuedModules_; + goog.queuedModules_ = []; + for (var i = 0;i < count;i++) { + var path = queue[i]; + goog.maybeProcessDeferredPath_(path); + } + } + }; + goog.maybeProcessDeferredDep_ = function(name) { + if (goog.isDeferredModule_(name) && goog.allDepsAreAvailable_(name)) { + var path = goog.getPathFromDeps_(name); + goog.maybeProcessDeferredPath_(goog.basePath + path); + } + }; + goog.isDeferredModule_ = function(name) { + var path = goog.getPathFromDeps_(name); + if (path && goog.dependencies_.pathIsModule[path]) { + var abspath = goog.basePath + path; + return abspath in goog.dependencies_.deferred; + } + return false; + }; + goog.allDepsAreAvailable_ = function(name) { + var path = goog.getPathFromDeps_(name); + if (path && path in goog.dependencies_.requires) { + for (var requireName in goog.dependencies_.requires[path]) { + if (!goog.isProvided_(requireName) && !goog.isDeferredModule_(requireName)) { + return false; + } + } + } + return true; + }; + goog.maybeProcessDeferredPath_ = function(abspath) { + if (abspath in goog.dependencies_.deferred) { + var src = goog.dependencies_.deferred[abspath]; + delete goog.dependencies_.deferred[abspath]; + goog.globalEval(src); + } + }; + goog.loadModule = function(moduleDef) { + var previousState = goog.moduleLoaderState_; + try { + goog.moduleLoaderState_ = {moduleName:undefined, declareTestMethods:false}; + var exports; + if (goog.isFunction(moduleDef)) { + exports = moduleDef.call(goog.global, {}); + } else { + if (goog.isString(moduleDef)) { + exports = goog.loadModuleFromSource_.call(goog.global, moduleDef); + } else { + throw Error("Invalid module definition"); + } + } + var moduleName = goog.moduleLoaderState_.moduleName; + if (!goog.isString(moduleName) || !moduleName) { + throw Error('Invalid module name "' + moduleName + '"'); + } + if (goog.moduleLoaderState_.declareLegacyNamespace) { + goog.constructNamespace_(moduleName, exports); + } else { + if (goog.SEAL_MODULE_EXPORTS && Object.seal) { + Object.seal(exports); + } + } + goog.loadedModules_[moduleName] = exports; + if (goog.moduleLoaderState_.declareTestMethods) { + for (var entry in exports) { + if (entry.indexOf("test", 0) === 0 || entry == "tearDown" || entry == "setUp" || entry == "setUpPage" || entry == "tearDownPage") { + goog.global[entry] = exports[entry]; + } + } + } + } finally { + goog.moduleLoaderState_ = previousState; + } + }; + goog.loadModuleFromSource_ = function(source) { + var exports = {}; + eval(arguments[0]); + return exports; + }; + goog.writeScriptTag_ = function(src, opt_sourceText) { + if (goog.inHtmlDocument_()) { + var doc = goog.global.document; + if (doc.readyState == "complete") { + var isDeps = /\bdeps.js$/.test(src); + if (isDeps) { + return false; + } else { + throw Error('Cannot write "' + src + '" after document load'); + } + } + var isOldIE = goog.IS_OLD_IE_; + if (opt_sourceText === undefined) { + if (!isOldIE) { + doc.write('