diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index c7440c4..0000000 --- a/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -root = true - -[*] -end_of_line = lf -insert_final_newline = true -indent_size = 2 -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.js] -indent_style = space - -[*.php] -indent_style = tab diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 92b1b35..0000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -bower_components -.DS_Store -*~ -node_modules diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8628f7b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: php -php: - - 5.6 - -before_script: - # install hook server - - git clone --depth=1 https://github.com/doubleleft/hook.git - - travis_retry composer self-update - - travis_retry composer install --no-dev --prefer-dist -d hook - - cd ./hook && sh ./.travis/install_server.sh && cd - - - # create default app for testing - - curl -XPOST http://hook.dev/index.php/apps --data '{"app":{"name":"hook-javascript"}}' > tests/app.json - - cat tests/app.json - - # install javascript dependencies and compile dist files - - npm install -g grunt-cli - - npm install -g bower - - bower install - - npm install - - grunt - -script: - - grunt travis diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 1415678..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = function(grunt) { - grunt.loadNpmTasks('grunt-saucelabs'); - require('grunt-loader').load(grunt); -}; diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 507bcaf..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013-2014 Doubleleft - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile deleted file mode 100644 index 3318cba..0000000 --- a/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -publish-docs: - mkdir -p ../hook-javascript-docs - grunt yuidoc - git init ../hook-javascript-docs - cd ../hook-javascript-docs && git remote add origin git@github.com:doubleleft/hook-javascript.git && git checkout -b gh-pages && git add . && git commit -m "update public documentation" && git push origin gh-pages -f diff --git a/README.md b/README.md deleted file mode 100644 index 75e9dc0..0000000 --- a/README.md +++ /dev/null @@ -1,64 +0,0 @@ -hook-javascript client ![Build status](https://travis-ci.org/doubleleft/hook-javascript.svg?branch=master) -=== - -[![Selenium Test Status](https://saucelabs.com/browser-matrix/hook-javascript.svg)](https://saucelabs.com/u/hook-javascript) - -JavaScript client for [hook](https://github.com/doubleleft/hook). - -- [Documentation](http://doubleleft.github.io/hook-javascript/classes/Hook.Client.html). -- [Plugins](https://github.com/doubleleft/hook-javascript/wiki/Plugins). - -How to use ---- - -Initialize with your app's credentials: - -```javascript -var hook = new Hook.Client({ - endpoint: "http://localhost:4665/", - app_id: 1, // your app id - key: 'test' // browser credentials of your app -}); -``` - -Creating collection entries: - -```javascript -hook.collection('posts').create({ - title: "Post name", - summary: "My awesome new post", - stars: 5 -}); -``` - -Filtering: - -```javascript -hook.collection('posts').where('stars', '>=', 5).then(function(data) { - console.log(data); -}); -``` - -View full documentation [here](http://doubleleft.github.io/hook-javascript/classes/Hook.Client.html). - -How to build ---- - -You'll need [nodejs](http://nodejs.org/) installed first. Then run the following -commands: - - $ npm install -g grunt-cli bower - $ npm install - $ bower install - $ grunt - -To build and publish the docs: - -```bash -make publish-docs -``` - -License ---- - -MIT diff --git a/api.js b/api.js new file mode 100644 index 0000000..b7a6f94 --- /dev/null +++ b/api.js @@ -0,0 +1,42 @@ +YUI.add("yuidoc-meta", function(Y) { + Y.YUIDoc = { meta: { + "classes": [ + "Backbone.HookCollection", + "Backbone.HookModel", + "Cordova", + "Hook.Auth", + "Hook.Channel.SSE", + "Hook.Channel.WEBSOCKETS", + "Hook.Client", + "Hook.Collection", + "Hook.Events", + "Hook.Iterable", + "Hook.KeyValues", + "Hook.Pagination", + "Hook.Plugin.Cordova.PushNotification", + "Hook.PluginManager", + "Hook.System", + "OAuth" + ], + "modules": [ + "Backbone", + "Hook", + "Hook.Plugin" + ], + "allModules": [ + { + "displayName": "Backbone", + "name": "Backbone" + }, + { + "displayName": "Hook", + "name": "Hook", + "description": "Deals with user registration/authentication" + }, + { + "displayName": "Hook.Plugin", + "name": "Hook.Plugin" + } + ] +} }; +}); \ No newline at end of file diff --git a/assets/css/external-small.png b/assets/css/external-small.png new file mode 100644 index 0000000..759a1cd Binary files /dev/null and b/assets/css/external-small.png differ diff --git a/assets/css/logo.png b/assets/css/logo.png new file mode 100644 index 0000000..609b336 Binary files /dev/null and b/assets/css/logo.png differ diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..cdfe209 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,783 @@ +/* +Font sizes for all selectors other than the body are given in percentages, +with 100% equal to 13px. To calculate a font size percentage, multiply the +desired size in pixels by 7.6923076923. + +Here's a quick lookup table: + +10px - 76.923% +11px - 84.615% +12px - 92.308% +13px - 100% +14px - 107.692% +15px - 115.385% +16px - 123.077% +17px - 130.769% +18px - 138.462% +19px - 146.154% +20px - 153.846% +*/ + +html { + background: #fff; + color: #333; + overflow-y: scroll; +} + +body { + /*font: 13px/1.4 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', 'Bitstream Vera Sans', 'Helvetica', 'Arial', sans-serif;*/ + font: 13px/1.4 'Helvetica', 'Arial', sans-serif; + margin: 0; + padding: 0; +} + +/* -- Links ----------------------------------------------------------------- */ +a { + color: #356de4; + text-decoration: none; +} + +.hidden { + display: none; +} + +a:hover { text-decoration: underline; } + +/* "Jump to Table of Contents" link is shown to assistive tools, but hidden from + sight until it's focused. */ +.jump { + position: absolute; + padding: 3px 6px; + left: -99999px; + top: 0; +} + +.jump:focus { left: 40%; } + +/* -- Paragraphs ------------------------------------------------------------ */ +p { margin: 1.3em 0; } +dd p, td p { margin-bottom: 0; } +dd p:first-child, td p:first-child { margin-top: 0; } + +/* -- Headings -------------------------------------------------------------- */ +h1, h2, h3, h4, h5, h6 { + color: #D98527;/*was #f80*/ + font-family: 'Trebuchet MS', sans-serif; + font-weight: bold; + line-height: 1.1; + margin: 1.1em 0 0.5em; +} + +h1 { + font-size: 184.6%; + color: #30418C; + margin: 0.75em 0 0.5em; +} + +h2 { + font-size: 153.846%; + color: #E48A2B; +} + +h3 { font-size: 138.462%; } + +h4 { + border-bottom: 1px solid #DBDFEA; + color: #E48A2B; + font-size: 115.385%; + font-weight: normal; + padding-bottom: 2px; +} + +h5, h6 { font-size: 107.692%; } + +/* -- Code and examples ----------------------------------------------------- */ +code, kbd, pre, samp { + font-family: Menlo, Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; + font-size: 92.308%; + line-height: 1.35; +} + +p code, p kbd, p samp, li code { + background: #FCFBFA; + border: 1px solid #EFEEED; + padding: 0 3px; +} + +a code, a kbd, a samp, +pre code, pre kbd, pre samp, +table code, table kbd, table samp, +.intro code, .intro kbd, .intro samp, +.toc code, .toc kbd, .toc samp { + background: none; + border: none; + padding: 0; +} + +pre.code, pre.terminal, pre.cmd { + overflow-x: auto; + *overflow-x: scroll; + padding: 0.3em 0.6em; +} + +pre.code { + background: #FCFBFA; + border: 1px solid #EFEEED; + border-left-width: 5px; +} + +pre.terminal, pre.cmd { + background: #F0EFFC; + border: 1px solid #D0CBFB; + border-left: 5px solid #D0CBFB; +} + +/* Don't reduce the font size of // elements inside
+   blocks. */
+pre code, pre kbd, pre samp { font-size: 100%; }
+
+/* Used to denote text that shouldn't be selectable, such as line numbers or
+   shell prompts. Guess which browser this doesn't work in. */
+.noselect {
+    -moz-user-select: -moz-none;
+    -khtml-user-select: none;
+    -webkit-user-select: none;
+    -o-user-select: none;
+    user-select: none;
+}
+
+/* -- Lists ----------------------------------------------------------------- */
+dd { margin: 0.2em 0 0.7em 1em; }
+dl { margin: 1em 0; }
+dt { font-weight: bold; }
+
+/* -- Tables ---------------------------------------------------------------- */
+caption, th { text-align: left; }
+
+table {
+    border-collapse: collapse;
+    width: 100%;
+}
+
+td, th {
+    border: 1px solid #fff;
+    padding: 5px 12px;
+    vertical-align: top;
+}
+
+td { background: #E6E9F5; }
+td dl { margin: 0; }
+td dl dl { margin: 1em 0; }
+td pre:first-child { margin-top: 0; }
+
+th {
+    background: #D2D7E6;/*#97A0BF*/
+    border-bottom: none;
+    border-top: none;
+    color: #000;/*#FFF1D5*/
+    font-family: 'Trebuchet MS', sans-serif;
+    font-weight: bold;
+    line-height: 1.3;
+    white-space: nowrap;
+}
+
+
+/* -- Layout and Content ---------------------------------------------------- */
+#doc {
+    margin: auto;
+    min-width: 1024px;
+}
+
+.content { padding: 0 20px 0 25px; }
+
+.sidebar {
+    padding: 0 15px 0 10px;
+}
+#bd {
+    padding: 7px 0 130px;
+    position: relative;
+    width: 99%;
+}
+
+/* -- Table of Contents ----------------------------------------------------- */
+
+/* The #toc id refers to the single global table of contents, while the .toc
+   class refers to generic TOC lists that could be used throughout the page. */
+
+.toc code, .toc kbd, .toc samp { font-size: 100%; }
+.toc li { font-weight: bold; }
+.toc li li { font-weight: normal; }
+
+/* -- Intro and Example Boxes ----------------------------------------------- */
+/*
+.intro, .example { margin-bottom: 2em; }
+.example {
+    -moz-border-radius: 4px;
+    -webkit-border-radius: 4px;
+    border-radius: 4px;
+    -moz-box-shadow: 0 0 5px #bfbfbf;
+    -webkit-box-shadow: 0 0 5px #bfbfbf;
+    box-shadow: 0 0 5px #bfbfbf;
+    padding: 1em;
+}
+.intro {
+    background: none repeat scroll 0 0 #F0F1F8; border: 1px solid #D4D8EB; padding: 0 1em;
+}
+*/
+
+/* -- Other Styles ---------------------------------------------------------- */
+
+/* These are probably YUI-specific, and should be moved out of Selleck's default
+   theme. */
+
+.button {
+    border: 1px solid #dadada;
+    -moz-border-radius: 3px;
+    -webkit-border-radius: 3px;
+    border-radius: 3px;
+    color: #444;
+    display: inline-block;
+    font-family: Helvetica, Arial, sans-serif;
+    font-size: 92.308%;
+    font-weight: bold;
+    padding: 4px 13px 3px;
+    -moz-text-shadow: 1px 1px 0 #fff;
+    -webkit-text-shadow: 1px 1px 0 #fff;
+    text-shadow: 1px 1px 0 #fff;
+    white-space: nowrap;
+
+    background: #EFEFEF; /* old browsers */
+    background: -moz-linear-gradient(top, #f5f5f5 0%, #efefef 50%, #e5e5e5 51%, #dfdfdf 100%); /* firefox */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f5f5f5), color-stop(50%,#efefef), color-stop(51%,#e5e5e5), color-stop(100%,#dfdfdf)); /* webkit */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5f5f5', endColorstr='#dfdfdf',GradientType=0 ); /* ie */
+}
+
+.button:hover {
+    border-color: #466899;
+    color: #fff;
+    text-decoration: none;
+    -moz-text-shadow: 1px 1px 0 #222;
+    -webkit-text-shadow: 1px 1px 0 #222;
+    text-shadow: 1px 1px 0 #222;
+
+    background: #6396D8; /* old browsers */
+    background: -moz-linear-gradient(top, #6396D8 0%, #5A83BC 50%, #547AB7 51%, #466899 100%); /* firefox */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#6396D8), color-stop(50%,#5A83BC), color-stop(51%,#547AB7), color-stop(100%,#466899)); /* webkit */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#6396D8', endColorstr='#466899',GradientType=0 ); /* ie */
+}
+
+.newwindow { text-align: center; }
+
+.header .version em {
+    display: block;
+    text-align: right;
+}
+
+
+#classdocs .item {
+    border-bottom: 1px solid #466899;
+    margin: 1em 0;
+    padding: 1.5em;
+}
+
+#classdocs .item .params p,
+    #classdocs .item .returns p,{
+    display: inline;
+}
+
+#classdocs .item em code, #classdocs .item em.comment {
+    color: green;
+}
+
+#classdocs .item em.comment a {
+    color: green;
+    text-decoration: underline;
+}
+
+#classdocs .foundat {
+    font-size: 11px;
+    font-style: normal;
+}
+
+.attrs .emits {
+    margin-left: 2em;
+    padding: .5em;
+    border-left: 1px dashed #ccc;
+}
+
+abbr {
+    border-bottom: 1px dashed #ccc;
+    font-size: 80%;
+    cursor: help;
+}
+
+.prettyprint li.L0, 
+.prettyprint li.L1, 
+.prettyprint li.L2, 
+.prettyprint li.L3, 
+.prettyprint li.L5, 
+.prettyprint li.L6, 
+.prettyprint li.L7, 
+.prettyprint li.L8 {
+    list-style: decimal;
+}
+
+ul li p {
+    margin-top: 0;
+}
+
+.method .name {
+    font-size: 110%;
+}
+
+.apidocs .methods .extends .method,
+.apidocs .properties .extends .property,
+.apidocs .attrs .extends .attr,
+.apidocs .events .extends .event {
+    font-weight: bold;
+}
+
+.apidocs .methods .extends .inherited,
+.apidocs .properties .extends .inherited,
+.apidocs .attrs .extends .inherited,
+.apidocs .events .extends .inherited {
+    font-weight: normal;
+}
+
+#hd {
+    background: whiteSmoke;
+    background: -moz-linear-gradient(top,#DCDBD9 0,#F6F5F3 100%);
+    background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,#DCDBD9),color-stop(100%,#F6F5F3));
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dcdbd9',endColorstr='#F6F5F3',GradientType=0);
+    border-bottom: 1px solid #DFDFDF;
+    padding: 0 15px 1px 20px;
+    margin-bottom: 15px;
+}
+
+#hd img {
+    margin-right: 10px;
+    vertical-align: middle;
+}
+
+
+/* -- API Docs CSS ---------------------------------------------------------- */
+
+/*
+This file is organized so that more generic styles are nearer the top, and more
+specific styles are nearer the bottom of the file. This allows us to take full
+advantage of the cascade to avoid redundant style rules. Please respect this
+convention when making changes.
+*/
+
+/* -- Generic TabView styles ------------------------------------------------ */
+
+/*
+These styles apply to all API doc tabviews. To change styles only for a
+specific tabview, see the other sections below.
+*/
+
+.yui3-js-enabled .apidocs .tabview {
+    visibility: hidden; /* Hide until the TabView finishes rendering. */
+    _visibility: visible;
+}
+
+.apidocs .tabview.yui3-tabview-content { visibility: visible; }
+.apidocs .tabview .yui3-tabview-panel { background: #fff; }
+
+/* -- Generic Content Styles ------------------------------------------------ */
+
+/* Headings */
+h2, h3, h4, h5, h6 {
+    border: none;
+    color: #30418C;
+    font-weight: bold;
+    text-decoration: none;
+}
+
+.link-docs {
+    float: right;
+    font-size: 15px;
+    margin: 4px 4px 6px;
+    padding: 6px 30px 5px;
+}
+
+.apidocs { zoom: 1; }
+
+/* Generic box styles. */
+.apidocs .box {
+    border: 1px solid;
+    border-radius: 3px;
+    margin: 1em 0;
+    padding: 0 1em;
+}
+
+/* A flag is a compact, capsule-like indicator of some kind. It's used to
+   indicate private and protected items, item return types, etc. in an
+   attractive and unobtrusive way. */
+.apidocs .flag {
+    background: #bababa;
+    border-radius: 3px;
+    color: #fff;
+    font-size: 11px;
+    margin: 0 0.5em;
+    padding: 2px 4px 1px;
+}
+
+/* Class/module metadata such as "Uses", "Extends", "Defined in", etc. */
+.apidocs .meta {
+    background: #f9f9f9;
+    border-color: #efefef;
+    color: #555;
+    font-size: 11px;
+    padding: 3px 6px;
+}
+
+.apidocs .meta p { margin: 0; }
+
+/* Deprecation warning. */
+.apidocs .box.deprecated,
+.apidocs .flag.deprecated {
+    background: #fdac9f;
+    border: 1px solid #fd7775;
+}
+
+.apidocs .box.deprecated p { margin: 0.5em 0; }
+.apidocs .flag.deprecated { color: #333; }
+
+/* Module/Class intro description. */
+.apidocs .intro {
+    background: #f0f1f8;
+    border-color: #d4d8eb;
+}
+
+/* Loading spinners. */
+#bd.loading .apidocs,
+#api-list.loading .yui3-tabview-panel {
+    background: #fff url(../img/spinner.gif) no-repeat center 70px;
+    min-height: 150px;
+}
+
+#bd.loading .apidocs .content,
+#api-list.loading .yui3-tabview-panel .apis {
+    display: none;
+}
+
+.apidocs .no-visible-items { color: #666; }
+
+/* Generic inline list. */
+.apidocs ul.inline {
+    display: inline;
+    list-style: none;
+    margin: 0;
+    padding: 0;
+}
+
+.apidocs ul.inline li { display: inline; }
+
+/* Comma-separated list. */
+.apidocs ul.commas li:after { content: ','; }
+.apidocs ul.commas li:last-child:after { content: ''; }
+
+/* Keyboard shortcuts. */
+kbd .cmd { font-family: Monaco, Helvetica; }
+
+/* -- Generic Access Level styles ------------------------------------------- */
+.apidocs .item.protected,
+.apidocs .item.private,
+.apidocs .index-item.protected,
+.apidocs .index-item.deprecated,
+.apidocs .index-item.private {
+    display: none;
+}
+
+.show-deprecated .item.deprecated,
+.show-deprecated .index-item.deprecated,
+.show-protected .item.protected,
+.show-protected .index-item.protected,
+.show-private .item.private,
+.show-private .index-item.private {
+    display: block;
+}
+
+.hide-inherited .item.inherited,
+.hide-inherited .index-item.inherited {
+    display: none;
+}
+
+/* -- Generic Item Index styles --------------------------------------------- */
+.apidocs .index { margin: 1.5em 0 3em; }
+
+.apidocs .index h3 {
+    border-bottom: 1px solid #efefef;
+    color: #333;
+    font-size: 13px;
+    margin: 2em 0 0.6em;
+    padding-bottom: 2px;
+}
+
+.apidocs .index .no-visible-items { margin-top: 2em; }
+
+.apidocs .index-list {
+    border-color: #efefef;
+    font-size: 12px;
+    list-style: none;
+    margin: 0;
+    padding: 0;
+    -moz-column-count: 4;
+    -moz-column-gap: 10px;
+    -moz-column-width: 170px;
+    -ms-column-count: 4;
+    -ms-column-gap: 10px;
+    -ms-column-width: 170px;
+    -o-column-count: 4;
+    -o-column-gap: 10px;
+    -o-column-width: 170px;
+    -webkit-column-count: 4;
+    -webkit-column-gap: 10px;
+    -webkit-column-width: 170px;
+    column-count: 4;
+    column-gap: 10px;
+    column-width: 170px;
+}
+
+.apidocs .no-columns .index-list {
+    -moz-column-count: 1;
+    -ms-column-count: 1;
+    -o-column-count: 1;
+    -webkit-column-count: 1;
+    column-count: 1;
+}
+
+.apidocs .index-item { white-space: nowrap; }
+
+.apidocs .index-item .flag {
+    background: none;
+    border: none;
+    color: #afafaf;
+    display: inline;
+    margin: 0 0 0 0.2em;
+    padding: 0;
+}
+
+/* -- Generic API item styles ----------------------------------------------- */
+.apidocs .args {
+    display: inline;
+    margin: 0 0.5em;
+}
+
+.apidocs .flag.chainable { background: #46ca3b; }
+.apidocs .flag.protected { background: #9b86fc; }
+.apidocs .flag.private { background: #fd6b1b; }
+.apidocs .flag.async { background: #356de4; }
+.apidocs .flag.required { background: #e60923; }
+
+.apidocs .item {
+    border-bottom: 1px solid #efefef;
+    margin: 1.5em 0 2em;
+    padding-bottom: 2em;
+}
+
+.apidocs .item h4,
+.apidocs .item h5,
+.apidocs .item h6 {
+    color: #333;
+    font-family: inherit;
+    font-size: 100%;
+}
+
+.apidocs .item .description p,
+.apidocs .item pre.code {
+    margin: 1em 0 0;
+}
+
+.apidocs .item .meta {
+    background: none;
+    border: none;
+    padding: 0;
+}
+
+.apidocs .item .name {
+    display: inline;
+    font-size: 14px;
+}
+
+.apidocs .item .type,
+.apidocs .item .type a,
+.apidocs .returns-inline {
+    color: #555;
+}
+
+.apidocs .item .type,
+.apidocs .returns-inline {
+    font-size: 11px;
+    margin: 0 0 0 0;
+}
+
+.apidocs .item .type a { border-bottom: 1px dotted #afafaf; }
+.apidocs .item .type a:hover { border: none; }
+
+/* -- Item Parameter List --------------------------------------------------- */
+.apidocs .params-list {
+    list-style: square;
+    margin: 1em 0 0 2em;
+    padding: 0;
+}
+
+.apidocs .param { margin-bottom: 1em; }
+
+.apidocs .param .type,
+.apidocs .param .type a {
+    color: #666;
+}
+
+.apidocs .param .type {
+    margin: 0 0 0 0.5em;
+    *margin-left: 0.5em;
+}
+
+.apidocs .param-name { font-weight: bold; }
+
+/* -- Item "Emits" block ---------------------------------------------------- */
+.apidocs .item .emits {
+    background: #f9f9f9;
+    border-color: #eaeaea;
+}
+
+/* -- Item "Returns" block -------------------------------------------------- */
+.apidocs .item .returns .type,
+.apidocs .item .returns .type a {
+    font-size: 100%;
+    margin: 0;
+}
+
+/* -- Class Constructor block ----------------------------------------------- */
+.apidocs .constructor .item {
+    border: none;
+    padding-bottom: 0;
+}
+
+/* -- File Source View ------------------------------------------------------ */
+.apidocs .file pre.code,
+#doc .apidocs .file pre.prettyprint {
+    background: inherit;
+    border: none;
+    overflow: visible;
+    padding: 0;
+}
+
+.apidocs .L0,
+.apidocs .L1,
+.apidocs .L2,
+.apidocs .L3,
+.apidocs .L4,
+.apidocs .L5,
+.apidocs .L6,
+.apidocs .L7,
+.apidocs .L8,
+.apidocs .L9 {
+    background: inherit;
+}
+
+/* -- Submodule List -------------------------------------------------------- */
+.apidocs .module-submodule-description {
+    font-size: 12px;
+    margin: 0.3em 0 1em;
+}
+
+.apidocs .module-submodule-description p:first-child { margin-top: 0; }
+
+/* -- Sidebar TabView ------------------------------------------------------- */
+#api-tabview { margin-top: 0.6em; }
+
+#api-tabview-filter,
+#api-tabview-panel {
+    border: 1px solid #dfdfdf;
+}
+
+#api-tabview-filter {
+    border-bottom: none;
+    border-top: none;
+    padding: 0.6em 10px 0 10px;
+}
+
+#api-tabview-panel { border-top: none; }
+#api-filter { width: 97%; }
+
+/* -- Content TabView ------------------------------------------------------- */
+#classdocs .yui3-tabview-panel { border: none; }
+
+/* -- Source File Contents -------------------------------------------------- */
+.prettyprint li.L0,
+.prettyprint li.L1,
+.prettyprint li.L2,
+.prettyprint li.L3,
+.prettyprint li.L5,
+.prettyprint li.L6,
+.prettyprint li.L7,
+.prettyprint li.L8 {
+    list-style: decimal;
+}
+
+/* -- API options ----------------------------------------------------------- */
+#api-options {
+    font-size: 11px;
+    margin-top: 2.2em;
+    position: absolute;
+    right: 1.5em;
+}
+
+/*#api-options label { margin-right: 0.6em; }*/
+
+/* -- API list -------------------------------------------------------------- */
+#api-list {
+    margin-top: 1.5em;
+    *zoom: 1;
+}
+
+.apis {
+    font-size: 12px;
+    line-height: 1.4;
+    list-style: none;
+    margin: 0;
+    padding: 0.5em 0 0.5em 0.4em;
+}
+
+.apis a {
+    border: 1px solid transparent;
+    display: block;
+    margin: 0 0 0 -4px;
+    padding: 1px 4px 0;
+    text-decoration: none;
+    _border: none;
+    _display: inline;
+}
+
+.apis a:hover,
+.apis a:focus {
+    background: #E8EDFC;
+    background: -moz-linear-gradient(top, #e8edfc 0%, #becef7 100%);
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#E8EDFC), color-stop(100%,#BECEF7));
+    border-color: #AAC0FA;
+    border-radius: 3px;
+    color: #333;
+    outline: none;
+}
+
+.api-list-item a:hover,
+.api-list-item a:focus {
+    font-weight: bold;
+    text-shadow: 1px 1px 1px #fff;
+}
+
+.apis .message { color: #888; }
+.apis .result a { padding: 3px 5px 2px; }
+
+.apis .result .type {
+    right: 4px;
+    top: 7px;
+}
+
+.api-list-item .yui3-highlight {
+    font-weight: bold;
+}
+
diff --git a/assets/favicon.png b/assets/favicon.png
new file mode 100644
index 0000000..5a95dda
Binary files /dev/null and b/assets/favicon.png differ
diff --git a/assets/img/spinner.gif b/assets/img/spinner.gif
new file mode 100644
index 0000000..44f96ba
Binary files /dev/null and b/assets/img/spinner.gif differ
diff --git a/assets/index.html b/assets/index.html
new file mode 100644
index 0000000..487fe15
--- /dev/null
+++ b/assets/index.html
@@ -0,0 +1,10 @@
+
+
+    
+        Redirector
+        
+    
+    
+        Click here to redirect
+    
+
diff --git a/assets/js/api-filter.js b/assets/js/api-filter.js
new file mode 100644
index 0000000..37aefba
--- /dev/null
+++ b/assets/js/api-filter.js
@@ -0,0 +1,52 @@
+YUI.add('api-filter', function (Y) {
+
+Y.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], {
+    // -- Initializer ----------------------------------------------------------
+    initializer: function () {
+        this._bindUIACBase();
+        this._syncUIACBase();
+    },
+    getDisplayName: function(name) {
+
+        Y.each(Y.YUIDoc.meta.allModules, function(i) {
+            if (i.name === name && i.displayName) {
+                name = i.displayName;
+            }
+        });
+
+        return name;
+    }
+
+}, {
+    // -- Attributes -----------------------------------------------------------
+    ATTRS: {
+        resultHighlighter: {
+            value: 'phraseMatch'
+        },
+
+        // May be set to "classes" or "modules".
+        queryType: {
+            value: 'classes'
+        },
+
+        source: {
+            valueFn: function() {
+                var self = this;
+                return function(q) {
+                    var data = Y.YUIDoc.meta[self.get('queryType')],
+                        out = [];
+                    Y.each(data, function(v) {
+                        if (v.toLowerCase().indexOf(q.toLowerCase()) > -1) {
+                            out.push(v);
+                        }
+                    });
+                    return out;
+                };
+            }
+        }
+    }
+});
+
+}, '3.4.0', {requires: [
+    'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources'
+]});
diff --git a/assets/js/api-list.js b/assets/js/api-list.js
new file mode 100644
index 0000000..88905b5
--- /dev/null
+++ b/assets/js/api-list.js
@@ -0,0 +1,251 @@
+YUI.add('api-list', function (Y) {
+
+var Lang   = Y.Lang,
+    YArray = Y.Array,
+
+    APIList = Y.namespace('APIList'),
+
+    classesNode    = Y.one('#api-classes'),
+    inputNode      = Y.one('#api-filter'),
+    modulesNode    = Y.one('#api-modules'),
+    tabviewNode    = Y.one('#api-tabview'),
+
+    tabs = APIList.tabs = {},
+
+    filter = APIList.filter = new Y.APIFilter({
+        inputNode : inputNode,
+        maxResults: 1000,
+
+        on: {
+            results: onFilterResults
+        }
+    }),
+
+    search = APIList.search = new Y.APISearch({
+        inputNode : inputNode,
+        maxResults: 100,
+
+        on: {
+            clear  : onSearchClear,
+            results: onSearchResults
+        }
+    }),
+
+    tabview = APIList.tabview = new Y.TabView({
+        srcNode  : tabviewNode,
+        panelNode: '#api-tabview-panel',
+        render   : true,
+
+        on: {
+            selectionChange: onTabSelectionChange
+        }
+    }),
+
+    focusManager = APIList.focusManager = tabviewNode.plug(Y.Plugin.NodeFocusManager, {
+        circular   : true,
+        descendants: '#api-filter, .yui3-tab-panel-selected .api-list-item a, .yui3-tab-panel-selected .result a',
+        keys       : {next: 'down:40', previous: 'down:38'}
+    }).focusManager,
+
+    LIST_ITEM_TEMPLATE =
+        '
  • ' + + '{displayName}' + + '
  • '; + +// -- Init --------------------------------------------------------------------- + +// Duckpunch FocusManager's key event handling to prevent it from handling key +// events when a modifier is pressed. +Y.before(function (e, activeDescendant) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { + return new Y.Do.Prevent(); + } +}, focusManager, '_focusPrevious', focusManager); + +Y.before(function (e, activeDescendant) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { + return new Y.Do.Prevent(); + } +}, focusManager, '_focusNext', focusManager); + +// Create a mapping of tabs in the tabview so we can refer to them easily later. +tabview.each(function (tab, index) { + var name = tab.get('label').toLowerCase(); + + tabs[name] = { + index: index, + name : name, + tab : tab + }; +}); + +// Switch tabs on Ctrl/Cmd-Left/Right arrows. +tabviewNode.on('key', onTabSwitchKey, 'down:37,39'); + +// Focus the filter input when the `/` key is pressed. +Y.one(Y.config.doc).on('key', onSearchKey, 'down:83'); + +// Keep the Focus Manager up to date. +inputNode.on('focus', function () { + focusManager.set('activeDescendant', inputNode); +}); + +// Update all tabview links to resolved URLs. +tabview.get('panelNode').all('a').each(function (link) { + link.setAttribute('href', link.get('href')); +}); + +// -- Private Functions -------------------------------------------------------- +function getFilterResultNode() { + return filter.get('queryType') === 'classes' ? classesNode : modulesNode; +} + +// -- Event Handlers ----------------------------------------------------------- +function onFilterResults(e) { + var frag = Y.one(Y.config.doc.createDocumentFragment()), + resultNode = getFilterResultNode(), + typePlural = filter.get('queryType'), + typeSingular = typePlural === 'classes' ? 'class' : 'module'; + + if (e.results.length) { + YArray.each(e.results, function (result) { + frag.append(Lang.sub(LIST_ITEM_TEMPLATE, { + rootPath : APIList.rootPath, + displayName : filter.getDisplayName(result.highlighted), + name : result.text, + typePlural : typePlural, + typeSingular: typeSingular + })); + }); + } else { + frag.append( + '
  • ' + + 'No ' + typePlural + ' found.' + + '
  • ' + ); + } + + resultNode.empty(true); + resultNode.append(frag); + + focusManager.refresh(); +} + +function onSearchClear(e) { + + focusManager.refresh(); +} + +function onSearchKey(e) { + var target = e.target; + + if (target.test('input,select,textarea') + || target.get('isContentEditable')) { + return; + } + + e.preventDefault(); + + inputNode.focus(); + focusManager.refresh(); +} + +function onSearchResults(e) { + var frag = Y.one(Y.config.doc.createDocumentFragment()); + + if (e.results.length) { + YArray.each(e.results, function (result) { + frag.append(result.display); + }); + } else { + frag.append( + '
  • ' + + 'No results found. Maybe you\'ll have better luck with a ' + + 'different query?' + + '
  • ' + ); + } + + + focusManager.refresh(); +} + +function onTabSelectionChange(e) { + var tab = e.newVal, + name = tab.get('label').toLowerCase(); + + tabs.selected = { + index: tab.get('index'), + name : name, + tab : tab + }; + + switch (name) { + case 'classes': // fallthru + case 'modules': + filter.setAttrs({ + minQueryLength: 0, + queryType : name + }); + + search.set('minQueryLength', -1); + + // Only send a request if this isn't the initially-selected tab. + if (e.prevVal) { + filter.sendRequest(filter.get('value')); + } + break; + + case 'everything': + filter.set('minQueryLength', -1); + search.set('minQueryLength', 1); + + if (search.get('value')) { + search.sendRequest(search.get('value')); + } else { + inputNode.focus(); + } + break; + + default: + // WTF? We shouldn't be here! + filter.set('minQueryLength', -1); + search.set('minQueryLength', -1); + } + + if (focusManager) { + setTimeout(function () { + focusManager.refresh(); + }, 1); + } +} + +function onTabSwitchKey(e) { + var currentTabIndex = tabs.selected.index; + + if (!(e.ctrlKey || e.metaKey)) { + return; + } + + e.preventDefault(); + + switch (e.keyCode) { + case 37: // left arrow + if (currentTabIndex > 0) { + tabview.selectChild(currentTabIndex - 1); + inputNode.focus(); + } + break; + + case 39: // right arrow + if (currentTabIndex < (Y.Object.size(tabs) - 2)) { + tabview.selectChild(currentTabIndex + 1); + inputNode.focus(); + } + break; + } +} + +}, '3.4.0', {requires: [ + 'api-filter', 'api-search', 'event-key', 'node-focusmanager', 'tabview' +]}); diff --git a/assets/js/api-search.js b/assets/js/api-search.js new file mode 100644 index 0000000..175f6a6 --- /dev/null +++ b/assets/js/api-search.js @@ -0,0 +1,98 @@ +YUI.add('api-search', function (Y) { + +var Lang = Y.Lang, + Node = Y.Node, + YArray = Y.Array; + +Y.APISearch = Y.Base.create('apiSearch', Y.Base, [Y.AutoCompleteBase], { + // -- Public Properties ---------------------------------------------------- + RESULT_TEMPLATE: + '
  • ' + + '' + + '

    {name}

    ' + + '{resultType}' + + '
    {description}
    ' + + '{class}' + + '
    ' + + '
  • ', + + // -- Initializer ---------------------------------------------------------- + initializer: function () { + this._bindUIACBase(); + this._syncUIACBase(); + }, + + // -- Protected Methods ---------------------------------------------------- + _apiResultFilter: function (query, results) { + // Filter components out of the results. + return YArray.filter(results, function (result) { + return result.raw.resultType === 'component' ? false : result; + }); + }, + + _apiResultFormatter: function (query, results) { + return YArray.map(results, function (result) { + var raw = Y.merge(result.raw), // create a copy + desc = raw.description || ''; + + // Convert description to text and truncate it if necessary. + desc = Node.create('
    ' + desc + '
    ').get('text'); + + if (desc.length > 65) { + desc = Y.Escape.html(desc.substr(0, 65)) + ' …'; + } else { + desc = Y.Escape.html(desc); + } + + raw['class'] || (raw['class'] = ''); + raw.description = desc; + + // Use the highlighted result name. + raw.name = result.highlighted; + + return Lang.sub(this.RESULT_TEMPLATE, raw); + }, this); + }, + + _apiTextLocator: function (result) { + return result.displayName || result.name; + } +}, { + // -- Attributes ----------------------------------------------------------- + ATTRS: { + resultFormatter: { + valueFn: function () { + return this._apiResultFormatter; + } + }, + + resultFilters: { + valueFn: function () { + return this._apiResultFilter; + } + }, + + resultHighlighter: { + value: 'phraseMatch' + }, + + resultListLocator: { + value: 'data.results' + }, + + resultTextLocator: { + valueFn: function () { + return this._apiTextLocator; + } + }, + + source: { + value: '/api/v1/search?q={query}&count={maxResults}' + } + } +}); + +}, '3.4.0', {requires: [ + 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources', + 'escape' +]}); diff --git a/assets/js/apidocs.js b/assets/js/apidocs.js new file mode 100644 index 0000000..e00591c --- /dev/null +++ b/assets/js/apidocs.js @@ -0,0 +1,370 @@ +YUI().use( + 'yuidoc-meta', + 'api-list', 'history-hash', 'node-screen', 'node-style', 'pjax', +function (Y) { + +var win = Y.config.win, + localStorage = win.localStorage, + + bdNode = Y.one('#bd'), + + pjax, + defaultRoute, + + classTabView, + selectedTab; + +// Kill pjax functionality unless serving over HTTP. +if (!Y.getLocation().protocol.match(/^https?\:/)) { + Y.Router.html5 = false; +} + +// Create the default route with middleware which enables syntax highlighting +// on the loaded content. +defaultRoute = Y.Pjax.defaultRoute.concat(function (req, res, next) { + prettyPrint(); + bdNode.removeClass('loading'); + + next(); +}); + +pjax = new Y.Pjax({ + container : '#docs-main', + contentSelector: '#docs-main > .content', + linkSelector : '#bd a', + titleSelector : '#xhr-title', + + navigateOnHash: true, + root : '/', + routes : [ + // -- / ---------------------------------------------------------------- + { + path : '/(index.html)?', + callbacks: defaultRoute + }, + + // -- /classes/* ------------------------------------------------------- + { + path : '/classes/:class.html*', + callbacks: [defaultRoute, 'handleClasses'] + }, + + // -- /files/* --------------------------------------------------------- + { + path : '/files/*file', + callbacks: [defaultRoute, 'handleFiles'] + }, + + // -- /modules/* ------------------------------------------------------- + { + path : '/modules/:module.html*', + callbacks: defaultRoute + } + ] +}); + +// -- Utility Functions -------------------------------------------------------- + +pjax.checkVisibility = function (tab) { + tab || (tab = selectedTab); + + if (!tab) { return; } + + var panelNode = tab.get('panelNode'), + visibleItems; + + // If no items are visible in the tab panel due to the current visibility + // settings, display a message to that effect. + visibleItems = panelNode.all('.item,.index-item').some(function (itemNode) { + if (itemNode.getComputedStyle('display') !== 'none') { + return true; + } + }); + + panelNode.all('.no-visible-items').remove(); + + if (!visibleItems) { + if (Y.one('#index .index-item')) { + panelNode.append( + '
    ' + + '

    ' + + 'Some items are not shown due to the current visibility ' + + 'settings. Use the checkboxes at the upper right of this ' + + 'page to change the visibility settings.' + + '

    ' + + '
    ' + ); + } else { + panelNode.append( + '
    ' + + '

    ' + + 'This class doesn\'t provide any methods, properties, ' + + 'attributes, or events.' + + '

    ' + + '
    ' + ); + } + } + + // Hide index sections without any visible items. + Y.all('.index-section').each(function (section) { + var items = 0, + visibleItems = 0; + + section.all('.index-item').each(function (itemNode) { + items += 1; + + if (itemNode.getComputedStyle('display') !== 'none') { + visibleItems += 1; + } + }); + + section.toggleClass('hidden', !visibleItems); + section.toggleClass('no-columns', visibleItems < 4); + }); +}; + +pjax.initClassTabView = function () { + if (!Y.all('#classdocs .api-class-tab').size()) { + return; + } + + if (classTabView) { + classTabView.destroy(); + selectedTab = null; + } + + classTabView = new Y.TabView({ + srcNode: '#classdocs', + + on: { + selectionChange: pjax.onTabSelectionChange + } + }); + + pjax.updateTabState(); + classTabView.render(); +}; + +pjax.initLineNumbers = function () { + var hash = win.location.hash.substring(1), + container = pjax.get('container'), + hasLines, node; + + // Add ids for each line number in the file source view. + container.all('.linenums>li').each(function (lineNode, index) { + lineNode.set('id', 'l' + (index + 1)); + lineNode.addClass('file-line'); + hasLines = true; + }); + + // Scroll to the desired line. + if (hasLines && /^l\d+$/.test(hash)) { + if ((node = container.getById(hash))) { + win.scroll(0, node.getY()); + } + } +}; + +pjax.initRoot = function () { + var terminators = /^(?:classes|files|modules)$/, + parts = pjax._getPathRoot().split('/'), + root = [], + i, len, part; + + for (i = 0, len = parts.length; i < len; i += 1) { + part = parts[i]; + + if (part.match(terminators)) { + // Makes sure the path will end with a "/". + root.push(''); + break; + } + + root.push(part); + } + + pjax.set('root', root.join('/')); +}; + +pjax.updateTabState = function (src) { + var hash = win.location.hash.substring(1), + defaultTab, node, tab, tabPanel; + + function scrollToNode() { + if (node.hasClass('protected')) { + Y.one('#api-show-protected').set('checked', true); + pjax.updateVisibility(); + } + + if (node.hasClass('private')) { + Y.one('#api-show-private').set('checked', true); + pjax.updateVisibility(); + } + + setTimeout(function () { + // For some reason, unless we re-get the node instance here, + // getY() always returns 0. + var node = Y.one('#classdocs').getById(hash); + win.scrollTo(0, node.getY() - 70); + }, 1); + } + + if (!classTabView) { + return; + } + + if (src === 'hashchange' && !hash) { + defaultTab = 'index'; + } else { + if (localStorage) { + defaultTab = localStorage.getItem('tab_' + pjax.getPath()) || + 'index'; + } else { + defaultTab = 'index'; + } + } + + if (hash && (node = Y.one('#classdocs').getById(hash))) { + if ((tabPanel = node.ancestor('.api-class-tabpanel', true))) { + if ((tab = Y.one('#classdocs .api-class-tab.' + tabPanel.get('id')))) { + if (classTabView.get('rendered')) { + Y.Widget.getByNode(tab).set('selected', 1); + } else { + tab.addClass('yui3-tab-selected'); + } + } + } + + // Scroll to the desired element if this is a hash URL. + if (node) { + if (classTabView.get('rendered')) { + scrollToNode(); + } else { + classTabView.once('renderedChange', scrollToNode); + } + } + } else { + tab = Y.one('#classdocs .api-class-tab.' + defaultTab); + + // When the `defaultTab` node isn't found, `localStorage` is stale. + if (!tab && defaultTab !== 'index') { + tab = Y.one('#classdocs .api-class-tab.index'); + } + + if (classTabView.get('rendered')) { + Y.Widget.getByNode(tab).set('selected', 1); + } else { + tab.addClass('yui3-tab-selected'); + } + } +}; + +pjax.updateVisibility = function () { + var container = pjax.get('container'); + + container.toggleClass('hide-inherited', + !Y.one('#api-show-inherited').get('checked')); + + container.toggleClass('show-deprecated', + Y.one('#api-show-deprecated').get('checked')); + + container.toggleClass('show-protected', + Y.one('#api-show-protected').get('checked')); + + container.toggleClass('show-private', + Y.one('#api-show-private').get('checked')); + + pjax.checkVisibility(); +}; + +// -- Route Handlers ----------------------------------------------------------- + +pjax.handleClasses = function (req, res, next) { + var status = res.ioResponse.status; + + // Handles success and local filesystem XHRs. + if (res.ioResponse.readyState === 4 && (!status || (status >= 200 && status < 300))) { + pjax.initClassTabView(); + } + + next(); +}; + +pjax.handleFiles = function (req, res, next) { + var status = res.ioResponse.status; + + // Handles success and local filesystem XHRs. + if (res.ioResponse.readyState === 4 && (!status || (status >= 200 && status < 300))) { + pjax.initLineNumbers(); + } + + next(); +}; + +// -- Event Handlers ----------------------------------------------------------- + +pjax.onNavigate = function (e) { + var hash = e.hash, + originTarget = e.originEvent && e.originEvent.target, + tab; + + if (hash) { + tab = originTarget && originTarget.ancestor('.yui3-tab', true); + + if (hash === win.location.hash) { + pjax.updateTabState('hashchange'); + } else if (!tab) { + win.location.hash = hash; + } + + e.preventDefault(); + return; + } + + // Only scroll to the top of the page when the URL doesn't have a hash. + this.set('scrollToTop', !e.url.match(/#.+$/)); + + bdNode.addClass('loading'); +}; + +pjax.onOptionClick = function (e) { + pjax.updateVisibility(); +}; + +pjax.onTabSelectionChange = function (e) { + var tab = e.newVal, + tabId = tab.get('contentBox').getAttribute('href').substring(1); + + selectedTab = tab; + + // If switching from a previous tab (i.e., this is not the default tab), + // replace the history entry with a hash URL that will cause this tab to + // be selected if the user navigates away and then returns using the back + // or forward buttons. + if (e.prevVal && localStorage) { + localStorage.setItem('tab_' + pjax.getPath(), tabId); + } + + pjax.checkVisibility(tab); +}; + +// -- Init --------------------------------------------------------------------- + +pjax.on('navigate', pjax.onNavigate); + +pjax.initRoot(); +pjax.upgrade(); +pjax.initClassTabView(); +pjax.initLineNumbers(); +pjax.updateVisibility(); + +Y.APIList.rootPath = pjax.get('root'); + +Y.one('#api-options').delegate('click', pjax.onOptionClick, 'input'); + +Y.on('hashchange', function (e) { + pjax.updateTabState('hashchange'); +}, win); + +}); diff --git a/assets/js/yui-prettify.js b/assets/js/yui-prettify.js new file mode 100644 index 0000000..18de864 --- /dev/null +++ b/assets/js/yui-prettify.js @@ -0,0 +1,17 @@ +YUI().use('node', function(Y) { + var code = Y.all('.prettyprint.linenums'); + if (code.size()) { + code.each(function(c) { + var lis = c.all('ol li'), + l = 1; + lis.each(function(n) { + n.prepend(''); + l++; + }); + }); + var h = location.hash; + location.hash = ''; + h = h.replace('LINE_', 'LINENUM_'); + location.hash = h; + } +}); diff --git a/assets/vendor/prettify/CHANGES.html b/assets/vendor/prettify/CHANGES.html new file mode 100644 index 0000000..b50b841 --- /dev/null +++ b/assets/vendor/prettify/CHANGES.html @@ -0,0 +1,130 @@ + + + + Change Log + + + README + +

    Known Issues

    + + +

    Change Log

    +

    29 March 2007

    + +

    4 Jul 2008

    + +

    5 Jul 2008

    +
    +

    14 Jul 2008

    + +

    6 Jan 2009

    + +

    21 May 2009

    + +

    14 August 2009

    + +

    3 October 2009

    + +

    19 July 2010

    + + + diff --git a/assets/vendor/prettify/COPYING b/assets/vendor/prettify/COPYING new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/assets/vendor/prettify/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/assets/vendor/prettify/README.html b/assets/vendor/prettify/README.html new file mode 100644 index 0000000..c6fe1a3 --- /dev/null +++ b/assets/vendor/prettify/README.html @@ -0,0 +1,203 @@ + + + + + Javascript code prettifier + + + + + + + + + + Languages : CH +

    Javascript code prettifier

    + +

    Setup

    +
      +
    1. Download a distribution +
    2. Include the script and stylesheets in your document + (you will need to make sure the css and js file are on your server, and + adjust the paths in the script and link tag) +
      +<link href="prettify.css" type="text/css" rel="stylesheet" />
      +<script type="text/javascript" src="prettify.js"></script>
      +
    3. Add onload="prettyPrint()" to your + document's body tag. +
    4. Modify the stylesheet to get the coloring you prefer
    5. +
    + +

    Usage

    +

    Put code snippets in + <pre class="prettyprint">...</pre> + or <code class="prettyprint">...</code> + and it will automatically be pretty printed. + + + + +
    The original + Prettier +
    class Voila {
    +public:
    +  // Voila
    +  static const string VOILA = "Voila";
    +
    +  // will not interfere with embedded tags.
    +}
    + +
    class Voila {
    +public:
    +  // Voila
    +  static const string VOILA = "Voila";
    +
    +  // will not interfere with embedded tags.
    +}
    +
    + +

    FAQ

    +

    Which languages does it work for?

    +

    The comments in prettify.js are authoritative but the lexer + should work on a number of languages including C and friends, + Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles. + It works passably on Ruby, PHP, VB, and Awk and a decent subset of Perl + and Ruby, but, because of commenting conventions, doesn't work on + Smalltalk, or CAML-like languages.

    + +

    LISPy languages are supported via an extension: + lang-lisp.js.

    +

    And similarly for + CSS, + Haskell, + Lua, + OCAML, SML, F#, + Visual Basic, + SQL, + Protocol Buffers, and + WikiText.. + +

    If you'd like to add an extension for your favorite language, please + look at src/lang-lisp.js and file an + issue including your language extension, and a testcase.

    + +

    How do I specify which language my code is in?

    +

    You don't need to specify the language since prettyprint() + will guess. You can specify a language by specifying the language extension + along with the prettyprint class like so:

    +
    <pre class="prettyprint lang-html">
    +  The lang-* class specifies the language file extensions.
    +  File extensions supported by default include
    +    "bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html",
    +    "java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",
    +    "xhtml", "xml", "xsl".
    +</pre>
    + +

    It doesn't work on <obfuscated code sample>?

    +

    Yes. Prettifying obfuscated code is like putting lipstick on a pig + — i.e. outside the scope of this tool.

    + +

    Which browsers does it work with?

    +

    It's been tested with IE 6, Firefox 1.5 & 2, and Safari 2.0.4. + Look at the test page to see if it + works in your browser.

    + +

    What's changed?

    +

    See the change log

    + +

    Why doesn't Prettyprinting of strings work on WordPress?

    +

    Apparently wordpress does "smart quoting" which changes close quotes. + This causes end quotes to not match up with open quotes. +

    This breaks prettifying as well as copying and pasting of code samples. + See + WordPress's help center for info on how to stop smart quoting of code + snippets.

    + +

    How do I put line numbers in my code?

    +

    You can use the linenums class to turn on line + numbering. If your code doesn't start at line number 1, you can + add a colon and a line number to the end of that class as in + linenums:52. + +

    For example +

    <pre class="prettyprint linenums:4"
    +>// This is line 4.
    +foo();
    +bar();
    +baz();
    +boo();
    +far();
    +faz();
    +<pre>
    + produces +
    // This is line 4.
    +foo();
    +bar();
    +baz();
    +boo();
    +far();
    +faz();
    +
    + +

    How do I prevent a portion of markup from being marked as code?

    +

    You can use the nocode class to identify a span of markup + that is not code. +

    <pre class=prettyprint>
    +int x = foo();  /* This is a comment  <span class="nocode">This is not code</span>
    +  Continuation of comment */
    +int y = bar();
    +</pre>
    +produces +
    +int x = foo();  /* This is a comment  This is not code
    +  Continuation of comment */
    +int y = bar();
    +
    + +

    For a more complete example see the issue22 + testcase.

    + +

    I get an error message "a is not a function" or "opt_whenDone is not a function"

    +

    If you are calling prettyPrint via an event handler, wrap it in a function. + Instead of doing +

    + addEventListener('load', prettyPrint, false); +
    + wrap it in a closure like +
    + addEventListener('load', function (event) { prettyPrint() }, false); +
    + so that the browser does not pass an event object to prettyPrint which + will confuse it. + +


    + + + + diff --git a/assets/vendor/prettify/prettify-min.css b/assets/vendor/prettify/prettify-min.css new file mode 100644 index 0000000..d44b3a2 --- /dev/null +++ b/assets/vendor/prettify/prettify-min.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} \ No newline at end of file diff --git a/assets/vendor/prettify/prettify-min.js b/assets/vendor/prettify/prettify-min.js new file mode 100644 index 0000000..4845d05 --- /dev/null +++ b/assets/vendor/prettify/prettify-min.js @@ -0,0 +1 @@ +window.PR_SHOULD_USE_CONTINUATION=true;var prettyPrintOne;var prettyPrint;(function(){var O=window;var j=["break,continue,do,else,for,if,return,while"];var v=[j,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var q=[v,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var m=[q,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var y=[q,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var T=[y,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"];var s="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes";var x=[q,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var t="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var J=[j,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var g=[j,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var I=[j,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var B=[m,T,x,t+J,g,I];var f=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;var D="str";var A="kwd";var k="com";var Q="typ";var H="lit";var M="pun";var G="pln";var n="tag";var F="dec";var K="src";var R="atn";var o="atv";var P="nocode";var N="(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function l(ab){var af=0;var U=false;var ae=false;for(var X=0,W=ab.length;X122)){if(!(am<65||ai>90)){ah.push([Math.max(65,ai)|32,Math.min(am,90)|32])}if(!(am<97||ai>122)){ah.push([Math.max(97,ai)&~32,Math.min(am,122)&~32])}}}}ah.sort(function(aw,av){return(aw[0]-av[0])||(av[1]-aw[1])});var ak=[];var aq=[];for(var at=0;atau[0]){if(au[1]+1>au[0]){ao.push("-")}ao.push(V(au[1]))}}ao.push("]");return ao.join("")}function Y(an){var al=an.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var aj=al.length;var ap=[];for(var am=0,ao=0;am=2&&ak==="["){al[am]=Z(ai)}else{if(ak!=="\\"){al[am]=ai.replace(/[a-zA-Z]/g,function(aq){var ar=aq.charCodeAt(0);return"["+String.fromCharCode(ar&~32,ar|32)+"]"})}}}}return al.join("")}var ac=[];for(var X=0,W=ab.length;X=0;){U[ae.charAt(ag)]=aa}}var ah=aa[1];var ac=""+ah;if(!ai.hasOwnProperty(ac)){aj.push(ah);ai[ac]=null}}aj.push(/[\0-\uffff]/);X=l(aj)})();var Z=V.length;var Y=function(aj){var ab=aj.sourceCode,aa=aj.basePos;var af=[aa,G];var ah=0;var ap=ab.match(X)||[];var al={};for(var ag=0,at=ap.length;ag=5&&"lang-"===ar.substring(0,5);if(ao&&!(ak&&typeof ak[1]==="string")){ao=false;ar=K}if(!ao){al[ai]=ar}}var ad=ah;ah+=ai.length;if(!ao){af.push(aa+ad,ar)}else{var an=ak[1];var am=ai.indexOf(an);var ae=am+an.length;if(ak[2]){ae=ai.length-ak[2].length;am=ae-an.length}var au=ar.substring(5);C(aa+ad,ai.substring(0,am),Y,af);C(aa+ad+am,an,r(au,an),af);C(aa+ad+ae,ai.substring(ae),Y,af)}}aj.decorations=af};return Y}function i(V){var Y=[],U=[];if(V.tripleQuotedStrings){Y.push([D,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(V.multiLineStrings){Y.push([D,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{Y.push([D,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(V.verbatimStrings){U.push([D,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var ab=V.hashComments;if(ab){if(V.cStyleComments){if(ab>1){Y.push([k,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{Y.push([k,/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}U.push([D,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])}else{Y.push([k,/^#[^\r\n]*/,null,"#"])}}if(V.cStyleComments){U.push([k,/^\/\/[^\r\n]*/,null]);U.push([k,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(V.regexLiterals){var aa=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");U.push(["lang-regex",new RegExp("^"+N+"("+aa+")")])}var X=V.types;if(X){U.push([Q,X])}var W=(""+V.keywords).replace(/^ | $/g,"");if(W.length){U.push([A,new RegExp("^(?:"+W.replace(/[\s,]+/g,"|")+")\\b"),null])}Y.push([G,/^\s+/,null," \r\n\t\xA0"]);var Z=/^.[^\s\w\.$@\'\"\`\/\\]*/;U.push([H,/^@[a-z_$][a-z_$@0-9]*/i,null],[Q,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[G,/^[a-z_$][a-z_$@0-9]*/i,null],[H,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[G,/^\\[\s\S]?/,null],[M,Z,null]);return h(Y,U)}var L=i({keywords:B,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function S(W,ah,aa){var V=/(?:^|\s)nocode(?:\s|$)/;var ac=/\r\n?|\n/;var ad=W.ownerDocument;var ag=ad.createElement("li");while(W.firstChild){ag.appendChild(W.firstChild)}var X=[ag];function af(am){switch(am.nodeType){case 1:if(V.test(am.className)){break}if("br"===am.nodeName){ae(am);if(am.parentNode){am.parentNode.removeChild(am)}}else{for(var ao=am.firstChild;ao;ao=ao.nextSibling){af(ao)}}break;case 3:case 4:if(aa){var an=am.nodeValue;var ak=an.match(ac);if(ak){var aj=an.substring(0,ak.index);am.nodeValue=aj;var ai=an.substring(ak.index+ak[0].length);if(ai){var al=am.parentNode;al.insertBefore(ad.createTextNode(ai),am.nextSibling)}ae(am);if(!aj){am.parentNode.removeChild(am)}}}break}}function ae(al){while(!al.nextSibling){al=al.parentNode;if(!al){return}}function aj(am,at){var ar=at?am.cloneNode(false):am;var ap=am.parentNode;if(ap){var aq=aj(ap,1);var ao=am.nextSibling;aq.appendChild(ar);for(var an=ao;an;an=ao){ao=an.nextSibling;aq.appendChild(an)}}return ar}var ai=aj(al.nextSibling,0);for(var ak;(ak=ai.parentNode)&&ak.nodeType===1;){ai=ak}X.push(ai)}for(var Z=0;Z=U){aj+=2}if(Y>=ar){ac+=2}}}finally{if(au){au.style.display=ak}}}var u={};function d(W,X){for(var U=X.length;--U>=0;){var V=X[U];if(!u.hasOwnProperty(V)){u[V]=W}else{if(O.console){console.warn("cannot override language handler %s",V)}}}}function r(V,U){if(!(V&&u.hasOwnProperty(V))){V=/^\s*]*(?:>|$)/],[k,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[M,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);d(h([[G,/^[\s]+/,null," \t\r\n"],[o,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[n,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[R,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[M,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);d(h([],[[o,/^[\s\S]+/]]),["uq.val"]);d(i({keywords:m,hashComments:true,cStyleComments:true,types:f}),["c","cc","cpp","cxx","cyc","m"]);d(i({keywords:"null,true,false"}),["json"]);d(i({keywords:T,hashComments:true,cStyleComments:true,verbatimStrings:true,types:f}),["cs"]);d(i({keywords:y,cStyleComments:true}),["java"]);d(i({keywords:I,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);d(i({keywords:J,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);d(i({keywords:t,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);d(i({keywords:g,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);d(i({keywords:x,cStyleComments:true,regexLiterals:true}),["js"]);d(i({keywords:s,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);d(h([],[[D,/^[\s\S]+/]]),["regex"]);function e(X){var W=X.langExtension;try{var U=b(X.sourceNode,X.pre);var V=U.sourceCode;X.sourceCode=V;X.spans=U.spans;X.basePos=0;r(W,V)(X);E(X)}catch(Y){if(O.console){console.log(Y&&Y.stack?Y.stack:Y)}}}function z(Y,X,W){var U=document.createElement("pre");U.innerHTML=Y;if(W){S(U,W,true)}var V={langExtension:X,numberLines:W,sourceNode:U,pre:1};e(V);return U.innerHTML}function c(aj){function ab(al){return document.getElementsByTagName(al)}var ah=[ab("pre"),ab("code"),ab("xmp")];var V=[];for(var ae=0;ae]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); \ No newline at end of file diff --git a/bower.json b/bower.json deleted file mode 100644 index f418c82..0000000 --- a/bower.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "hook-javascript", - "description": "hook javascript client", - "homepage": "https://github.com/doubleleft/hook-javascript", - "main": "./dist/hook.js", - "ignore": [ - "src", - "hook-ext", - "docs", - "grunt", - "tests", - "yuidoc-theme", - "node_modules", - "bower_components" - ], - "dependencies" : { - }, - "devDependencies": { - "json.date": "RickStrahl/json.date-extensions#f16379c45f0150047c547ab821e94aad00b2c2a9", - "uxhr": "endel/uxhr#a484e430e224375b786072da5abb94dfd3c68685", - "qunit": "~1.9.0", - "es6-promise": "~2.2.0", - "lodash": "~2.4.0", - "blueimp-canvas-to-blob": "~2.1.0", - "event-source-polyfill": "0.0.1", - "AutobahnJS": "tavendo/AutobahnJS#v0.8.2", - "backbone": "~1.1.2", - "jquery": "~2.1.0", - "winchan": "mozilla/winchan#ac4b142c34daa84bbcb5d8663fad19ce6394cb18" - } -} diff --git a/classes/Backbone.HookCollection.html b/classes/Backbone.HookCollection.html new file mode 100644 index 0000000..039e292 --- /dev/null +++ b/classes/Backbone.HookCollection.html @@ -0,0 +1,301 @@ + + + + + Backbone.HookCollection - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Backbone.HookCollection Class

    +
    + + + + + + + + + Module: Backbone + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    fetchRemote

    + + +
    + (
      + +
    • + + models + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Reset collection data and triggers 'fetch' event.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + models + Array + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Backbone.HookModel.html b/classes/Backbone.HookModel.html new file mode 100644 index 0000000..c9e9ef1 --- /dev/null +++ b/classes/Backbone.HookModel.html @@ -0,0 +1,194 @@ + + + + + Backbone.HookModel - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Backbone.HookModel Class

    +
    + + + + + + + + + Module: Backbone + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + + + + + + + +
    + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Cordova.html b/classes/Cordova.html new file mode 100644 index 0000000..d572e01 --- /dev/null +++ b/classes/Cordova.html @@ -0,0 +1,257 @@ + + + + + Cordova - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Cordova Class

    +
    + + + + + + + + + Module: Hook.Plugin + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + + + +
    +

    Properties

    + +
      + +
    • + push + + + +
    • + +
    +
    + + + + + +
    + + + + +
    +

    Properties

    + + +
    +

    push

    + Hook.Plugin.Cordova.PushNotification + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Auth.html b/classes/Hook.Auth.html new file mode 100644 index 0000000..a33e716 --- /dev/null +++ b/classes/Hook.Auth.html @@ -0,0 +1,1159 @@ + + + + + Hook.Auth - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Auth Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    +

    Deals with user registration/authentication

    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + +
    +

    Properties

    + + +
    + + + + + +
    + + +
    +

    Methods

    + + +
    +

    forgotPassword

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Send a 'forgot password' confirmation email to target user email address.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +
    client.auth.forgotPassword({
    +  email: "edreyer@doubleleft.com",
    +  subject: "Project name: Forgot your password?",
    +  template: "Hi {{name}}, click here to reset your password http://custom-project.com/pass-recovery-path.html?token={{token}}"
    +}).then(function(data){
    +  console.log("Email enviado!", data);
    +}, function(data){
    +  console.log("User not found: ", data);
    +});
    + +
    +
    + +
    + + +
    +

    getToken

    + + + () + + + + + String | Null + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + + + +
    +

    Returns:

    + +
    + + + String | Null: + + +
    +
    + + + +
    + + +
    +

    login

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Verify if user is already registered, and log-in if succeed.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +
    client.auth.login({email: "edreyer@doubleleft.com", password: "123"}).then(function(data){
    +  console.log("User found: ", data);
    +}, function(data){
    +  console.log("User not found or password invalid.", data);
    +});
    + +
    +
    + +
    + + +
    +

    logout

    + + + () + + + + + Hook.Auth + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + + + +
    +

    Returns:

    + +
    + + + Hook.Auth: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    register

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Register a user.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    +

    Example:

    + +
    +

    Register with email address

    +
    client.auth.register({
    +  email: "endel@doubleleft.com",
    +  password: "12345",
    +  name: "Endel Dreyer"
    +}).then(function(user) {
    +  console.log("Registered user: ", user);
    +});
    + +
    +
    + +
    + + +
    +

    resetPassword

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Reset user password

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
        + +
      • + + password + Object + + +
        + +
        + + +
      • + +
      • + + token + Object + + +
        +

        [optional]

        + +
        + + +
      • + +
      + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Getting token automatically from query string

    +
    client.auth.resetPassword("my-new-password-123").then(function(data){
    +  console.log("Password reseted! ", data);
    +}, function(data){
    +  console.log("Error", data.error);
    +});
    +

    Providing a token manually

    +
    client.auth.resetPassword({token: "xxx", password: "my-new-password-123"}).then(function(data){
    +  console.log("Password reseted! ", data);
    +}, function(data){
    +  console.log("Error", data.error);
    +});
    + +
    +
    + +
    + + +
    +

    setUserData

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + Hook.Auth + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Auth: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    update

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Update current user info.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +
    client.auth.update({ score: 100 }).then(function(data){
    +  console.log("updated successfully: ", data);
    +}).otherwise(function(data){
    +  console.log("error: ", data);
    +});
    + +
    +
    + +
    + + +
    + + + +
    +

    Properties

    + + +
    +

    currentUser

    + Object + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Channel.SSE.html b/classes/Hook.Channel.SSE.html new file mode 100644 index 0000000..7396855 --- /dev/null +++ b/classes/Hook.Channel.SSE.html @@ -0,0 +1,848 @@ + + + + + Hook.Channel.SSE - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Channel.SSE Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    close

    + + + () + + + + + Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Close event source connection.

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Channel: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    disconnect

    + + +
    + (
      + +
    • + + synchronous + +
    • + +
    ) +
    + + + + + Hook.Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Disconnect from channel, publishing a 'disconnected' message.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + synchronous + Boolean + + + + +
      +

      default = false

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Channel: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    isConnected

    + + + () + + + + + Boolean + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Is EventSource listenning to messages?

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Boolean: + + +
    +
    + + + +
    + + +
    +

    publish

    + + +
    + (
      + +
    • + + event + +
    • + +
    • + + message + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Publish event message

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + event + String + + + + +
      + +
      + + +
    • + +
    • + + message + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    subscribe

    + + +
    + (
      + +
    • + + event + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Subscribe to channel. Publishes a 'connected' message on the first time.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + event + String + + + + +
      +

      (optional)

      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Registering for all messages

    +
    channel.subscribe(function(event, data) {
    +  console.log("Message: ", event, data);
    +})
    +

    Registering for a single custom event

    +
    channel.subscribe('some-event', function(data) {
    +  console.log("Custom event triggered: ", data);
    +})
    +

    Registering for client connected/disconnected events

    +
    channel.subscribe('connected', function(data) {
    +  console.log("New client connected: ", data.client_id);
    +});
    +channel.subscribe('disconnected', function(data) {
    +  console.log("Client disconnected: ", data.client_id);
    +});
    +

    Registering error event

    +
    channel.subscribe('state:open', function(e) {
    +  console.log("Error: ", e);
    +});
    +channel.subscribe('state:error', function(e) {
    +  console.log("Error: ", e);
    +});
    + +
    +
    + +
    + + +
    +

    unsubscribe

    + + +
    + (
      + +
    • + + event + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Unsubscribe to a event listener

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + event + String + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Channel.WEBSOCKETS.html b/classes/Hook.Channel.WEBSOCKETS.html new file mode 100644 index 0000000..874ec30 --- /dev/null +++ b/classes/Hook.Channel.WEBSOCKETS.html @@ -0,0 +1,871 @@ + + + + + Hook.Channel.WEBSOCKETS - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Channel.WEBSOCKETS Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    call

    + + +
    + (
      + +
    • + + procedure + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + procedure + String + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    disconnect

    + + + () + + + + + Hook.Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Disconnect from channel, publishing a 'disconnected' message.

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Hook.Channel: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    isConnected

    + + + () + + + + + Boolean + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Is EventSource listenning to messages?

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Boolean: + + +
    +
    + + + +
    + + +
    +

    publish

    + + +
    + (
      + +
    • + + event + +
    • + +
    • + + message + +
    • + +
    • + + options + +
    • + +
    ) +
    + + + + + Hook.Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Publish event message

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + event + String + + + + +
      + +
      + + +
    • + +
    • + + message + Object + + + + +
      + +
      + + +
    • + +
    • + + options + Object + + + + +
      +

      'exclude' and 'elegible' are optional options.

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Channel: + + +
    +
    + + + +
    + + +
    +

    subscribe

    + + +
    + (
      + +
    • + + event + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Hook.Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Subscribe to channel. Publishes a 'connected' message on the first time.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + event + String + + + + +
      +

      (optional)

      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Channel: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Registering for a single custom event

    +
    channel.subscribe('some-event', function(data) {
    +  console.log("Custom event triggered: ", data);
    +})
    +

    Registering for client connected/disconnected events

    +
    channel.subscribe('connected', function(data) {
    +  console.log("New client connected: ", data.client_id);
    +});
    +channel.subscribe('disconnected', function(data) {
    +  console.log("Client disconnected: ", data.client_id);
    +});
    + +
    +
    + +
    + + +
    +

    unsubscribe

    + + +
    + (
      + +
    • + + event + +
    • + +
    ) +
    + + + + + Hook.Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Unsubscribe to a event listener

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + event + String + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Channel: + + +
    +
    + + + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Client.html b/classes/Hook.Client.html new file mode 100644 index 0000000..75f7052 --- /dev/null +++ b/classes/Hook.Client.html @@ -0,0 +1,1518 @@ + + + + + Hook.Client - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Client Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    +

    Hook.Client is the entry-point for using hook.

    +

    You should instantiate a global javascript client for consuming hook.

    +
    var client = new Hook.Client({
    +  url: "http://local-or-remote-hook-address.com/public/index.php/",
    +  app_id: 1,   // your app's id
    +  key: 'test'  // your app's public key
    +});
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + +
    +

    Properties

    + + +
    + + + + + +
    + + +
    +

    Methods

    + + +
    +

    channel

    + + +
    + (
      + +
    • + + name + +
    • + +
    • + + options + +
    • + +
    ) +
    + + + + + Hook.Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Get channel instance.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + name + String + + + + +
      + +
      + + +
    • + +
    • + + options + Object + + + + +
      +

      (optional)

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Channel: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Create a channel using Servet-Sent Events transport.

    +
    var channel = client.channel('messages');
    +

    Create a channel using WebSockets transport.

    +
    var channel = client.channel('messages', { transport: "websockets" });
    + +
    +
    + +
    + + +
    +

    collection

    + + +
    + (
      + +
    • + + collectionName + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Get collection instance.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + collectionName + String + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Retrieve a collection reference. Your collection tables are created on demand.

    +
    // Users collection
    +var users = client.collection('users');
    +
    +// Highscores
    +var highscores = client.collection('highscores');
    + +
    +
    + +
    + + +
    +

    delete

    + + +
    + (
      + +
    • + + segments + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Delete existing resource.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + segments + String + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    +

    get

    + + +
    + (
      + +
    • + + segments + +
    • + +
    • + + data + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Retrieve a resource

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + segments + String + + + + +
      + +
      + + +
    • + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    +

    getHeaders

    + + + () + + + + + Object + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Get XHR headers for app/auth context.

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Object: + + +
    +
    + + + +
    + + +
    +

    getPayload

    + + +
    + (
      + +
    • + + requestMethod + +
    • + +
    • + + data + +
    • + +
    ) +
    + + + + + String | FormData + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Get payload of given data

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + requestMethod + String + + + + +
      + +
      + + +
    • + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + String | FormData: + + +
    +
    + + + +
    + + +
    +

    post

    + + +
    + (
      + +
    • + + segments + +
    • + +
    • + + data + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Create resource

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + segments + String + + + + +
      + +
      + + +
    • + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    +

    put

    + + +
    + (
      + +
    • + + segments + +
    • + +
    • + + data + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Update existing resource

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + segments + String + + + + +
      + +
      + + +
    • + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    +

    request

    + + +
    + (
      + +
    • + + segments + +
    • + +
    • + + method + +
    • + +
    • + + data + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + segments + String + + + + +
      + +
      + + +
    • + +
    • + + method + String + + + + +
      + +
      + + +
    • + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    +

    url

    + + +
    + (
      + +
    • + + route + +
    • + +
    ) +
    + + + + + String + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Get remote URL string.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + route + String + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + String: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Downloading data from a hook route

    +
    location.href = client.url('download', { something: "hey" })
    +

    Using custom hook route for image catpcha

    +
    // Implementing custom route for captcha: https://github.com/doubleleft/hook/wiki/Composer-dependencies
    +var img = new Image();
    +img.src = client.url('captcha');
    + +
    +
    + +
    + + +
    + + + +
    +

    Properties

    + + +
    +

    auth

    + Hook.Auth + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    keys

    + Hook.KeyValues + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    system

    + Hook.System + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Collection.html b/classes/Hook.Collection.html new file mode 100644 index 0000000..4784461 --- /dev/null +++ b/classes/Hook.Collection.html @@ -0,0 +1,3884 @@ + + + + + Hook.Collection - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Collection Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    avg

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Aggregate field with 'avg' values

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Get the average value from highscore collection

    +
    client.collection('highscore').avg('score', function(data) {
    +  console.log("avg: ", data);
    +});
    + +
    +
    + +
    + + +
    +

    channel

    + + +
    + (
      + +
    • + + options + +
    • + +
    ) +
    + + + + + Hook.Channel + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Get channel for this collection.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + options + Object + + + + +
      +

      (optional)

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Channel: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Streaming collection data

    +
    client.collection('messages').where('type', 'new-game').channel().subscribe(function(event, data) {
    +  console.log("Received new-game message: ", data);
    +});
    +
    +client.collection('messages').create({type: 'sad', text: "i'm sad because streaming won't catch me"});
    +client.collection('messages').create({type: 'new-game', text: "yey, streaming will catch me!"});
    + +
    +
    + +
    + + +
    +

    clone

    + + + () + + + + + Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Return a new copy of the collection.

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Collection: + + +
    +
    + + + +
    + + +
    +

    count

    + + +
    + (
      + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Count the number of items on this collection

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + callback + Function + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Count the elements of the current query

    +
    client.collection('posts').where('author','Vicente').count(function(total) {
    +  console.log("Total:", total);
    +});
    + +
    +
    + +
    + + +
    +

    create

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Create a new resource

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Creating an entry

    +
    client.collection('posts').create({
    +  title: "Post name",
    +  summary: "My awesome new post",
    +  stars: 5
    +});
    +

    Listening to complete event

    +
    // Verbose way
    +var c = client.collection('posts');
    +var promise = c.create({ title: "Post name", summary: "Something", stars: 5 });
    +promise.then(function(data) {
    +    console.log(data);
    +});
    +
    +// Short way
    +client.collection('posts').create({ title: "Post name", summary: "Something", stars: 5 }).then(function(data) {
    +    console.log(data);
    +});
    + +
    +
    + +
    + + +
    +

    debug

    + + + () + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Alias for then & console.log.bind(console)

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    decrement

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + value + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Decrement a value from 'field' from all rows matching current filter.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + value + Number + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Decrement user score

    +
    client.collection('users').where('_id', user_id).decrement('score', 10).then(function(numRows) {
    +  console.log(numRows, " users has been updated");
    +});
    + +
    +
    + +
    + + +
    +

    distinct

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + ... + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    The 'distinct' can be used to return only distinct (different) values.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + ... + String + + + + +
      +

      more fields

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    find

    + + +
    + (
      + +
    • + + _id + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Find first item by _id

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + _id + Number + + + + +
      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Finding first item by _id, with 'success' callback as param.

    +
    client.collection('posts').find(50, function(data) {
    +  console.log("Row:", data);
    +});
    +

    Catching 'not found' error.

    +
    client.collection('posts').find(128371923).then(function(data) {
    +  console.log("Row:", data); // will never execute this
    +}).otherwise(function(e) {
    +  console.log("Not found.");
    +});
    + +
    +
    + +
    + + +
    +

    first

    + + +
    + (
      + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Query only the first result

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + callback + Function + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Return just the first element for current query

    +
    client.collection('users').sort('created_at', -1).first(function(data) {
    +  console.log("Last created user:", data);
    +});
    + +
    +
    + +
    + + +
    +

    firstOrCreate

    + + +
    + (
      + +
    • + + data + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    First or create

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + +

    example Return the first match for 'data' param, or create it.

    +
    client.collection('uniques').firstOrCreate({type: "something"}).then(function(data) {
    +  console.log("Unique row: ", data);
    +});
    + + +
    +
    + + + +
    + + +
    +

    get

    + + + () + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Get collection data, based on where params.

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    group

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + ... + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Group results by field

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + ... + String + + + + +
      +

      more fields

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    increment

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + value + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Increment a value from 'field' from all rows matching current filter.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + value + Number + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Increment user score

    +
    client.collection('users').where('_id', user_id).increment('score', 10).then(function(numRows) {
    +  console.log(numRows, " users has been updated");
    +});
    + +
    +
    + +
    + + +
    +

    join

    + + +
    + (
      + +
    • + + ... + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Set the relationships that should be eager loaded.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + ... + String + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Simple relationship

    +
    client.collection('books').join('author').each(function(book) {
    +  console.log("Author: ", book.author.name);
    +});
    +

    Multiple relationships

    +
    client.collection('books').join('author', 'publisher').each(function(book) {
    +  console.log("Author: ", book.author.name);
    +  console.log("Publisher: ", book.publisher.name);
    +});
    +

    Nested relationships

    +
    client.collection('books').join('author.contacts').each(function(book) {
    +  console.log("Author: ", book.author.name);
    +  console.log("Contacts: ", book.author.contacts);
    +});
    + +
    +
    + +
    + + +
    +

    limit

    + + +
    + (
      + +
    • + + int + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + int + Number + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Limit the number of rows to retrieve

    +
    client.collection('posts').sort('updated_at', -1).limit(5).then(function(data) {
    +  console.log("Last 5 rows updated: ", data);
    +});
    +

    Limit and offset

    +
    client.collection('posts').sort('updated_at', -1).limit(5).offset(5).then(function(data) {
    +  console.log("last 5 rows updated, after 5 lastest: ", data);
    +});
    + +
    +
    + +
    + + +
    +

    max

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Aggregate field with 'max' values

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Get the max value from highscore collection

    +
    client.collection('highscore').max('score', function(data) {
    +  console.log("max: ", data);
    +});
    + +
    +
    + +
    + + +
    +

    min

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Aggregate field with 'min' values

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Get the min value from highscore collection

    +
    client.collection('highscore').min('score', function(data) {
    +  console.log("min: ", data);
    +});
    + +
    +
    + +
    + + +
    +

    offset

    + + +
    + (
      + +
    • + + int + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + int + Number + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    orWhere

    + + +
    + (
      + +
    • + + where + +
    • + +
    • + + operation + +
    • + +
    • + + value + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Add OR query param

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + where + Object | String + + + + +
      +

      params or field name

      + +
      + + +
    • + +
    • + + operation + String + + + + +
      +

      '<', '<=', '>', '>=', '!=', 'in', 'between', 'not_in', 'not_between', 'like', 'not_null'

      + +
      + + +
    • + +
    • + + value + String + + + + +
      +

      value

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    remember

    + + +
    + (
      + +
    • + + minutes + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Indicate that the query results should be cached.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + minutes + Number + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Caching a query

    +
    client.collection('posts').sort('updated_at', -1).limit(5).remember(10).then(function(data) {
    +  // ...
    +});
    + +
    +
    + +
    + + +
    +

    remove

    + + +
    + (
      + +
    • + + id + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Remove a single row by id

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + id + String + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Deleting a row by id

    +
    client.collection('posts').remove(1).then(function(data) {
    +  console.log("Success:", data.success);
    +});
    +

    Deleting multiple rows

    +
    client.collection('ranking').where('score', 0).remove().then(function(data) {
    +  console.log("Success:", data.success);
    +});
    + +
    +
    + +
    + + +
    +

    reset

    + + + () + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Clear collection filtering state

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    select

    + + + () + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Fields that should be retrieved from the database

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    + + +
    +

    sort

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + direction + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + direction + Number | String + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Return just the first element for current query

    +
    // Ommit the second argument for ascending order:
    +client.collection('users').sort('created_at').then(function(data){ });
    +
    +// Use 1 or 'asc' to specify ascending order:
    +client.collection('users').sort('created_at', 1).then(function(data){  });
    +client.collection('users').sort('created_at', 'asc').then(function(data){  });
    +
    +// Use -1 or 'desc' for descending order:
    +client.collection('users').sort('created_at', -1).then(function(data) {  });
    +client.collection('users').sort('created_at', 'desc').then(function(data) {  });
    + +
    +
    + +
    + + +
    +

    sum

    + + +
    + (
      + +
    • + + field + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Aggregate field with 'sum' values

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + field + String + + + + +
      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      +

      [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Get the sum value from highscore collection

    +
    client.collection('highscore').sum('score', function(data) {
    +  console.log("sum: ", data);
    +});
    + +
    +
    + +
    + + +
    +

    then

    + + + () + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Alias for get & then

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    update

    + + +
    + (
      + +
    • + + _id + +
    • + +
    • + + data + +
    • + +
    ) +
    + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Update a single collection entry

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + _id + Number | String + + + + +
      + +
      + + +
    • + +
    • + + data + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    +

    Example:

    + +
    +

    Updating a single row

    +
    client.collection('posts').update(1, { title: "Changing post title" }).then(function(data) {
    +  console.log("Success:", data.success);
    +});
    + +
    +
    + +
    + + +
    +

    updateAll

    + + +
    + (
      + +
    • + + data + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Update all collection's data based on where params.

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + data + Object + + + + +
      +

      key-value data to update from matched rows [optional]

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Updating all rows of the collection

    +
    client.collection('users').updateAll({category: 'everybody'}).then(function(numRows) {
    +  console.log(numRows, " users has been updated");
    +});
    +

    Updating collection filters

    +
    client.collection('users').where('age','<',18).updateAll({category: 'baby'}).then(function(numRows) {
    +  console.log(numRows, " users has been updated");
    +});
    + +
    +
    + +
    + + +
    +

    where

    + + +
    + (
      + +
    • + + where + +
    • + +
    • + + operation + +
    • + +
    • + + value + +
    • + +
    ) +
    + + + + + Hook.Collection + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Add where param

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + where + Object | String + + + + +
      +

      params or field name

      + +
      + + +
    • + +
    • + + operation + String + + + + +
      +

      '<', '<=', '>', '>=', '!=', 'in', 'between', 'not_in', 'not_between', 'like', 'not_null'

      + +
      + + +
    • + +
    • + + value + String + + + + +
      +

      value

      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Hook.Collection: + +

    this

    + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Multiple 'where' calls

    +
    var c = client.collection('posts');
    +c.where('author','Vicente'); // equal operator may be omitted
    +c.where('stars','>',10);     // support '<' and '>' operators
    +c.then(function(result) {
    +  console.log(result);
    +});
    +

    One 'where' call

    +
    client.collection('posts').where({
    +  author: 'Vicente',
    +  stars: ['>', 10]
    +}).then(function(result) {
    +  console.log(result);
    +})
    +

    Filtering 'in' value list.

    +
    client.collection('posts').where('author_id', 'in', [500, 501]).then(function(result) {
    +  console.log(result);
    +})
    +

    Partial String matching

    +
    client.collection('posts').where('author', 'like', '%Silva%').then(function(result) {
    +  console.log(result);
    +})
    + +
    +
    + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Events.html b/classes/Hook.Events.html new file mode 100644 index 0000000..043f9b5 --- /dev/null +++ b/classes/Hook.Events.html @@ -0,0 +1,194 @@ + + + + + Hook.Events - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Events Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + + + + + + + +
    + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Iterable.html b/classes/Hook.Iterable.html new file mode 100644 index 0000000..4d45cb4 --- /dev/null +++ b/classes/Hook.Iterable.html @@ -0,0 +1,1208 @@ + + + + + Hook.Iterable - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Iterable Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    +

    Iterable is for internal use only.

    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    _iterate

    + + +
    + (
      + +
    • + + method + +
    • + +
    • + + func + +
    • + +
    • + + argument + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Iterate using lodash function

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + method + String + + + + +
      + +
      + + +
    • + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    • + + argument + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    each

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    every

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    filter

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    find

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    groupBy

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    max

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    min

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    +

    reject

    + + +
    + (
      + +
    • + + func + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + func + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.KeyValues.html b/classes/Hook.KeyValues.html new file mode 100644 index 0000000..af1ce8a --- /dev/null +++ b/classes/Hook.KeyValues.html @@ -0,0 +1,488 @@ + + + + + Hook.KeyValues - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.KeyValues Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + +
      + +
    • + get + + + +
    • + +
    • + set + + + +
    • + +
    +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    get

    + + +
    + (
      + +
    • + + key + +
    • + +
    • + + callback + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + key + String + + + + +
      + +
      + + +
    • + +
    • + + callback + Function + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Get a key value

    +
    client.keys.get('my-custom-key', function(key) {
    +  console.log(key.value);
    +});
    + +
    +
    + +
    + + +
    +

    set

    + + +
    + (
      + +
    • + + key + +
    • + +
    • + + value + +
    • + +
    ) +
    + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + key + String + + + + +
      + +
      + + +
    • + +
    • + + value + String | Number + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Set a key value

    +
    client.keys.set('my-custom-key', 'custom value').then(function(key) {
    +  console.log(key);
    +});
    + +
    +
    + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Pagination.html b/classes/Hook.Pagination.html new file mode 100644 index 0000000..98595dd --- /dev/null +++ b/classes/Hook.Pagination.html @@ -0,0 +1,748 @@ + + + + + Hook.Pagination - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Pagination Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + +
    +

    Properties

    + + +
    + + + + + +
    + + +
    +

    Methods

    + + +
    +

    hasNext

    + + + () + + + + + Boolean + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + + + +
    +

    Returns:

    + +
    + + + Boolean: + + +
    +
    + + + +
    + + +
    +

    isFetching

    + + + () + + + + + Booelan + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    + +
    + + + + +
    +

    Returns:

    + +
    + + + Booelan: + + +
    +
    + + + +
    + + +
    + + + +
    +

    Properties

    + + +
    +

    collection

    + Hook.Collection + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    current_page

    + Number + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    from

    + Number + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    items

    + Object + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    last_page

    + Number + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    per_page

    + Number + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    to

    + Number + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    +

    total

    + Number + + + + + + + + + +
    + + + +

    + + + + +

    + + + + +
    + +
    + +
    + + + + + + +
    + + +
    + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.Plugin.Cordova.PushNotification.html b/classes/Hook.Plugin.Cordova.PushNotification.html new file mode 100644 index 0000000..c2bdec3 --- /dev/null +++ b/classes/Hook.Plugin.Cordova.PushNotification.html @@ -0,0 +1,366 @@ + + + + + Hook.Plugin.Cordova.PushNotification - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Plugin.Cordova.PushNotification Class

    +
    + + + +
    + Extends Hook.Events +
    + + + + + + + Module: Hook.Plugin + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + + +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    register

    + + + () + + + + + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Register device for Push Notifications

    + +
    + + + + +
    +

    Returns:

    + +
    + + +

    Hook.Plugin.Cordova.PushNotification

    + + +
    +
    + + + +
    +

    Example:

    + +
    +

    Registering for push notifications on Android

    +
    //
    +// Get a senderID on your app's Google Console
    +// - https://developers.google.com/console
    +//
    +dl.cordova.push.register({senderID: "xxxx"}).on('notification', function(e) {
    +  console.log("Notification: ", e);
    +});
    +

    Registering for push notifications on iOS

    +
    dl.cordova.push.register().on('notification', function(e) {
    +  console.log("Notification: ", e);
    +});
    + +
    +
    + +
    + + +
    +

    unregister

    + + + () + + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Unregister device for Push Notifications

    + +
    + + + + + + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.PluginManager.html b/classes/Hook.PluginManager.html new file mode 100644 index 0000000..5070872 --- /dev/null +++ b/classes/Hook.PluginManager.html @@ -0,0 +1,400 @@ + + + + + Hook.PluginManager - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.PluginManager Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + +
      + +
    • + register + + + static + + +
    • + +
    • + setup + + + static + + +
    • + +
    +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    register

    + + +
    + (
      + +
    • + + class + +
    • + +
    ) +
    + + + + + + + + + + + + static + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Register plugin to be instantiated on Hook.Client

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + class + Object + + + + +
      + +
      + + +
    • + +
    +
    + + + + + +
    + + +
    +

    setup

    + + +
    + (
      + +
    • + + client + +
    • + +
    ) +
    + + + + + + + + + + + + static + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Register all plugins on target Hook.Client

    + +
    + + +
    +

    Parameters:

    + + +
    + + + + + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/Hook.System.html b/classes/Hook.System.html new file mode 100644 index 0000000..c815f08 --- /dev/null +++ b/classes/Hook.System.html @@ -0,0 +1,284 @@ + + + + + Hook.System - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.System Class

    +
    + + + + + + + + + Module: Hook + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + +
    +

    Methods

    + +
      + +
    • + time + + + +
    • + +
    +
    + + + + + + + +
    + + +
    +

    Methods

    + + +
    +

    time

    + + + () + + + + + Promise + + + + + + + + + + + + + + + +
    + + + +

    + + + + +

    + + + + + +
    + +
    +

    Return server's system time.

    + +
    + + + + +
    +

    Returns:

    + +
    + + + Promise: + + +
    +
    + + + +
    + + +
    + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/classes/OAuth.html b/classes/OAuth.html new file mode 100644 index 0000000..f365e93 --- /dev/null +++ b/classes/OAuth.html @@ -0,0 +1,194 @@ + + + + + OAuth - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    OAuth Class

    +
    + + + + + + + + + Module: Hook.Plugin + + + + +
    + + + +
    + +
    + + + +
    + + +
    +
    +

    Item Index

    + + + + + + + + +
    + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/data.json b/data.json new file mode 100644 index 0000000..b651a41 --- /dev/null +++ b/data.json @@ -0,0 +1,2337 @@ +{ + "project": { + "name": "hook-javascript", + "description": "hook javascript client", + "version": "0.2.1", + "url": "https://github.com/doubleleft/hook-javascript", + "nocode": "true", + "themedir": "yuidoc-theme" + }, + "files": { + "src/channel/sse.js": { + "name": "src/channel/sse.js", + "modules": {}, + "classes": { + "Hook.Channel.SSE": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/channel/websockets.js": { + "name": "src/channel/websockets.js", + "modules": {}, + "classes": { + "Hook.Channel.WEBSOCKETS": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/core/api.js": { + "name": "src/core/api.js", + "modules": {}, + "classes": {}, + "fors": {}, + "namespaces": {} + }, + "src/core/client.js": { + "name": "src/core/client.js", + "modules": {}, + "classes": { + "Hook.Client": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/core/events.js": { + "name": "src/core/events.js", + "modules": {}, + "classes": { + "Hook.Events": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/core/iterable.js": { + "name": "src/core/iterable.js", + "modules": {}, + "classes": { + "Hook.Iterable": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/core/plugin_manager.js": { + "name": "src/core/plugin_manager.js", + "modules": {}, + "classes": { + "Hook.PluginManager": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/plugins/cordova/cordova.js": { + "name": "src/plugins/cordova/cordova.js", + "modules": {}, + "classes": { + "Cordova": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/plugins/cordova/push_notification.js": { + "name": "src/plugins/cordova/push_notification.js", + "modules": {}, + "classes": { + "Hook.Plugin.Cordova.PushNotification": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/plugins/backbone.js": { + "name": "src/plugins/backbone.js", + "modules": { + "Backbone": 1 + }, + "classes": { + "Backbone.HookModel": 1, + "Backbone.HookCollection": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/plugins/oauth.js": { + "name": "src/plugins/oauth.js", + "modules": { + "Hook.Plugin": 1 + }, + "classes": { + "OAuth": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/auth.js": { + "name": "src/auth.js", + "modules": { + "Hook": 1 + }, + "classes": { + "Hook.Auth": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/channel.js": { + "name": "src/channel.js", + "modules": {}, + "classes": {}, + "fors": {}, + "namespaces": {} + }, + "src/collection.js": { + "name": "src/collection.js", + "modules": {}, + "classes": { + "Hook.Collection": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/collection_item.js": { + "name": "src/collection_item.js", + "modules": {}, + "classes": {}, + "fors": {}, + "namespaces": {} + }, + "src/key_values.js": { + "name": "src/key_values.js", + "modules": {}, + "classes": { + "Hook.KeyValues": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/pagination.js": { + "name": "src/pagination.js", + "modules": {}, + "classes": { + "Hook.Pagination": 1 + }, + "fors": {}, + "namespaces": {} + }, + "src/system.js": { + "name": "src/system.js", + "modules": {}, + "classes": { + "Hook.System": 1 + }, + "fors": {}, + "namespaces": {} + } + }, + "modules": { + "Hook": { + "name": "Hook", + "submodules": {}, + "classes": { + "Hook.Channel.SSE": 1, + "Hook.Channel.WEBSOCKETS": 1, + "Hook.Client": 1, + "Hook.Events": 1, + "Hook.Iterable": 1, + "Hook.PluginManager": 1, + "Hook.Auth": 1, + "Hook.Collection": 1, + "Hook.KeyValues": 1, + "Hook.Pagination": 1, + "Hook.System": 1 + }, + "fors": {}, + "namespaces": {}, + "tag": "module", + "file": "src/system.js", + "line": 1, + "description": "Deals with user registration/authentication", + "params": [ + { + "name": "client", + "description": "", + "type": "Client" + }, + { + "name": "namespace", + "description": "", + "type": "String" + }, + { + "name": "options", + "description": "optional", + "type": "Object" + } + ], + "is_constructor": 1, + "example": [ + " Connecting through websockets.\n\n var channel = client.channel('messages', { transport: \"websockets\" });", + " Force socket server endpoint.\n\n var channel = client.channel('messages', {\n transport: \"websockets\",\n url: \"ws://localhost:8080\"\n });" + ], + "static": 1, + "extends": "Hook.Events" + }, + "Hook.Plugin": { + "name": "Hook.Plugin", + "submodules": {}, + "classes": { + "Cordova": 1, + "Hook.Plugin.Cordova.PushNotification": 1, + "OAuth": 1 + }, + "fors": {}, + "namespaces": {}, + "tag": "module", + "file": "src/plugins/oauth.js", + "line": 1, + "requires": [ + "winchan ~ac4b142c" + ] + }, + "Backbone": { + "name": "Backbone", + "submodules": {}, + "classes": { + "Backbone.HookModel": 1, + "Backbone.HookCollection": 1 + }, + "fors": {}, + "namespaces": {}, + "tag": "module", + "file": "src/plugins/backbone.js", + "line": 47, + "requires": [ + "backbone.js ~1.1.2" + ] + } + }, + "classes": { + "Hook.Channel.SSE": { + "name": "Hook.Channel.SSE", + "shortname": "Hook.Channel.SSE", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/channel/sse.js", + "line": 1 + }, + "Hook.Channel.WEBSOCKETS": { + "name": "Hook.Channel.WEBSOCKETS", + "shortname": "Hook.Channel.WEBSOCKETS", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/channel/websockets.js", + "line": 1 + }, + "Hook.Client": { + "name": "Hook.Client", + "shortname": "Hook.Client", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/core/client.js", + "line": 1, + "description": "Hook.Client is the entry-point for using hook.\n\nYou should instantiate a global javascript client for consuming hook.\n\n```javascript\nvar client = new Hook.Client({\n url: \"http://local-or-remote-hook-address.com/public/index.php/\",\n app_id: 1, // your app's id\n key: 'test' // your app's public key\n});\n```" + }, + "Hook.Events": { + "name": "Hook.Events", + "shortname": "Hook.Events", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/core/events.js", + "line": 1 + }, + "Hook.Iterable": { + "name": "Hook.Iterable", + "shortname": "Hook.Iterable", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/core/iterable.js", + "line": 1, + "description": "Iterable is for internal use only." + }, + "Hook.PluginManager": { + "name": "Hook.PluginManager", + "shortname": "Hook.PluginManager", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/core/plugin_manager.js", + "line": 1 + }, + "Cordova": { + "name": "Cordova", + "shortname": "Cordova", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook.Plugin", + "namespace": "", + "file": "src/plugins/cordova/cordova.js", + "line": 1 + }, + "Hook.Plugin.Cordova.PushNotification": { + "name": "Hook.Plugin.Cordova.PushNotification", + "shortname": "Hook.Plugin.Cordova.PushNotification", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook.Plugin", + "namespace": "", + "file": "src/plugins/cordova/push_notification.js", + "line": 10, + "extends": "Hook.Events" + }, + "Backbone.HookModel": { + "name": "Backbone.HookModel", + "shortname": "Backbone.HookModel", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Backbone", + "namespace": "", + "file": "src/plugins/backbone.js", + "line": 8 + }, + "Backbone.HookCollection": { + "name": "Backbone.HookCollection", + "shortname": "Backbone.HookCollection", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Backbone", + "namespace": "", + "file": "src/plugins/backbone.js", + "line": 47 + }, + "OAuth": { + "name": "OAuth", + "shortname": "OAuth", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook.Plugin", + "namespace": "", + "file": "src/plugins/oauth.js", + "line": 1 + }, + "Hook.Auth": { + "name": "Hook.Auth", + "shortname": "Hook.Auth", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/auth.js", + "line": 1, + "description": "Deals with user registration/authentication" + }, + "Hook.Collection": { + "name": "Hook.Collection", + "shortname": "Hook.Collection", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/collection.js", + "line": 1 + }, + "Hook.KeyValues": { + "name": "Hook.KeyValues", + "shortname": "Hook.KeyValues", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/key_values.js", + "line": 1 + }, + "Hook.Pagination": { + "name": "Hook.Pagination", + "shortname": "Hook.Pagination", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/pagination.js", + "line": 1 + }, + "Hook.System": { + "name": "Hook.System", + "shortname": "Hook.System", + "classitems": [], + "plugins": [], + "extensions": [], + "plugin_for": [], + "extension_for": [], + "module": "Hook", + "namespace": "", + "file": "src/system.js", + "line": 1 + } + }, + "classitems": [ + { + "file": "src/channel/sse.js", + "line": 19, + "description": "Subscribe to channel. Publishes a 'connected' message on the first time.", + "itemtype": "method", + "name": "subscribe", + "params": [ + { + "name": "event", + "description": "(optional)", + "type": "String" + }, + { + "name": "callback", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Registering for all messages\n\n channel.subscribe(function(event, data) {\n console.log(\"Message: \", event, data);\n })", + " Registering for a single custom event\n\n channel.subscribe('some-event', function(data) {\n console.log(\"Custom event triggered: \", data);\n })", + " Registering for client connected/disconnected events\n\n channel.subscribe('connected', function(data) {\n console.log(\"New client connected: \", data.client_id);\n });\n channel.subscribe('disconnected', function(data) {\n console.log(\"Client disconnected: \", data.client_id);\n });", + " Registering error event\n\n channel.subscribe('state:open', function(e) {\n console.log(\"Error: \", e);\n });\n channel.subscribe('state:error', function(e) {\n console.log(\"Error: \", e);\n });\n\n" + ], + "class": "Hook.Channel.SSE", + "module": "Hook" + }, + { + "file": "src/channel/sse.js", + "line": 91, + "class": "Hook.Channel.SSE", + "module": "Hook" + }, + { + "file": "src/channel/sse.js", + "line": 105, + "description": "Is EventSource listenning to messages?", + "itemtype": "method", + "name": "isConnected", + "return": { + "description": "", + "type": "Boolean" + }, + "class": "Hook.Channel.SSE", + "module": "Hook" + }, + { + "file": "src/channel/sse.js", + "line": 114, + "description": "Unsubscribe to a event listener", + "itemtype": "method", + "name": "unsubscribe", + "params": [ + { + "name": "event", + "description": "", + "type": "String" + } + ], + "class": "Hook.Channel.SSE", + "module": "Hook" + }, + { + "file": "src/channel/sse.js", + "line": 125, + "description": "Publish event message", + "itemtype": "method", + "name": "publish", + "params": [ + { + "name": "event", + "description": "", + "type": "String" + }, + { + "name": "message", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Channel.SSE", + "module": "Hook" + }, + { + "file": "src/channel/sse.js", + "line": 187, + "description": "Disconnect from channel, publishing a 'disconnected' message.", + "itemtype": "method", + "name": "disconnect", + "params": [ + { + "name": "synchronous", + "description": "default = false", + "type": "Boolean" + } + ], + "return": { + "description": "this", + "type": "Hook.Channel" + }, + "class": "Hook.Channel.SSE", + "module": "Hook" + }, + { + "file": "src/channel/sse.js", + "line": 203, + "description": "Close event source connection.", + "itemtype": "method", + "name": "close", + "return": { + "description": "this", + "type": "Channel" + }, + "class": "Hook.Channel.SSE", + "module": "Hook" + }, + { + "file": "src/channel/websockets.js", + "line": 78, + "description": "Subscribe to channel. Publishes a 'connected' message on the first time.", + "itemtype": "method", + "name": "subscribe", + "params": [ + { + "name": "event", + "description": "(optional)", + "type": "String" + }, + { + "name": "callback", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Hook.Channel" + }, + "example": [ + " Registering for a single custom event\n\n channel.subscribe('some-event', function(data) {\n console.log(\"Custom event triggered: \", data);\n })", + " Registering for client connected/disconnected events\n\n channel.subscribe('connected', function(data) {\n console.log(\"New client connected: \", data.client_id);\n });\n channel.subscribe('disconnected', function(data) {\n console.log(\"Client disconnected: \", data.client_id);\n });\n" + ], + "class": "Hook.Channel.WEBSOCKETS", + "module": "Hook" + }, + { + "file": "src/channel/websockets.js", + "line": 114, + "description": "Is EventSource listenning to messages?", + "itemtype": "method", + "name": "isConnected", + "return": { + "description": "", + "type": "Boolean" + }, + "class": "Hook.Channel.WEBSOCKETS", + "module": "Hook" + }, + { + "file": "src/channel/websockets.js", + "line": 123, + "description": "Unsubscribe to a event listener", + "itemtype": "method", + "name": "unsubscribe", + "params": [ + { + "name": "event", + "description": "", + "type": "String" + } + ], + "return": { + "description": "", + "type": "Hook.Channel" + }, + "class": "Hook.Channel.WEBSOCKETS", + "module": "Hook" + }, + { + "file": "src/channel/websockets.js", + "line": 136, + "description": "Publish event message", + "itemtype": "method", + "name": "publish", + "params": [ + { + "name": "event", + "description": "", + "type": "String" + }, + { + "name": "message", + "description": "", + "type": "Object" + }, + { + "name": "options", + "description": "'exclude' and 'elegible' are optional options.", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Hook.Channel" + }, + "class": "Hook.Channel.WEBSOCKETS", + "module": "Hook" + }, + { + "file": "src/channel/websockets.js", + "line": 163, + "description": "Disconnect from channel, publishing a 'disconnected' message.", + "itemtype": "method", + "name": "disconnect", + "return": { + "description": "this", + "type": "Hook.Channel" + }, + "class": "Hook.Channel.WEBSOCKETS", + "module": "Hook" + }, + { + "file": "src/channel/websockets.js", + "line": 173, + "itemtype": "method", + "name": "call", + "params": [ + { + "name": "procedure", + "description": "", + "type": "String" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Channel.WEBSOCKETS", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 38, + "itemtype": "property", + "name": "keys", + "type": "Hook.KeyValues", + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 43, + "itemtype": "property", + "name": "auth", + "type": "Hook.Auth", + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 48, + "itemtype": "property", + "name": "system", + "type": "Hook.System", + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 57, + "description": "Get collection instance.", + "itemtype": "method", + "name": "collection", + "params": [ + { + "name": "collectionName", + "description": "", + "type": "String" + } + ], + "return": { + "description": "", + "type": "Hook.Collection" + }, + "example": [ + " Retrieve a collection reference. Your collection tables are created on demand.\n\n // Users collection\n var users = client.collection('users');\n\n // Highscores\n var highscores = client.collection('highscores');\n" + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 76, + "description": "Get channel instance.", + "itemtype": "method", + "name": "channel", + "params": [ + { + "name": "name", + "description": "", + "type": "String" + }, + { + "name": "options", + "description": "(optional)", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Hook.Channel" + }, + "example": [ + " Create a channel using Servet-Sent Events transport.\n\n var channel = client.channel('messages');", + " Create a channel using WebSockets transport.\n\n var channel = client.channel('messages', { transport: \"websockets\" });\n" + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 105, + "description": "Get remote URL string.", + "itemtype": "method", + "name": "url", + "params": [ + { + "name": "route", + "description": "", + "type": "String" + } + ], + "return": { + "description": "", + "type": "String" + }, + "example": [ + " Downloading data from a hook route\n\n location.href = client.url('download', { something: \"hey\" })", + " Using custom hook route for image catpcha\n\n // Implementing custom route for captcha: https://github.com/doubleleft/hook/wiki/Composer-dependencies\n var img = new Image();\n img.src = client.url('captcha');\n" + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 128, + "description": "Create resource", + "itemtype": "method", + "name": "post", + "params": [ + { + "name": "segments", + "description": "", + "type": "String" + }, + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 141, + "description": "Retrieve a resource", + "itemtype": "method", + "name": "get", + "params": [ + { + "name": "segments", + "description": "", + "type": "String" + }, + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 151, + "description": "Update existing resource", + "itemtype": "method", + "name": "put", + "params": [ + { + "name": "segments", + "description": "", + "type": "String" + }, + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 161, + "description": "Delete existing resource.", + "itemtype": "method", + "name": "delete", + "params": [ + { + "name": "segments", + "description": "", + "type": "String" + } + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 170, + "itemtype": "method", + "name": "request", + "params": [ + { + "name": "segments", + "description": "", + "type": "String" + }, + { + "name": "method", + "description": "", + "type": "String" + }, + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 246, + "description": "Get XHR headers for app/auth context.", + "itemtype": "method", + "name": "getHeaders", + "return": { + "description": "", + "type": "Object" + }, + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/client.js", + "line": 266, + "description": "Get payload of given data", + "itemtype": "method", + "name": "getPayload", + "params": [ + { + "name": "requestMethod", + "description": "", + "type": "String" + }, + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "String|FormData" + }, + "class": "Hook.Client", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 8, + "itemtype": "method", + "name": "each", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 15, + "itemtype": "method", + "name": "find", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 22, + "itemtype": "method", + "name": "filter", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 29, + "itemtype": "method", + "name": "max", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 36, + "itemtype": "method", + "name": "min", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 43, + "itemtype": "method", + "name": "every", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 50, + "itemtype": "method", + "name": "reject", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 57, + "itemtype": "method", + "name": "groupBy", + "params": [ + { + "name": "func", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/iterable.js", + "line": 64, + "description": "Iterate using lodash function", + "itemtype": "method", + "name": "_iterate", + "params": [ + { + "name": "method", + "description": "", + "type": "String" + }, + { + "name": "func", + "description": "", + "type": "Function" + }, + { + "name": "argument", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Iterable", + "module": "Hook" + }, + { + "file": "src/core/plugin_manager.js", + "line": 10, + "description": "Register plugin to be instantiated on Hook.Client", + "itemtype": "method", + "name": "register", + "params": [ + { + "name": "class", + "description": "", + "type": "Object" + } + ], + "static": 1, + "class": "Hook.PluginManager", + "module": "Hook" + }, + { + "file": "src/core/plugin_manager.js", + "line": 20, + "description": "Register all plugins on target Hook.Client", + "itemtype": "method", + "name": "setup", + "params": [ + { + "name": "client", + "description": "", + "type": "Hook.Client" + } + ], + "static": 1, + "class": "Hook.PluginManager", + "module": "Hook" + }, + { + "file": "src/plugins/cordova/cordova.js", + "line": 8, + "itemtype": "property", + "name": "push", + "type": "Hook.Plugin.Cordova.PushNotification", + "class": "Cordova", + "module": "Hook.Plugin" + }, + { + "file": "src/plugins/cordova/push_notification.js", + "line": 1, + "description": "-------------\nDependency plugins:\n-------------\n- https://github.com/phonegap-build/PushPlugin\n- https://github.com/apache/cordova-plugin-device\n- https://github.com/danmichaelo/cordova-plugin-appinfo", + "class": "Hook.Plugin.Cordova.PushNotification", + "module": "Hook.Plugin" + }, + { + "file": "src/plugins/cordova/push_notification.js", + "line": 41, + "description": "Register device for Push Notifications", + "itemtype": "method", + "name": "register", + "return": { + "description": "Hook.Plugin.Cordova.PushNotification" + }, + "example": [ + " Registering for push notifications on Android\n\n //\n // Get a senderID on your app's Google Console\n // - https://developers.google.com/console\n //\n dl.cordova.push.register({senderID: \"xxxx\"}).on('notification', function(e) {\n console.log(\"Notification: \", e);\n });", + " Registering for push notifications on iOS\n\n dl.cordova.push.register().on('notification', function(e) {\n console.log(\"Notification: \", e);\n });" + ], + "class": "Hook.Plugin.Cordova.PushNotification", + "module": "Hook.Plugin" + }, + { + "file": "src/plugins/cordova/push_notification.js", + "line": 205, + "description": "Unregister device for Push Notifications", + "itemtype": "method", + "name": "unregister", + "class": "Hook.Plugin.Cordova.PushNotification", + "module": "Hook.Plugin" + }, + { + "file": "src/plugins/cordova/push_notification.js", + "line": 212, + "description": "method _registerDevice", + "class": "Hook.Plugin.Cordova.PushNotification", + "module": "Hook.Plugin" + }, + { + "file": "src/plugins/backbone.js", + "line": 60, + "description": "Reset collection data and triggers 'fetch' event.", + "itemtype": "method", + "name": "fetchRemote", + "params": [ + { + "name": "models", + "description": "", + "type": "Array" + } + ], + "class": "Backbone.HookCollection", + "module": "Backbone" + }, + { + "file": "src/auth.js", + "line": 12, + "itemtype": "property", + "name": "currentUser", + "type": "{Object}", + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 37, + "itemtype": "method", + "name": "setUserData", + "params": [ + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "this", + "type": "Hook.Auth" + }, + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 61, + "description": "Register a user.", + "params": [ + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "itemtype": "method", + "name": "register", + "example": [ + " Register with email address\n\n client.auth.register({\n email: \"endel@doubleleft.com\",\n password: \"12345\",\n name: \"Endel Dreyer\"\n }).then(function(user) {\n console.log(\"Registered user: \", user);\n });\n" + ], + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 87, + "description": "Verify if user is already registered, and log-in if succeed.", + "itemtype": "method", + "name": "login", + "params": [ + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + "\n\n client.auth.login({email: \"edreyer@doubleleft.com\", password: \"123\"}).then(function(data){\n console.log(\"User found: \", data);\n }, function(data){\n console.log(\"User not found or password invalid.\", data);\n });" + ], + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 111, + "description": "Update current user info.", + "itemtype": "method", + "name": "update", + "params": [ + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + "\n\n client.auth.update({ score: 100 }).then(function(data){\n console.log(\"updated successfully: \", data);\n }).otherwise(function(data){\n console.log(\"error: \", data);\n });" + ], + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 140, + "description": "Send a 'forgot password' confirmation email to target user email address.", + "itemtype": "method", + "name": "forgotPassword", + "params": [ + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + "\n\n client.auth.forgotPassword({\n email: \"edreyer@doubleleft.com\",\n subject: \"Project name: Forgot your password?\",\n template: \"Hi {{name}}, click here to reset your password http://custom-project.com/pass-recovery-path.html?token={{token}}\"\n }).then(function(data){\n console.log(\"Email enviado!\", data);\n }, function(data){\n console.log(\"User not found: \", data);\n });" + ], + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 163, + "description": "Reset user password", + "itemtype": "method", + "name": "resetPassword", + "params": [ + { + "name": "data", + "description": "", + "type": "Object", + "props": [ + { + "name": "password", + "description": "", + "type": "Object" + }, + { + "name": "token", + "description": "[optional]", + "type": "Object" + } + ] + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Getting token automatically from query string\n\n client.auth.resetPassword(\"my-new-password-123\").then(function(data){\n console.log(\"Password reseted! \", data);\n }, function(data){\n console.log(\"Error\", data.error);\n });", + " Providing a token manually\n\n client.auth.resetPassword({token: \"xxx\", password: \"my-new-password-123\"}).then(function(data){\n console.log(\"Password reseted! \", data);\n }, function(data){\n console.log(\"Error\", data.error);\n });\n" + ], + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 199, + "itemtype": "method", + "name": "logout", + "return": { + "description": "this", + "type": "Hook.Auth" + }, + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/auth.js", + "line": 207, + "itemtype": "method", + "name": "getToken", + "return": { + "description": "", + "type": "String|null" + }, + "class": "Hook.Auth", + "module": "Hook" + }, + { + "file": "src/channel.js", + "line": 1, + "description": "Channel implementations", + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 22, + "description": "Create a new resource", + "itemtype": "method", + "name": "create", + "params": [ + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "example": [ + " Creating an entry\n\n client.collection('posts').create({\n title: \"Post name\",\n summary: \"My awesome new post\",\n stars: 5\n });", + " Listening to complete event\n\n // Verbose way\n var c = client.collection('posts');\n var promise = c.create({ title: \"Post name\", summary: \"Something\", stars: 5 });\n promise.then(function(data) {\n console.log(data);\n });\n\n // Short way\n client.collection('posts').create({ title: \"Post name\", summary: \"Something\", stars: 5 }).then(function(data) {\n console.log(data);\n });\n" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 56, + "description": "Fields that should be retrieved from the database", + "itemtype": "method", + "name": "select", + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 66, + "description": "Get collection data, based on `where` params.", + "itemtype": "method", + "name": "get", + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 75, + "description": "Add `where` param", + "itemtype": "method", + "name": "where", + "params": [ + { + "name": "where", + "description": "params or field name", + "type": "Object | String" + }, + { + "name": "operation", + "description": "'<', '<=', '>', '>=', '!=', 'in', 'between', 'not_in', 'not_between', 'like', 'not_null'", + "type": "String" + }, + { + "name": "value", + "description": "value", + "type": "String" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "example": [ + " Multiple 'where' calls\n\n var c = client.collection('posts');\n c.where('author','Vicente'); // equal operator may be omitted\n c.where('stars','>',10); // support '<' and '>' operators\n c.then(function(result) {\n console.log(result);\n });", + " One 'where' call\n\n client.collection('posts').where({\n author: 'Vicente',\n stars: ['>', 10]\n }).then(function(result) {\n console.log(result);\n })", + " Filtering 'in' value list.\n\n client.collection('posts').where('author_id', 'in', [500, 501]).then(function(result) {\n console.log(result);\n })", + " Partial String matching\n\n client.collection('posts').where('author', 'like', '%Silva%').then(function(result) {\n console.log(result);\n })\n" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 140, + "description": "Add OR query param", + "itemtype": "method", + "name": "orWhere", + "params": [ + { + "name": "where", + "description": "params or field name", + "type": "Object | String" + }, + { + "name": "operation", + "description": "'<', '<=', '>', '>=', '!=', 'in', 'between', 'not_in', 'not_between', 'like', 'not_null'", + "type": "String" + }, + { + "name": "value", + "description": "value", + "type": "String" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 152, + "description": "Find first item by _id", + "itemtype": "method", + "name": "find", + "params": [ + { + "name": "_id", + "description": "", + "type": "Number" + }, + { + "name": "callback", + "description": "[optional]", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Finding first item by _id, with 'success' callback as param.\n\n client.collection('posts').find(50, function(data) {\n console.log(\"Row:\", data);\n });", + " Catching 'not found' error.\n\n client.collection('posts').find(128371923).then(function(data) {\n console.log(\"Row:\", data); // will never execute this\n }).otherwise(function(e) {\n console.log(\"Not found.\");\n });\n" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 182, + "description": "Set the relationships that should be eager loaded.", + "itemtype": "method", + "name": "join", + "params": [ + { + "name": "...", + "description": "", + "type": "String" + } + ], + "return": { + "description": "", + "type": "Hook.Collection" + }, + "example": [ + " Simple relationship\n\n client.collection('books').join('author').each(function(book) {\n console.log(\"Author: \", book.author.name);\n });", + " Multiple relationships\n\n client.collection('books').join('author', 'publisher').each(function(book) {\n console.log(\"Author: \", book.author.name);\n console.log(\"Publisher: \", book.publisher.name);\n });", + " Nested relationships\n\n client.collection('books').join('author.contacts').each(function(book) {\n console.log(\"Author: \", book.author.name);\n console.log(\"Contacts: \", book.author.contacts);\n });\n" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 215, + "description": "The 'distinct' can be used to return only distinct (different) values.", + "itemtype": "method", + "name": "distinct", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "...", + "description": "more fields", + "type": "String" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 227, + "description": "Group results by field", + "itemtype": "method", + "name": "group", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "...", + "description": "more fields", + "type": "String" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 239, + "description": "Count the number of items on this collection", + "itemtype": "method", + "name": "count", + "params": [ + { + "name": "callback", + "description": "[optional]", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Count the elements of the current query\n\n client.collection('posts').where('author','Vicente').count(function(total) {\n console.log(\"Total:\", total);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 261, + "description": "Aggregate field with 'max' values", + "itemtype": "method", + "name": "max", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "callback", + "description": "[optional]", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Get the max value from highscore collection\n\n client.collection('highscore').max('score', function(data) {\n console.log(\"max: \", data);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 283, + "description": "Aggregate field with 'min' values", + "itemtype": "method", + "name": "min", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "callback", + "description": "[optional]", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Get the min value from highscore collection\n\n client.collection('highscore').min('score', function(data) {\n console.log(\"min: \", data);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 305, + "description": "Aggregate field with 'avg' values", + "itemtype": "method", + "name": "avg", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "callback", + "description": "[optional]", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Get the average value from highscore collection\n\n client.collection('highscore').avg('score', function(data) {\n console.log(\"avg: \", data);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 327, + "description": "Aggregate field with 'sum' values", + "itemtype": "method", + "name": "sum", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "callback", + "description": "[optional]", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Get the sum value from highscore collection\n\n client.collection('highscore').sum('score', function(data) {\n console.log(\"sum: \", data);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 349, + "description": "Query only the first result", + "itemtype": "method", + "name": "first", + "params": [ + { + "name": "callback", + "description": "[optional]", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Return just the first element for current query\n\n client.collection('users').sort('created_at', -1).first(function(data) {\n console.log(\"Last created user:\", data);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 368, + "description": "First or create", + "itemtype": "method", + "name": "firstOrCreate", + "params": [ + { + "name": "data", + "description": "", + "type": "Object" + }, + { + "name": "callback", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "example Return the first match for 'data' param, or create it.\n\n client.collection('uniques').firstOrCreate({type: \"something\"}).then(function(data) {\n console.log(\"Unique row: \", data);\n });", + "type": "Promise" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 388, + "description": "Alias for get & then", + "itemtype": "method", + "name": "then", + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 399, + "description": "Alias for then & console.log.bind(console)", + "itemtype": "method", + "name": "debug", + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 409, + "description": "Clear collection filtering state", + "itemtype": "method", + "name": "reset", + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 425, + "itemtype": "method", + "name": "sort", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "direction", + "description": "", + "type": "Number|String" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "example": [ + " Return just the first element for current query\n\n // Ommit the second argument for ascending order:\n client.collection('users').sort('created_at').then(function(data){ });\n\n // Use 1 or 'asc' to specify ascending order:\n client.collection('users').sort('created_at', 1).then(function(data){ });\n client.collection('users').sort('created_at', 'asc').then(function(data){ });\n\n // Use -1 or 'desc' for descending order:\n client.collection('users').sort('created_at', -1).then(function(data) { });\n client.collection('users').sort('created_at', 'desc').then(function(data) { });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 454, + "itemtype": "method", + "name": "limit", + "params": [ + { + "name": "int", + "description": "", + "type": "Number" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "example": [ + " Limit the number of rows to retrieve\n\n client.collection('posts').sort('updated_at', -1).limit(5).then(function(data) {\n console.log(\"Last 5 rows updated: \", data);\n });", + " Limit and offset\n\n client.collection('posts').sort('updated_at', -1).limit(5).offset(5).then(function(data) {\n console.log(\"last 5 rows updated, after 5 lastest: \", data);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 476, + "itemtype": "method", + "name": "offset", + "see": [ + "limit" + ], + "params": [ + { + "name": "int", + "description": "", + "type": "Number" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 488, + "description": "Indicate that the query results should be cached.", + "itemtype": "method", + "name": "remember", + "params": [ + { + "name": "minutes", + "description": "", + "type": "Number" + } + ], + "return": { + "description": "this", + "type": "Hook.Collection" + }, + "example": [ + " Caching a query\n\n client.collection('posts').sort('updated_at', -1).limit(5).remember(10).then(function(data) {\n // ...\n });\n" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 507, + "description": "Get channel for this collection.", + "itemtype": "method", + "name": "channel", + "params": [ + { + "name": "options", + "description": "(optional)", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Hook.Channel" + }, + "example": [ + " Streaming collection data\n\n client.collection('messages').where('type', 'new-game').channel().subscribe(function(event, data) {\n console.log(\"Received new-game message: \", data);\n });\n\n client.collection('messages').create({type: 'sad', text: \"i'm sad because streaming won't catch me\"});\n client.collection('messages').create({type: 'new-game', text: \"yey, streaming will catch me!\"});\n" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 528, + "description": "Drop entire collection. This operation is irreversible.", + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 536, + "description": "Remove a single row by id", + "itemtype": "method", + "name": "remove", + "params": [ + { + "name": "id", + "description": "[optional]", + "type": "String" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Deleting a row by id\n\n client.collection('posts').remove(1).then(function(data) {\n console.log(\"Success:\", data.success);\n });", + " Deleting multiple rows\n\n client.collection('ranking').where('score', 0).remove().then(function(data) {\n console.log(\"Success:\", data.success);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 562, + "description": "Update a single collection entry", + "itemtype": "method", + "name": "update", + "params": [ + { + "name": "_id", + "description": "", + "type": "Number | String" + }, + { + "name": "data", + "description": "", + "type": "Object" + } + ], + "example": [ + " Updating a single row\n\n client.collection('posts').update(1, { title: \"Changing post title\" }).then(function(data) {\n console.log(\"Success:\", data.success);\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 578, + "description": "Increment a value from 'field' from all rows matching current filter.", + "itemtype": "method", + "name": "increment", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "value", + "description": "", + "type": "Number" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Increment user score\n\n client.collection('users').where('_id', user_id).increment('score', 10).then(function(numRows) {\n console.log(numRows, \" users has been updated\");\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 600, + "description": "Decrement a value from 'field' from all rows matching current filter.", + "itemtype": "method", + "name": "decrement", + "params": [ + { + "name": "field", + "description": "", + "type": "String" + }, + { + "name": "value", + "description": "", + "type": "Number" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Decrement user score\n\n client.collection('users').where('_id', user_id).decrement('score', 10).then(function(numRows) {\n console.log(numRows, \" users has been updated\");\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 622, + "description": "Update all collection's data based on `where` params.", + "itemtype": "method", + "name": "updateAll", + "params": [ + { + "name": "data", + "description": "key-value data to update from matched rows [optional]", + "type": "Object" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Updating all rows of the collection\n\n client.collection('users').updateAll({category: 'everybody'}).then(function(numRows) {\n console.log(numRows, \" users has been updated\");\n });", + " Updating collection filters\n\n client.collection('users').where('age','<',18).updateAll({category: 'baby'}).then(function(numRows) {\n console.log(numRows, \" users has been updated\");\n });" + ], + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection.js", + "line": 706, + "description": "Return a new copy of the collection.", + "itemtype": "method", + "name": "clone", + "return": { + "description": "", + "type": "Collection" + }, + "class": "Hook.Collection", + "module": "Hook" + }, + { + "file": "src/collection_item.js", + "line": 1, + "description": "module Hook\nclass Hook.CollectionItem\n\nparam {Hook.Collection} collection\nparam {Number|String} _id\nconstructor", + "class": "Hook.KeyValues", + "module": "Hook" + }, + { + "file": "src/key_values.js", + "line": 12, + "itemtype": "method", + "name": "get", + "params": [ + { + "name": "key", + "description": "", + "type": "String" + }, + { + "name": "callback", + "description": "", + "type": "Function" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Get a key value\n\n client.keys.get('my-custom-key', function(key) {\n console.log(key.value);\n });" + ], + "class": "Hook.KeyValues", + "module": "Hook" + }, + { + "file": "src/key_values.js", + "line": 32, + "itemtype": "method", + "name": "set", + "params": [ + { + "name": "key", + "description": "", + "type": "String" + }, + { + "name": "value", + "description": "", + "type": "String|Number" + } + ], + "return": { + "description": "", + "type": "Promise" + }, + "example": [ + " Set a key value\n\n client.keys.set('my-custom-key', 'custom value').then(function(key) {\n console.log(key);\n });" + ], + "class": "Hook.KeyValues", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 12, + "itemtype": "property", + "name": "collection", + "type": "{Hook.Collection}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 22, + "itemtype": "property", + "name": "total", + "type": "{Number}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 28, + "itemtype": "property", + "name": "per_page", + "type": "{Number}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 34, + "itemtype": "property", + "name": "current_page", + "type": "{Number}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 40, + "itemtype": "property", + "name": "last_page", + "type": "{Number}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 46, + "itemtype": "property", + "name": "from", + "type": "{Number}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 52, + "itemtype": "property", + "name": "to", + "type": "{Number}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 58, + "itemtype": "property", + "name": "items", + "type": "{Object}", + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 65, + "itemtype": "method", + "name": "hasNext", + "return": { + "description": "", + "type": "Boolean" + }, + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/pagination.js", + "line": 73, + "itemtype": "method", + "name": "isFetching", + "return": { + "description": "", + "type": "Booelan" + }, + "class": "Hook.Pagination", + "module": "Hook" + }, + { + "file": "src/system.js", + "line": 12, + "description": "Return server's system time.", + "itemtype": "method", + "name": "time", + "return": { + "description": "", + "type": "Promise" + }, + "class": "Hook.System", + "module": "Hook" + } + ], + "warnings": [ + { + "message": "Missing item type", + "line": " src/channel/sse.js:91" + }, + { + "message": "Missing item type\n-------------\nDependency plugins:\n-------------\n- https://github.com/phonegap-build/PushPlugin\n- https://github.com/apache/cordova-plugin-device\n- https://github.com/danmichaelo/cordova-plugin-appinfo", + "line": " src/plugins/cordova/push_notification.js:1" + }, + { + "message": "Missing item type\nmethod _registerDevice", + "line": " src/plugins/cordova/push_notification.js:212" + }, + { + "message": "Missing item type\nChannel implementations", + "line": " src/channel.js:1" + }, + { + "message": "Missing item type\nDrop entire collection. This operation is irreversible.", + "line": " src/collection.js:528" + }, + { + "message": "Missing item type\nmodule Hook\nclass Hook.CollectionItem\n\nparam {Hook.Collection} collection\nparam {Number|String} _id\nconstructor", + "line": " src/collection_item.js:1" + } + ] +} \ No newline at end of file diff --git a/dist/hook.js b/dist/hook.js deleted file mode 100644 index 0be15b3..0000000 --- a/dist/hook.js +++ /dev/null @@ -1,10032 +0,0 @@ -/* - * hook-javascript v0.3.9 - * https://github.com/doubleleft/hook-javascript - * - * @copyright 2015 Doubleleft - * @build 7/20/2015 - */ -(function(window) { - -/** - * JSON Date Extensions - JSON date parsing extensions - * - * (c) 2014 Rick Strahl, West Wind Technologies - * - * Released under MIT License - * http://en.wikipedia.org/wiki/MIT_License - */ -(function(undefined) { - if (this.JSON && !this.JSON.dateParser) { - var reISO = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.{0,1}\d*))(?:Z|(\+|-)([\d|:]*))?$/; - var reMsAjax = /^\/Date\((d|-|.*)\)[\/|\\]$/; - - /// - /// set this if you want MS Ajax Dates parsed - /// before calling any of the other functions - /// - JSON.parseMsAjaxDate = false; - - JSON.useDateParser = function(reset) { - /// - /// Globally enables JSON date parsing for JSON.parse(). - /// Replaces the default JSON.parse() method and adds - /// the datePaser() extension to the processing chain. - /// - /// when set restores the original JSON.parse() function - - // if any parameter is passed reset - if (typeof reset != "undefined") { - if (JSON._parseSaved) { - JSON.parse = JSON._parseSaved; - JSON._parseSaved = null; - } - } else { - if (!JSON.parseSaved) { - JSON._parseSaved = JSON.parse; - JSON.parse = JSON.parseWithDate; - } - } - }; - - /// - /// Creates a new filter that processes dates and also delegates to a chain filter optionaly. - /// - /// property name that is parsed - /// returns a new chainning filter for dates - function createDateParser(chainFilter) { - return function(key, value) { - if (typeof value === 'string') { - var a = reISO.exec(value); - if (a) - return new Date(value); - - if (!JSON.parseMsAjaxDate) - return value; - - a = reMsAjax.exec(value); - if (a) { - var b = a[1].split(/[-+,.]/); - return new Date(b[0] ? +b[0] : 0 - +b[1]); - } - } - if (chainFilter !== undefined) - return chainFilter(key, value); - else - return value; - }; - } - - /// - /// A filter that can be used with JSON.parse to convert dates. - /// - /// property name that is parsed - /// property value - /// returns date or the original value if not a date string - JSON.dateParser = createDateParser(); - - JSON.parseWithDate = function(json, chainFilter) { - /// - /// Wrapper around the JSON.parse() function that adds a date - /// filtering extension. Returns all dates as real JavaScript dates. - /// - /// JSON to be parsed - /// parsed value or object - var parse = JSON._parseSaved ? JSON._parseSaved : JSON.parse; - try { - var res = parse(json, createDateParser(chainFilter)); - return res; - } catch (e) { - // orignal error thrown has no error message so rethrow with message - throw new Error("JSON content could not be parsed"); - } - }; - - JSON.dateStringToDate = function(dtString, nullDateVal) { - /// - /// Converts a JSON ISO or MSAJAX date or real date a date value. - /// Supports both JSON encoded dates or plain date formatted strings - /// (without the JSON string quotes). - /// If you pass a date the date is returned as is. If you pass null - /// null or the nullDateVal is returned. - /// - /// Date String in ISO or MSAJAX format - /// value to return if date can't be parsed - /// date or the nullDateVal (null by default) - if (!nullDateVal) - nullDateVal = null; - - if (!dtString) - return nullDateVal; // empty - - if (dtString.getTime) - return dtString; // already a date - - if (dtString[0] === '"' || dtString[0] === "'") - // strip off JSON quotes - dtString = dtString.substr(1, dtString.length - 2); - - var a = reISO.exec(dtString); - if (a) - return new Date(dtString); - - if (!JSON.parseMsAjaxDate) - return nullDateVal; - - a = reMsAjax.exec(dtString); - if (a) { - var b = a[1].split(/[-,.]/); - return new Date(+b[0]); - } - return nullDateVal; - }; - } -})(); - -/*! - * @overview es6-promise - a tiny implementation of Promises/A+. - * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) - * @license Licensed under MIT license - * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE - * @version 2.2.0 - */ - -(function() { - "use strict"; - function lib$es6$promise$utils$$objectOrFunction(x) { - return typeof x === 'function' || (typeof x === 'object' && x !== null); - } - - function lib$es6$promise$utils$$isFunction(x) { - return typeof x === 'function'; - } - - function lib$es6$promise$utils$$isMaybeThenable(x) { - return typeof x === 'object' && x !== null; - } - - var lib$es6$promise$utils$$_isArray; - if (!Array.isArray) { - lib$es6$promise$utils$$_isArray = function (x) { - return Object.prototype.toString.call(x) === '[object Array]'; - }; - } else { - lib$es6$promise$utils$$_isArray = Array.isArray; - } - - var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray; - var lib$es6$promise$asap$$len = 0; - var lib$es6$promise$asap$$toString = {}.toString; - var lib$es6$promise$asap$$vertxNext; - var lib$es6$promise$asap$$customSchedulerFn; - - function lib$es6$promise$asap$$asap(callback, arg) { - lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback; - lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg; - lib$es6$promise$asap$$len += 2; - if (lib$es6$promise$asap$$len === 2) { - // If len is 2, that means that we need to schedule an async flush. - // If additional callbacks are queued before the queue is flushed, they - // will be processed by this flush that we are scheduling. - if (lib$es6$promise$asap$$customSchedulerFn) { - lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush); - } else { - lib$es6$promise$asap$$scheduleFlush(); - } - } - } - - var lib$es6$promise$asap$$default = lib$es6$promise$asap$$asap; - function lib$es6$promise$asap$$setScheduler(scheduleFn) { - lib$es6$promise$asap$$customSchedulerFn = scheduleFn; - } - - var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined; - var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {}; - var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver; - var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; - - // test for web worker but not in IE10 - var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && - typeof importScripts !== 'undefined' && - typeof MessageChannel !== 'undefined'; - - // node - function lib$es6$promise$asap$$useNextTick() { - var nextTick = process.nextTick; - // node version 0.10.x displays a deprecation warning when nextTick is used recursively - // setImmediate should be used instead instead - var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/); - if (Array.isArray(version) && version[1] === '0' && version[2] === '10') { - nextTick = setImmediate; - } - return function() { - nextTick(lib$es6$promise$asap$$flush); - }; - } - - // vertx - function lib$es6$promise$asap$$useVertxTimer() { - return function() { - lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush); - }; - } - - function lib$es6$promise$asap$$useMutationObserver() { - var iterations = 0; - var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush); - var node = document.createTextNode(''); - observer.observe(node, { characterData: true }); - - return function() { - node.data = (iterations = ++iterations % 2); - }; - } - - // web worker - function lib$es6$promise$asap$$useMessageChannel() { - var channel = new MessageChannel(); - channel.port1.onmessage = lib$es6$promise$asap$$flush; - return function () { - channel.port2.postMessage(0); - }; - } - - function lib$es6$promise$asap$$useSetTimeout() { - return function() { - setTimeout(lib$es6$promise$asap$$flush, 1); - }; - } - - var lib$es6$promise$asap$$queue = new Array(1000); - function lib$es6$promise$asap$$flush() { - for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) { - var callback = lib$es6$promise$asap$$queue[i]; - var arg = lib$es6$promise$asap$$queue[i+1]; - - callback(arg); - - lib$es6$promise$asap$$queue[i] = undefined; - lib$es6$promise$asap$$queue[i+1] = undefined; - } - - lib$es6$promise$asap$$len = 0; - } - - function lib$es6$promise$asap$$attemptVertex() { - try { - var r = require; - var vertx = r('vertx'); - lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext; - return lib$es6$promise$asap$$useVertxTimer(); - } catch(e) { - return lib$es6$promise$asap$$useSetTimeout(); - } - } - - var lib$es6$promise$asap$$scheduleFlush; - // Decide what async method to use to triggering processing of queued callbacks: - if (lib$es6$promise$asap$$isNode) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick(); - } else if (lib$es6$promise$asap$$BrowserMutationObserver) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver(); - } else if (lib$es6$promise$asap$$isWorker) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel(); - } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertex(); - } else { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout(); - } - - function lib$es6$promise$$internal$$noop() {} - - var lib$es6$promise$$internal$$PENDING = void 0; - var lib$es6$promise$$internal$$FULFILLED = 1; - var lib$es6$promise$$internal$$REJECTED = 2; - - var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject(); - - function lib$es6$promise$$internal$$selfFullfillment() { - return new TypeError("You cannot resolve a promise with itself"); - } - - function lib$es6$promise$$internal$$cannotReturnOwn() { - return new TypeError('A promises callback cannot return that same promise.'); - } - - function lib$es6$promise$$internal$$getThen(promise) { - try { - return promise.then; - } catch(error) { - lib$es6$promise$$internal$$GET_THEN_ERROR.error = error; - return lib$es6$promise$$internal$$GET_THEN_ERROR; - } - } - - function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { - try { - then.call(value, fulfillmentHandler, rejectionHandler); - } catch(e) { - return e; - } - } - - function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) { - lib$es6$promise$asap$$default(function(promise) { - var sealed = false; - var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) { - if (sealed) { return; } - sealed = true; - if (thenable !== value) { - lib$es6$promise$$internal$$resolve(promise, value); - } else { - lib$es6$promise$$internal$$fulfill(promise, value); - } - }, function(reason) { - if (sealed) { return; } - sealed = true; - - lib$es6$promise$$internal$$reject(promise, reason); - }, 'Settle: ' + (promise._label || ' unknown promise')); - - if (!sealed && error) { - sealed = true; - lib$es6$promise$$internal$$reject(promise, error); - } - }, promise); - } - - function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) { - if (thenable._state === lib$es6$promise$$internal$$FULFILLED) { - lib$es6$promise$$internal$$fulfill(promise, thenable._result); - } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, thenable._result); - } else { - lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) { - lib$es6$promise$$internal$$resolve(promise, value); - }, function(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - }); - } - } - - function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) { - if (maybeThenable.constructor === promise.constructor) { - lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable); - } else { - var then = lib$es6$promise$$internal$$getThen(maybeThenable); - - if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error); - } else if (then === undefined) { - lib$es6$promise$$internal$$fulfill(promise, maybeThenable); - } else if (lib$es6$promise$utils$$isFunction(then)) { - lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then); - } else { - lib$es6$promise$$internal$$fulfill(promise, maybeThenable); - } - } - } - - function lib$es6$promise$$internal$$resolve(promise, value) { - if (promise === value) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFullfillment()); - } else if (lib$es6$promise$utils$$objectOrFunction(value)) { - lib$es6$promise$$internal$$handleMaybeThenable(promise, value); - } else { - lib$es6$promise$$internal$$fulfill(promise, value); - } - } - - function lib$es6$promise$$internal$$publishRejection(promise) { - if (promise._onerror) { - promise._onerror(promise._result); - } - - lib$es6$promise$$internal$$publish(promise); - } - - function lib$es6$promise$$internal$$fulfill(promise, value) { - if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } - - promise._result = value; - promise._state = lib$es6$promise$$internal$$FULFILLED; - - if (promise._subscribers.length !== 0) { - lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publish, promise); - } - } - - function lib$es6$promise$$internal$$reject(promise, reason) { - if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } - promise._state = lib$es6$promise$$internal$$REJECTED; - promise._result = reason; - - lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publishRejection, promise); - } - - function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) { - var subscribers = parent._subscribers; - var length = subscribers.length; - - parent._onerror = null; - - subscribers[length] = child; - subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment; - subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection; - - if (length === 0 && parent._state) { - lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publish, parent); - } - } - - function lib$es6$promise$$internal$$publish(promise) { - var subscribers = promise._subscribers; - var settled = promise._state; - - if (subscribers.length === 0) { return; } - - var child, callback, detail = promise._result; - - for (var i = 0; i < subscribers.length; i += 3) { - child = subscribers[i]; - callback = subscribers[i + settled]; - - if (child) { - lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail); - } else { - callback(detail); - } - } - - promise._subscribers.length = 0; - } - - function lib$es6$promise$$internal$$ErrorObject() { - this.error = null; - } - - var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject(); - - function lib$es6$promise$$internal$$tryCatch(callback, detail) { - try { - return callback(detail); - } catch(e) { - lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e; - return lib$es6$promise$$internal$$TRY_CATCH_ERROR; - } - } - - function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) { - var hasCallback = lib$es6$promise$utils$$isFunction(callback), - value, error, succeeded, failed; - - if (hasCallback) { - value = lib$es6$promise$$internal$$tryCatch(callback, detail); - - if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) { - failed = true; - error = value.error; - value = null; - } else { - succeeded = true; - } - - if (promise === value) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn()); - return; - } - - } else { - value = detail; - succeeded = true; - } - - if (promise._state !== lib$es6$promise$$internal$$PENDING) { - // noop - } else if (hasCallback && succeeded) { - lib$es6$promise$$internal$$resolve(promise, value); - } else if (failed) { - lib$es6$promise$$internal$$reject(promise, error); - } else if (settled === lib$es6$promise$$internal$$FULFILLED) { - lib$es6$promise$$internal$$fulfill(promise, value); - } else if (settled === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, value); - } - } - - function lib$es6$promise$$internal$$initializePromise(promise, resolver) { - try { - resolver(function resolvePromise(value){ - lib$es6$promise$$internal$$resolve(promise, value); - }, function rejectPromise(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - }); - } catch(e) { - lib$es6$promise$$internal$$reject(promise, e); - } - } - - function lib$es6$promise$enumerator$$Enumerator(Constructor, input) { - var enumerator = this; - - enumerator._instanceConstructor = Constructor; - enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop); - - if (enumerator._validateInput(input)) { - enumerator._input = input; - enumerator.length = input.length; - enumerator._remaining = input.length; - - enumerator._init(); - - if (enumerator.length === 0) { - lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); - } else { - enumerator.length = enumerator.length || 0; - enumerator._enumerate(); - if (enumerator._remaining === 0) { - lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); - } - } - } else { - lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError()); - } - } - - lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) { - return lib$es6$promise$utils$$isArray(input); - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() { - return new Error('Array Methods must be provided an Array'); - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._init = function() { - this._result = new Array(this.length); - }; - - var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator; - - lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() { - var enumerator = this; - - var length = enumerator.length; - var promise = enumerator.promise; - var input = enumerator._input; - - for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { - enumerator._eachEntry(input[i], i); - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) { - var enumerator = this; - var c = enumerator._instanceConstructor; - - if (lib$es6$promise$utils$$isMaybeThenable(entry)) { - if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) { - entry._onerror = null; - enumerator._settledAt(entry._state, i, entry._result); - } else { - enumerator._willSettleAt(c.resolve(entry), i); - } - } else { - enumerator._remaining--; - enumerator._result[i] = entry; - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) { - var enumerator = this; - var promise = enumerator.promise; - - if (promise._state === lib$es6$promise$$internal$$PENDING) { - enumerator._remaining--; - - if (state === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, value); - } else { - enumerator._result[i] = value; - } - } - - if (enumerator._remaining === 0) { - lib$es6$promise$$internal$$fulfill(promise, enumerator._result); - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { - var enumerator = this; - - lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) { - enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value); - }, function(reason) { - enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason); - }); - }; - function lib$es6$promise$promise$all$$all(entries) { - return new lib$es6$promise$enumerator$$default(this, entries).promise; - } - var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all; - function lib$es6$promise$promise$race$$race(entries) { - /*jshint validthis:true */ - var Constructor = this; - - var promise = new Constructor(lib$es6$promise$$internal$$noop); - - if (!lib$es6$promise$utils$$isArray(entries)) { - lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); - return promise; - } - - var length = entries.length; - - function onFulfillment(value) { - lib$es6$promise$$internal$$resolve(promise, value); - } - - function onRejection(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - } - - for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { - lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); - } - - return promise; - } - var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race; - function lib$es6$promise$promise$resolve$$resolve(object) { - /*jshint validthis:true */ - var Constructor = this; - - if (object && typeof object === 'object' && object.constructor === Constructor) { - return object; - } - - var promise = new Constructor(lib$es6$promise$$internal$$noop); - lib$es6$promise$$internal$$resolve(promise, object); - return promise; - } - var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve; - function lib$es6$promise$promise$reject$$reject(reason) { - /*jshint validthis:true */ - var Constructor = this; - var promise = new Constructor(lib$es6$promise$$internal$$noop); - lib$es6$promise$$internal$$reject(promise, reason); - return promise; - } - var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject; - - var lib$es6$promise$promise$$counter = 0; - - function lib$es6$promise$promise$$needsResolver() { - throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); - } - - function lib$es6$promise$promise$$needsNew() { - throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); - } - - var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise; - /** - Promise objects represent the eventual result of an asynchronous operation. The - primary way of interacting with a promise is through its `then` method, which - registers callbacks to receive either a promise’s eventual value or the reason - why the promise cannot be fulfilled. - - Terminology - ----------- - - - `promise` is an object or function with a `then` method whose behavior conforms to this specification. - - `thenable` is an object or function that defines a `then` method. - - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). - - `exception` is a value that is thrown using the throw statement. - - `reason` is a value that indicates why a promise was rejected. - - `settled` the final resting state of a promise, fulfilled or rejected. - - A promise can be in one of three states: pending, fulfilled, or rejected. - - Promises that are fulfilled have a fulfillment value and are in the fulfilled - state. Promises that are rejected have a rejection reason and are in the - rejected state. A fulfillment value is never a thenable. - - Promises can also be said to *resolve* a value. If this value is also a - promise, then the original promise's settled state will match the value's - settled state. So a promise that *resolves* a promise that rejects will - itself reject, and a promise that *resolves* a promise that fulfills will - itself fulfill. - - - Basic Usage: - ------------ - - ```js - var promise = new Promise(function(resolve, reject) { - // on success - resolve(value); - - // on failure - reject(reason); - }); - - promise.then(function(value) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Advanced Usage: - --------------- - - Promises shine when abstracting away asynchronous interactions such as - `XMLHttpRequest`s. - - ```js - function getJSON(url) { - return new Promise(function(resolve, reject){ - var xhr = new XMLHttpRequest(); - - xhr.open('GET', url); - xhr.onreadystatechange = handler; - xhr.responseType = 'json'; - xhr.setRequestHeader('Accept', 'application/json'); - xhr.send(); - - function handler() { - if (this.readyState === this.DONE) { - if (this.status === 200) { - resolve(this.response); - } else { - reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); - } - } - }; - }); - } - - getJSON('/posts.json').then(function(json) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Unlike callbacks, promises are great composable primitives. - - ```js - Promise.all([ - getJSON('/posts'), - getJSON('/comments') - ]).then(function(values){ - values[0] // => postsJSON - values[1] // => commentsJSON - - return values; - }); - ``` - - @class Promise - @param {function} resolver - Useful for tooling. - @constructor - */ - function lib$es6$promise$promise$$Promise(resolver) { - this._id = lib$es6$promise$promise$$counter++; - this._state = undefined; - this._result = undefined; - this._subscribers = []; - - if (lib$es6$promise$$internal$$noop !== resolver) { - if (!lib$es6$promise$utils$$isFunction(resolver)) { - lib$es6$promise$promise$$needsResolver(); - } - - if (!(this instanceof lib$es6$promise$promise$$Promise)) { - lib$es6$promise$promise$$needsNew(); - } - - lib$es6$promise$$internal$$initializePromise(this, resolver); - } - } - - lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default; - lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default; - lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default; - lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default; - lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler; - lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$default; - - lib$es6$promise$promise$$Promise.prototype = { - constructor: lib$es6$promise$promise$$Promise, - - /** - The primary way of interacting with a promise is through its `then` method, - which registers callbacks to receive either a promise's eventual value or the - reason why the promise cannot be fulfilled. - - ```js - findUser().then(function(user){ - // user is available - }, function(reason){ - // user is unavailable, and you are given the reason why - }); - ``` - - Chaining - -------- - - The return value of `then` is itself a promise. This second, 'downstream' - promise is resolved with the return value of the first promise's fulfillment - or rejection handler, or rejected if the handler throws an exception. - - ```js - findUser().then(function (user) { - return user.name; - }, function (reason) { - return 'default name'; - }).then(function (userName) { - // If `findUser` fulfilled, `userName` will be the user's name, otherwise it - // will be `'default name'` - }); - - findUser().then(function (user) { - throw new Error('Found user, but still unhappy'); - }, function (reason) { - throw new Error('`findUser` rejected and we're unhappy'); - }).then(function (value) { - // never reached - }, function (reason) { - // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. - // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. - }); - ``` - If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. - - ```js - findUser().then(function (user) { - throw new PedagogicalException('Upstream error'); - }).then(function (value) { - // never reached - }).then(function (value) { - // never reached - }, function (reason) { - // The `PedgagocialException` is propagated all the way down to here - }); - ``` - - Assimilation - ------------ - - Sometimes the value you want to propagate to a downstream promise can only be - retrieved asynchronously. This can be achieved by returning a promise in the - fulfillment or rejection handler. The downstream promise will then be pending - until the returned promise is settled. This is called *assimilation*. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // The user's comments are now available - }); - ``` - - If the assimliated promise rejects, then the downstream promise will also reject. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // If `findCommentsByAuthor` fulfills, we'll have the value here - }, function (reason) { - // If `findCommentsByAuthor` rejects, we'll have the reason here - }); - ``` - - Simple Example - -------------- - - Synchronous Example - - ```javascript - var result; - - try { - result = findResult(); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - findResult(function(result, err){ - if (err) { - // failure - } else { - // success - } - }); - ``` - - Promise Example; - - ```javascript - findResult().then(function(result){ - // success - }, function(reason){ - // failure - }); - ``` - - Advanced Example - -------------- - - Synchronous Example - - ```javascript - var author, books; - - try { - author = findAuthor(); - books = findBooksByAuthor(author); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - - function foundBooks(books) { - - } - - function failure(reason) { - - } - - findAuthor(function(author, err){ - if (err) { - failure(err); - // failure - } else { - try { - findBoooksByAuthor(author, function(books, err) { - if (err) { - failure(err); - } else { - try { - foundBooks(books); - } catch(reason) { - failure(reason); - } - } - }); - } catch(error) { - failure(err); - } - // success - } - }); - ``` - - Promise Example; - - ```javascript - findAuthor(). - then(findBooksByAuthor). - then(function(books){ - // found books - }).catch(function(reason){ - // something went wrong - }); - ``` - - @method then - @param {Function} onFulfilled - @param {Function} onRejected - Useful for tooling. - @return {Promise} - */ - then: function(onFulfillment, onRejection) { - var parent = this; - var state = parent._state; - - if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { - return this; - } - - var child = new this.constructor(lib$es6$promise$$internal$$noop); - var result = parent._result; - - if (state) { - var callback = arguments[state - 1]; - lib$es6$promise$asap$$default(function(){ - lib$es6$promise$$internal$$invokeCallback(state, child, callback, result); - }); - } else { - lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection); - } - - return child; - }, - - /** - `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same - as the catch block of a try/catch statement. - - ```js - function findAuthor(){ - throw new Error('couldn't find that author'); - } - - // synchronous - try { - findAuthor(); - } catch(reason) { - // something went wrong - } - - // async with promises - findAuthor().catch(function(reason){ - // something went wrong - }); - ``` - - @method catch - @param {Function} onRejection - Useful for tooling. - @return {Promise} - */ - 'catch': function(onRejection) { - return this.then(null, onRejection); - } - }; - function lib$es6$promise$polyfill$$polyfill() { - var local; - - if (typeof global !== 'undefined') { - local = global; - } else if (typeof self !== 'undefined') { - local = self; - } else { - try { - local = Function('return this')(); - } catch (e) { - throw new Error('polyfill failed because global object is unavailable in this environment'); - } - } - - var P = local.Promise; - - if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { - return; - } - - local.Promise = lib$es6$promise$promise$$default; - } - var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; - - var lib$es6$promise$umd$$ES6Promise = { - 'Promise': lib$es6$promise$promise$$default, - 'polyfill': lib$es6$promise$polyfill$$default - }; - - /* global define:true module:true window: true */ - if (typeof define === 'function' && define['amd']) { - define(function() { return lib$es6$promise$umd$$ES6Promise; }); - } else if (typeof module !== 'undefined' && module['exports']) { - module['exports'] = lib$es6$promise$umd$$ES6Promise; - } else if (typeof this !== 'undefined') { - this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise; - } - - lib$es6$promise$polyfill$$default(); -}).call(this); - - -(function (root, factory) { - if (typeof exports === 'object') { - module.exports = factory(); - } else if (typeof define === 'function' && define.amd) { - define('uxhr', factory); - } else { - root.uxhr = factory(); - } -}(this, function () { - - "use strict"; - - return function (url, data, options) { - - data = data || ''; - options = options || {}; - - var complete = options.complete || function(){}, - success = options.success || function(){}, - error = options.error || function(){}, - timeout = options.timeout || 0, - ontimeout = options.ontimeout || function(){}, - onprogress = options.onprogress || function(){}, - headers = options.headers || {}, - method = options.method || 'GET', - sync = options.sync || false, - req = (function() { - - if (typeof 'XMLHttpRequest' !== 'undefined') { - - // CORS (IE8-9) - if (url.indexOf('http') === 0 && typeof XDomainRequest !== 'undefined') { - return new XDomainRequest(); - } - - // local, CORS (other browsers) - return new XMLHttpRequest(); - - } else if (typeof 'ActiveXObject' !== 'undefined') { - return new ActiveXObject('Microsoft.XMLHTTP'); - } - - })(); - - if (!req) { - throw new Error ('Browser doesn\'t support XHR'); - } - - // serialize data? - var hasFormData = (typeof(window.FormData) !== 'undefined'); - if (typeof data !== 'string' && (hasFormData && !(data instanceof window.FormData))) { - var serialized = []; - for (var datum in data) { - serialized.push(datum + '=' + data[datum]); - } - data = serialized.join('&'); - } - - // use ? or &, accourding to given url - if (method === 'GET' && data) { - url += (url.indexOf('?') >= 0) ? '&' + data : '?' + data; - } - - // open connection - req.open(method, url, !sync); - - // set timeout - // timeouts cannot be set for synchronous requests made from a document. - if (!sync) { - if ('ontimeout' in req) { - req.timeout = timeout; - req.ontimeout = ontimeout; - } - } - - // set onprogress - if ('onprogress' in req) { - req.onprogress = onprogress; - } - - // listen for XHR events - req.onload = function () { - complete(req.responseText, req.status); - success(req.responseText); - }; - req.onerror = function () { - complete(req.responseText); - error(req.responseText, req.status); - }; - - if (typeof(req.setRequestHeader)!=="undefined") { - // set headers - for (var header in headers) { - req.setRequestHeader(header, headers[header]); - } - } - - // send it - req.send(method !== 'GET' ? data : null); - return req; - }; - -})); - -/** - * @license - * Lo-Dash 2.4.2 (Custom Build) - * Build: `lodash modern -o ./dist/lodash.js` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -;(function() { - - /** Used as a safe reference for `undefined` in pre ES5 environments */ - var undefined; - - /** Used to pool arrays and objects used internally */ - var arrayPool = [], - objectPool = []; - - /** Used to generate unique IDs */ - var idCounter = 0; - - /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */ - var keyPrefix = +new Date + ''; - - /** Used as the size when optimizations are enabled for large arrays */ - var largeArraySize = 75; - - /** Used as the max size of the `arrayPool` and `objectPool` */ - var maxPoolSize = 40; - - /** Used to detect and test whitespace */ - var whitespace = ( - // whitespace - ' \t\x0B\f\xA0\ufeff' + - - // line terminators - '\n\r\u2028\u2029' + - - // unicode category "Zs" space separators - '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000' - ); - - /** Used to match empty string literals in compiled template source */ - var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - - /** - * Used to match ES6 template delimiters - * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals - */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - - /** Used to match regexp flags from their coerced string values */ - var reFlags = /\w*$/; - - /** Used to detected named functions */ - var reFuncName = /^\s*function[ \n\r\t]+\w/; - - /** Used to match "interpolate" template delimiters */ - var reInterpolate = /<%=([\s\S]+?)%>/g; - - /** Used to match leading whitespace and zeros to be removed */ - var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)'); - - /** Used to ensure capturing order of template delimiters */ - var reNoMatch = /($^)/; - - /** Used to detect functions containing a `this` reference */ - var reThis = /\bthis\b/; - - /** Used to match unescaped characters in compiled string literals */ - var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; - - /** Used to assign default `context` object properties */ - var contextProps = [ - 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', - 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', - 'parseInt', 'setTimeout' - ]; - - /** Used to make template sourceURLs easier to identify */ - var templateCounter = 0; - - /** `Object#toString` result shortcuts */ - var argsClass = '[object Arguments]', - arrayClass = '[object Array]', - boolClass = '[object Boolean]', - dateClass = '[object Date]', - funcClass = '[object Function]', - numberClass = '[object Number]', - objectClass = '[object Object]', - regexpClass = '[object RegExp]', - stringClass = '[object String]'; - - /** Used to identify object classifications that `_.clone` supports */ - var cloneableClasses = {}; - cloneableClasses[funcClass] = false; - cloneableClasses[argsClass] = cloneableClasses[arrayClass] = - cloneableClasses[boolClass] = cloneableClasses[dateClass] = - cloneableClasses[numberClass] = cloneableClasses[objectClass] = - cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; - - /** Used as an internal `_.debounce` options object */ - var debounceOptions = { - 'leading': false, - 'maxWait': 0, - 'trailing': false - }; - - /** Used as the property descriptor for `__bindData__` */ - var descriptor = { - 'configurable': false, - 'enumerable': false, - 'value': null, - 'writable': false - }; - - /** Used to determine if values are of the language type Object */ - var objectTypes = { - 'boolean': false, - 'function': true, - 'object': true, - 'number': false, - 'string': false, - 'undefined': false - }; - - /** Used to escape characters for inclusion in compiled string literals */ - var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\t': 't', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - /** Used as a reference to the global object */ - var root = (objectTypes[typeof window] && window) || this; - - /** Detect free variable `exports` */ - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - - /** Detect free variable `module` */ - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; - - /** Detect the popular CommonJS extension `module.exports` */ - var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; - - /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */ - var freeGlobal = objectTypes[typeof global] && global; - if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { - root = freeGlobal; - } - - /*--------------------------------------------------------------------------*/ - - /** - * The base implementation of `_.indexOf` without support for binary searches - * or `fromIndex` constraints. - * - * @private - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value or `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - var index = (fromIndex || 0) - 1, - length = array ? array.length : 0; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * An implementation of `_.contains` for cache objects that mimics the return - * signature of `_.indexOf` by returning `0` if the value is found, else `-1`. - * - * @private - * @param {Object} cache The cache object to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns `0` if `value` is found, else `-1`. - */ - function cacheIndexOf(cache, value) { - var type = typeof value; - cache = cache.cache; - - if (type == 'boolean' || value == null) { - return cache[value] ? 0 : -1; - } - if (type != 'number' && type != 'string') { - type = 'object'; - } - var key = type == 'number' ? value : keyPrefix + value; - cache = (cache = cache[type]) && cache[key]; - - return type == 'object' - ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1) - : (cache ? 0 : -1); - } - - /** - * Adds a given value to the corresponding cache object. - * - * @private - * @param {*} value The value to add to the cache. - */ - function cachePush(value) { - var cache = this.cache, - type = typeof value; - - if (type == 'boolean' || value == null) { - cache[value] = true; - } else { - if (type != 'number' && type != 'string') { - type = 'object'; - } - var key = type == 'number' ? value : keyPrefix + value, - typeCache = cache[type] || (cache[type] = {}); - - if (type == 'object') { - (typeCache[key] || (typeCache[key] = [])).push(value); - } else { - typeCache[key] = true; - } - } - } - - /** - * Used by `_.max` and `_.min` as the default callback when a given - * collection is a string value. - * - * @private - * @param {string} value The character to inspect. - * @returns {number} Returns the code unit of given character. - */ - function charAtCallback(value) { - return value.charCodeAt(0); - } - - /** - * Used by `sortBy` to compare transformed `collection` elements, stable sorting - * them in ascending order. - * - * @private - * @param {Object} a The object to compare to `b`. - * @param {Object} b The object to compare to `a`. - * @returns {number} Returns the sort order indicator of `1` or `-1`. - */ - function compareAscending(a, b) { - var ac = a.criteria, - bc = b.criteria, - index = -1, - length = ac.length; - - while (++index < length) { - var value = ac[index], - other = bc[index]; - - if (value !== other) { - if (value > other || typeof value == 'undefined') { - return 1; - } - if (value < other || typeof other == 'undefined') { - return -1; - } - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to return the same value for - // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 - // - // This also ensures a stable sort in V8 and other engines. - // See http://code.google.com/p/v8/issues/detail?id=90 - return a.index - b.index; - } - - /** - * Creates a cache object to optimize linear searches of large arrays. - * - * @private - * @param {Array} [array=[]] The array to search. - * @returns {null|Object} Returns the cache object or `null` if caching should not be used. - */ - function createCache(array) { - var index = -1, - length = array.length, - first = array[0], - mid = array[(length / 2) | 0], - last = array[length - 1]; - - if (first && typeof first == 'object' && - mid && typeof mid == 'object' && last && typeof last == 'object') { - return false; - } - var cache = getObject(); - cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false; - - var result = getObject(); - result.array = array; - result.cache = cache; - result.push = cachePush; - - while (++index < length) { - result.push(array[index]); - } - return result; - } - - /** - * Used by `template` to escape characters for inclusion in compiled - * string literals. - * - * @private - * @param {string} match The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(match) { - return '\\' + stringEscapes[match]; - } - - /** - * Gets an array from the array pool or creates a new one if the pool is empty. - * - * @private - * @returns {Array} The array from the pool. - */ - function getArray() { - return arrayPool.pop() || []; - } - - /** - * Gets an object from the object pool or creates a new one if the pool is empty. - * - * @private - * @returns {Object} The object from the pool. - */ - function getObject() { - return objectPool.pop() || { - 'array': null, - 'cache': null, - 'criteria': null, - 'false': false, - 'index': 0, - 'null': false, - 'number': null, - 'object': null, - 'push': null, - 'string': null, - 'true': false, - 'undefined': false, - 'value': null - }; - } - - /** - * Releases the given array back to the array pool. - * - * @private - * @param {Array} [array] The array to release. - */ - function releaseArray(array) { - array.length = 0; - if (arrayPool.length < maxPoolSize) { - arrayPool.push(array); - } - } - - /** - * Releases the given object back to the object pool. - * - * @private - * @param {Object} [object] The object to release. - */ - function releaseObject(object) { - var cache = object.cache; - if (cache) { - releaseObject(cache); - } - object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; - if (objectPool.length < maxPoolSize) { - objectPool.push(object); - } - } - - /** - * Slices the `collection` from the `start` index up to, but not including, - * the `end` index. - * - * Note: This function is used instead of `Array#slice` to support node lists - * in IE < 9 and to ensure dense arrays are returned. - * - * @private - * @param {Array|Object|string} collection The collection to slice. - * @param {number} start The start index. - * @param {number} end The end index. - * @returns {Array} Returns the new array. - */ - function slice(array, start, end) { - start || (start = 0); - if (typeof end == 'undefined') { - end = array ? array.length : 0; - } - var index = -1, - length = end - start || 0, - result = Array(length < 0 ? 0 : length); - - while (++index < length) { - result[index] = array[start + index]; - } - return result; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Create a new `lodash` function using the given context object. - * - * @static - * @memberOf _ - * @category Utilities - * @param {Object} [context=root] The context object. - * @returns {Function} Returns the `lodash` function. - */ - function runInContext(context) { - // Avoid issues with some ES3 environments that attempt to use values, named - // after built-in constructors like `Object`, for the creation of literals. - // ES5 clears this up by stating that literals must use built-in constructors. - // See http://es5.github.io/#x11.1.5. - context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; - - /** Native constructor references */ - var Array = context.Array, - Boolean = context.Boolean, - Date = context.Date, - Function = context.Function, - Math = context.Math, - Number = context.Number, - Object = context.Object, - RegExp = context.RegExp, - String = context.String, - TypeError = context.TypeError; - - /** - * Used for `Array` method references. - * - * Normally `Array.prototype` would suffice, however, using an array literal - * avoids issues in Narwhal. - */ - var arrayRef = []; - - /** Used for native method references */ - var objectProto = Object.prototype; - - /** Used to restore the original `_` reference in `noConflict` */ - var oldDash = context._; - - /** Used to resolve the internal [[Class]] of values */ - var toString = objectProto.toString; - - /** Used to detect if a method is native */ - var reNative = RegExp('^' + - String(toString) - .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') - .replace(/toString| for [^\]]+/g, '.*?') + '$' - ); - - /** Native method shortcuts */ - var ceil = Math.ceil, - clearTimeout = context.clearTimeout, - floor = Math.floor, - fnToString = Function.prototype.toString, - getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, - hasOwnProperty = objectProto.hasOwnProperty, - push = arrayRef.push, - setTimeout = context.setTimeout, - splice = arrayRef.splice, - unshift = arrayRef.unshift; - - /** Used to set meta data on functions */ - var defineProperty = (function() { - // IE 8 only accepts DOM elements - try { - var o = {}, - func = isNative(func = Object.defineProperty) && func, - result = func(o, o, o) && func; - } catch(e) { } - return result; - }()); - - /* Native method shortcuts for methods with the same name as other `lodash` methods */ - var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate, - nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray, - nativeIsFinite = context.isFinite, - nativeIsNaN = context.isNaN, - nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys, - nativeMax = Math.max, - nativeMin = Math.min, - nativeParseInt = context.parseInt, - nativeRandom = Math.random; - - /** Used to lookup a built-in constructor by [[Class]] */ - var ctorByClass = {}; - ctorByClass[arrayClass] = Array; - ctorByClass[boolClass] = Boolean; - ctorByClass[dateClass] = Date; - ctorByClass[funcClass] = Function; - ctorByClass[objectClass] = Object; - ctorByClass[numberClass] = Number; - ctorByClass[regexpClass] = RegExp; - ctorByClass[stringClass] = String; - - /*--------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps the given value to enable intuitive - * method chaining. - * - * In addition to Lo-Dash methods, wrappers also have the following `Array` methods: - * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, - * and `unshift` - * - * Chaining is supported in custom builds as long as the `value` method is - * implicitly or explicitly included in the build. - * - * The chainable wrapper functions are: - * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, - * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`, - * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, - * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, - * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, - * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, - * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, - * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, - * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`, - * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`, - * and `zip` - * - * The non-chainable wrapper functions are: - * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`, - * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`, - * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, - * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, - * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, - * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`, - * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`, - * `template`, `unescape`, `uniqueId`, and `value` - * - * The wrapper functions `first` and `last` return wrapped values when `n` is - * provided, otherwise they return unwrapped values. - * - * Explicit chaining can be enabled by using the `_.chain` method. - * - * @name _ - * @constructor - * @category Chaining - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns a `lodash` instance. - * @example - * - * var wrapped = _([1, 2, 3]); - * - * // returns an unwrapped value - * wrapped.reduce(function(sum, num) { - * return sum + num; - * }); - * // => 6 - * - * // returns a wrapped value - * var squares = wrapped.map(function(num) { - * return num * num; - * }); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor - return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__')) - ? value - : new lodashWrapper(value); - } - - /** - * A fast path for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap in a `lodash` instance. - * @param {boolean} chainAll A flag to enable chaining for all methods - * @returns {Object} Returns a `lodash` instance. - */ - function lodashWrapper(value, chainAll) { - this.__chain__ = !!chainAll; - this.__wrapped__ = value; - } - // ensure `new lodashWrapper` is an instance of `lodash` - lodashWrapper.prototype = lodash.prototype; - - /** - * An object used to flag environments features. - * - * @static - * @memberOf _ - * @type Object - */ - var support = lodash.support = {}; - - /** - * Detect if functions can be decompiled by `Function#toString` - * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). - * - * @memberOf _.support - * @type boolean - */ - support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext); - - /** - * Detect if `Function#name` is supported (all but IE). - * - * @memberOf _.support - * @type boolean - */ - support.funcNames = typeof Function.name == 'string'; - - /** - * By default, the template delimiters used by Lo-Dash are similar to those in - * embedded Ruby (ERB). Change the following template settings to use alternative - * delimiters. - * - * @static - * @memberOf _ - * @type Object - */ - lodash.templateSettings = { - - /** - * Used to detect `data` property values to be HTML-escaped. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'escape': /<%-([\s\S]+?)%>/g, - - /** - * Used to detect code to be evaluated. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'evaluate': /<%([\s\S]+?)%>/g, - - /** - * Used to detect `data` property values to inject. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'interpolate': reInterpolate, - - /** - * Used to reference the data object in the template text. - * - * @memberOf _.templateSettings - * @type string - */ - 'variable': '', - - /** - * Used to import variables into the compiled template. - * - * @memberOf _.templateSettings - * @type Object - */ - 'imports': { - - /** - * A reference to the `lodash` function. - * - * @memberOf _.templateSettings.imports - * @type Function - */ - '_': lodash - } - }; - - /*--------------------------------------------------------------------------*/ - - /** - * The base implementation of `_.bind` that creates the bound function and - * sets its meta data. - * - * @private - * @param {Array} bindData The bind data array. - * @returns {Function} Returns the new bound function. - */ - function baseBind(bindData) { - var func = bindData[0], - partialArgs = bindData[2], - thisArg = bindData[4]; - - function bound() { - // `Function#bind` spec - // http://es5.github.io/#x15.3.4.5 - if (partialArgs) { - // avoid `arguments` object deoptimizations by using `slice` instead - // of `Array.prototype.slice.call` and not assigning `arguments` to a - // variable as a ternary expression - var args = slice(partialArgs); - push.apply(args, arguments); - } - // mimic the constructor's `return` behavior - // http://es5.github.io/#x13.2.2 - if (this instanceof bound) { - // ensure `new bound` is an instance of `func` - var thisBinding = baseCreate(func.prototype), - result = func.apply(thisBinding, args || arguments); - return isObject(result) ? result : thisBinding; - } - return func.apply(thisArg, args || arguments); - } - setBindData(bound, bindData); - return bound; - } - - /** - * The base implementation of `_.clone` without argument juggling or support - * for `thisArg` binding. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} [isDeep=false] Specify a deep clone. - * @param {Function} [callback] The function to customize cloning values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates clones with source counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, isDeep, callback, stackA, stackB) { - if (callback) { - var result = callback(value); - if (typeof result != 'undefined') { - return result; - } - } - // inspect [[Class]] - var isObj = isObject(value); - if (isObj) { - var className = toString.call(value); - if (!cloneableClasses[className]) { - return value; - } - var ctor = ctorByClass[className]; - switch (className) { - case boolClass: - case dateClass: - return new ctor(+value); - - case numberClass: - case stringClass: - return new ctor(value); - - case regexpClass: - result = ctor(value.source, reFlags.exec(value)); - result.lastIndex = value.lastIndex; - return result; - } - } else { - return value; - } - var isArr = isArray(value); - if (isDeep) { - // check for circular references and return corresponding clone - var initedStack = !stackA; - stackA || (stackA = getArray()); - stackB || (stackB = getArray()); - - var length = stackA.length; - while (length--) { - if (stackA[length] == value) { - return stackB[length]; - } - } - result = isArr ? ctor(value.length) : {}; - } - else { - result = isArr ? slice(value) : assign({}, value); - } - // add array properties assigned by `RegExp#exec` - if (isArr) { - if (hasOwnProperty.call(value, 'index')) { - result.index = value.index; - } - if (hasOwnProperty.call(value, 'input')) { - result.input = value.input; - } - } - // exit for shallow clone - if (!isDeep) { - return result; - } - // add the source value to the stack of traversed objects - // and associate it with its clone - stackA.push(value); - stackB.push(result); - - // recursively populate clone (susceptible to call stack limits) - (isArr ? forEach : forOwn)(value, function(objValue, key) { - result[key] = baseClone(objValue, isDeep, callback, stackA, stackB); - }); - - if (initedStack) { - releaseArray(stackA); - releaseArray(stackB); - } - return result; - } - - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. - */ - function baseCreate(prototype, properties) { - return isObject(prototype) ? nativeCreate(prototype) : {}; - } - // fallback for browsers without `Object.create` - if (!nativeCreate) { - baseCreate = (function() { - function Object() {} - return function(prototype) { - if (isObject(prototype)) { - Object.prototype = prototype; - var result = new Object; - Object.prototype = null; - } - return result || context.Object(); - }; - }()); - } - - /** - * The base implementation of `_.createCallback` without support for creating - * "_.pluck" or "_.where" style callbacks. - * - * @private - * @param {*} [func=identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of the created callback. - * @param {number} [argCount] The number of arguments the callback accepts. - * @returns {Function} Returns a callback function. - */ - function baseCreateCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - // exit early for no `thisArg` or already bound by `Function#bind` - if (typeof thisArg == 'undefined' || !('prototype' in func)) { - return func; - } - var bindData = func.__bindData__; - if (typeof bindData == 'undefined') { - if (support.funcNames) { - bindData = !func.name; - } - bindData = bindData || !support.funcDecomp; - if (!bindData) { - var source = fnToString.call(func); - if (!support.funcNames) { - bindData = !reFuncName.test(source); - } - if (!bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = reThis.test(source); - setBindData(func, bindData); - } - } - } - // exit early if there are no `this` references or `func` is bound - if (bindData === false || (bindData !== true && bindData[1] & 1)) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 2: return function(a, b) { - return func.call(thisArg, a, b); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - } - return bind(func, thisArg); - } - - /** - * The base implementation of `createWrapper` that creates the wrapper and - * sets its meta data. - * - * @private - * @param {Array} bindData The bind data array. - * @returns {Function} Returns the new function. - */ - function baseCreateWrapper(bindData) { - var func = bindData[0], - bitmask = bindData[1], - partialArgs = bindData[2], - partialRightArgs = bindData[3], - thisArg = bindData[4], - arity = bindData[5]; - - var isBind = bitmask & 1, - isBindKey = bitmask & 2, - isCurry = bitmask & 4, - isCurryBound = bitmask & 8, - key = func; - - function bound() { - var thisBinding = isBind ? thisArg : this; - if (partialArgs) { - var args = slice(partialArgs); - push.apply(args, arguments); - } - if (partialRightArgs || isCurry) { - args || (args = slice(arguments)); - if (partialRightArgs) { - push.apply(args, partialRightArgs); - } - if (isCurry && args.length < arity) { - bitmask |= 16 & ~32; - return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); - } - } - args || (args = arguments); - if (isBindKey) { - func = thisBinding[key]; - } - if (this instanceof bound) { - thisBinding = baseCreate(func.prototype); - var result = func.apply(thisBinding, args); - return isObject(result) ? result : thisBinding; - } - return func.apply(thisBinding, args); - } - setBindData(bound, bindData); - return bound; - } - - /** - * The base implementation of `_.difference` that accepts a single array - * of values to exclude. - * - * @private - * @param {Array} array The array to process. - * @param {Array} [values] The array of values to exclude. - * @returns {Array} Returns a new array of filtered values. - */ - function baseDifference(array, values) { - var index = -1, - indexOf = getIndexOf(), - length = array ? array.length : 0, - isLarge = length >= largeArraySize && indexOf === baseIndexOf, - result = []; - - if (isLarge) { - var cache = createCache(values); - if (cache) { - indexOf = cacheIndexOf; - values = cache; - } else { - isLarge = false; - } - } - while (++index < length) { - var value = array[index]; - if (indexOf(values, value) < 0) { - result.push(value); - } - } - if (isLarge) { - releaseObject(values); - } - return result; - } - - /** - * The base implementation of `_.flatten` without support for callback - * shorthands or `thisArg` binding. - * - * @private - * @param {Array} array The array to flatten. - * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level. - * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects. - * @param {number} [fromIndex=0] The index to start from. - * @returns {Array} Returns a new flattened array. - */ - function baseFlatten(array, isShallow, isStrict, fromIndex) { - var index = (fromIndex || 0) - 1, - length = array ? array.length : 0, - result = []; - - while (++index < length) { - var value = array[index]; - - if (value && typeof value == 'object' && typeof value.length == 'number' - && (isArray(value) || isArguments(value))) { - // recursively flatten arrays (susceptible to call stack limits) - if (!isShallow) { - value = baseFlatten(value, isShallow, isStrict); - } - var valIndex = -1, - valLength = value.length, - resIndex = result.length; - - result.length += valLength; - while (++valIndex < valLength) { - result[resIndex++] = value[valIndex]; - } - } else if (!isStrict) { - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.isEqual`, without support for `thisArg` binding, - * that allows partial "_.where" style comparisons. - * - * @private - * @param {*} a The value to compare. - * @param {*} b The other value to compare. - * @param {Function} [callback] The function to customize comparing values. - * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons. - * @param {Array} [stackA=[]] Tracks traversed `a` objects. - * @param {Array} [stackB=[]] Tracks traversed `b` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(a, b, callback, isWhere, stackA, stackB) { - // used to indicate that when comparing objects, `a` has at least the properties of `b` - if (callback) { - var result = callback(a, b); - if (typeof result != 'undefined') { - return !!result; - } - } - // exit early for identical values - if (a === b) { - // treat `+0` vs. `-0` as not equal - return a !== 0 || (1 / a == 1 / b); - } - var type = typeof a, - otherType = typeof b; - - // exit early for unlike primitive values - if (a === a && - !(a && objectTypes[type]) && - !(b && objectTypes[otherType])) { - return false; - } - // exit early for `null` and `undefined` avoiding ES3's Function#call behavior - // http://es5.github.io/#x15.3.4.4 - if (a == null || b == null) { - return a === b; - } - // compare [[Class]] names - var className = toString.call(a), - otherClass = toString.call(b); - - if (className == argsClass) { - className = objectClass; - } - if (otherClass == argsClass) { - otherClass = objectClass; - } - if (className != otherClass) { - return false; - } - switch (className) { - case boolClass: - case dateClass: - // coerce dates and booleans to numbers, dates to milliseconds and booleans - // to `1` or `0` treating invalid dates coerced to `NaN` as not equal - return +a == +b; - - case numberClass: - // treat `NaN` vs. `NaN` as equal - return (a != +a) - ? b != +b - // but treat `+0` vs. `-0` as not equal - : (a == 0 ? (1 / a == 1 / b) : a == +b); - - case regexpClass: - case stringClass: - // coerce regexes to strings (http://es5.github.io/#x15.10.6.4) - // treat string primitives and their corresponding object instances as equal - return a == String(b); - } - var isArr = className == arrayClass; - if (!isArr) { - // unwrap any `lodash` wrapped values - var aWrapped = hasOwnProperty.call(a, '__wrapped__'), - bWrapped = hasOwnProperty.call(b, '__wrapped__'); - - if (aWrapped || bWrapped) { - return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB); - } - // exit for functions and DOM nodes - if (className != objectClass) { - return false; - } - // in older versions of Opera, `arguments` objects have `Array` constructors - var ctorA = a.constructor, - ctorB = b.constructor; - - // non `Object` object instances with different constructors are not equal - if (ctorA != ctorB && - !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && - ('constructor' in a && 'constructor' in b) - ) { - return false; - } - } - // assume cyclic structures are equal - // the algorithm for detecting cyclic structures is adapted from ES 5.1 - // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3) - var initedStack = !stackA; - stackA || (stackA = getArray()); - stackB || (stackB = getArray()); - - var length = stackA.length; - while (length--) { - if (stackA[length] == a) { - return stackB[length] == b; - } - } - var size = 0; - result = true; - - // add `a` and `b` to the stack of traversed objects - stackA.push(a); - stackB.push(b); - - // recursively compare objects and arrays (susceptible to call stack limits) - if (isArr) { - // compare lengths to determine if a deep comparison is necessary - length = a.length; - size = b.length; - result = size == length; - - if (result || isWhere) { - // deep compare the contents, ignoring non-numeric properties - while (size--) { - var index = length, - value = b[size]; - - if (isWhere) { - while (index--) { - if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { - break; - } - } - } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { - break; - } - } - } - } - else { - // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` - // which, in this case, is more costly - forIn(b, function(value, key, b) { - if (hasOwnProperty.call(b, key)) { - // count the number of properties. - size++; - // deep compare each property value. - return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); - } - }); - - if (result && !isWhere) { - // ensure both objects have the same number of properties - forIn(a, function(value, key, a) { - if (hasOwnProperty.call(a, key)) { - // `size` will be `-1` if `a` has more properties than `b` - return (result = --size > -1); - } - }); - } - } - stackA.pop(); - stackB.pop(); - - if (initedStack) { - releaseArray(stackA); - releaseArray(stackB); - } - return result; - } - - /** - * The base implementation of `_.merge` without argument juggling or support - * for `thisArg` binding. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} [callback] The function to customize merging properties. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - */ - function baseMerge(object, source, callback, stackA, stackB) { - (isArray(source) ? forEach : forOwn)(source, function(source, key) { - var found, - isArr, - result = source, - value = object[key]; - - if (source && ((isArr = isArray(source)) || isPlainObject(source))) { - // avoid merging previously merged cyclic sources - var stackLength = stackA.length; - while (stackLength--) { - if ((found = stackA[stackLength] == source)) { - value = stackB[stackLength]; - break; - } - } - if (!found) { - var isShallow; - if (callback) { - result = callback(value, source); - if ((isShallow = typeof result != 'undefined')) { - value = result; - } - } - if (!isShallow) { - value = isArr - ? (isArray(value) ? value : []) - : (isPlainObject(value) ? value : {}); - } - // add `source` and associated `value` to the stack of traversed objects - stackA.push(source); - stackB.push(value); - - // recursively merge objects and arrays (susceptible to call stack limits) - if (!isShallow) { - baseMerge(value, source, callback, stackA, stackB); - } - } - } - else { - if (callback) { - result = callback(value, source); - if (typeof result == 'undefined') { - result = source; - } - } - if (typeof result != 'undefined') { - value = result; - } - } - object[key] = value; - }); - } - - /** - * The base implementation of `_.random` without argument juggling or support - * for returning floating-point numbers. - * - * @private - * @param {number} min The minimum possible value. - * @param {number} max The maximum possible value. - * @returns {number} Returns a random number. - */ - function baseRandom(min, max) { - return min + floor(nativeRandom() * (max - min + 1)); - } - - /** - * The base implementation of `_.uniq` without support for callback shorthands - * or `thisArg` binding. - * - * @private - * @param {Array} array The array to process. - * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted. - * @param {Function} [callback] The function called per iteration. - * @returns {Array} Returns a duplicate-value-free array. - */ - function baseUniq(array, isSorted, callback) { - var index = -1, - indexOf = getIndexOf(), - length = array ? array.length : 0, - result = []; - - var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf, - seen = (callback || isLarge) ? getArray() : result; - - if (isLarge) { - var cache = createCache(seen); - indexOf = cacheIndexOf; - seen = cache; - } - while (++index < length) { - var value = array[index], - computed = callback ? callback(value, index, array) : value; - - if (isSorted - ? !index || seen[seen.length - 1] !== computed - : indexOf(seen, computed) < 0 - ) { - if (callback || isLarge) { - seen.push(computed); - } - result.push(value); - } - } - if (isLarge) { - releaseArray(seen.array); - releaseObject(seen); - } else if (callback) { - releaseArray(seen); - } - return result; - } - - /** - * Creates a function that aggregates a collection, creating an object composed - * of keys generated from the results of running each element of the collection - * through a callback. The given `setter` function sets the keys and values - * of the composed object. - * - * @private - * @param {Function} setter The setter function. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter) { - return function(collection, callback, thisArg) { - var result = {}; - callback = lodash.createCallback(callback, thisArg, 3); - - var index = -1, - length = collection ? collection.length : 0; - - if (typeof length == 'number') { - while (++index < length) { - var value = collection[index]; - setter(result, value, callback(value, index, collection), collection); - } - } else { - forOwn(collection, function(value, key, collection) { - setter(result, value, callback(value, key, collection), collection); - }); - } - return result; - }; - } - - /** - * Creates a function that, when called, either curries or invokes `func` - * with an optional `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of method flags to compose. - * The bitmask may be composed of the following flags: - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` - * 8 - `_.curry` (bound) - * 16 - `_.partial` - * 32 - `_.partialRight` - * @param {Array} [partialArgs] An array of arguments to prepend to those - * provided to the new function. - * @param {Array} [partialRightArgs] An array of arguments to append to those - * provided to the new function. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new function. - */ - function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { - var isBind = bitmask & 1, - isBindKey = bitmask & 2, - isCurry = bitmask & 4, - isCurryBound = bitmask & 8, - isPartial = bitmask & 16, - isPartialRight = bitmask & 32; - - if (!isBindKey && !isFunction(func)) { - throw new TypeError; - } - if (isPartial && !partialArgs.length) { - bitmask &= ~16; - isPartial = partialArgs = false; - } - if (isPartialRight && !partialRightArgs.length) { - bitmask &= ~32; - isPartialRight = partialRightArgs = false; - } - var bindData = func && func.__bindData__; - if (bindData && bindData !== true) { - // clone `bindData` - bindData = slice(bindData); - if (bindData[2]) { - bindData[2] = slice(bindData[2]); - } - if (bindData[3]) { - bindData[3] = slice(bindData[3]); - } - // set `thisBinding` is not previously bound - if (isBind && !(bindData[1] & 1)) { - bindData[4] = thisArg; - } - // set if previously bound but not currently (subsequent curried functions) - if (!isBind && bindData[1] & 1) { - bitmask |= 8; - } - // set curried arity if not yet set - if (isCurry && !(bindData[1] & 4)) { - bindData[5] = arity; - } - // append partial left arguments - if (isPartial) { - push.apply(bindData[2] || (bindData[2] = []), partialArgs); - } - // append partial right arguments - if (isPartialRight) { - unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs); - } - // merge flags - bindData[1] |= bitmask; - return createWrapper.apply(null, bindData); - } - // fast path for `_.bind` - var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper; - return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]); - } - - /** - * Used by `escape` to convert characters to HTML entities. - * - * @private - * @param {string} match The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeHtmlChar(match) { - return htmlEscapes[match]; - } - - /** - * Gets the appropriate "indexOf" function. If the `_.indexOf` method is - * customized, this method returns the custom method, otherwise it returns - * the `baseIndexOf` function. - * - * @private - * @returns {Function} Returns the "indexOf" function. - */ - function getIndexOf() { - var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result; - return result; - } - - /** - * Checks if `value` is a native function. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a native function, else `false`. - */ - function isNative(value) { - return typeof value == 'function' && reNative.test(value); - } - - /** - * Sets `this` binding data on a given function. - * - * @private - * @param {Function} func The function to set data on. - * @param {Array} value The data array to set. - */ - var setBindData = !defineProperty ? noop : function(func, value) { - descriptor.value = value; - defineProperty(func, '__bindData__', descriptor); - descriptor.value = null; - }; - - /** - * A fallback implementation of `isPlainObject` which checks if a given value - * is an object created by the `Object` constructor, assuming objects created - * by the `Object` constructor have no inherited enumerable properties and that - * there are no `Object.prototype` extensions. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - */ - function shimIsPlainObject(value) { - var ctor, - result; - - // avoid non Object objects, `arguments` objects, and DOM elements - if (!(value && toString.call(value) == objectClass) || - (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) { - return false; - } - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - forIn(value, function(value, key) { - result = key; - }); - return typeof result == 'undefined' || hasOwnProperty.call(value, result); - } - - /** - * Used by `unescape` to convert HTML entities to characters. - * - * @private - * @param {string} match The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - function unescapeHtmlChar(match) { - return htmlUnescapes[match]; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Checks if `value` is an `arguments` object. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`. - * @example - * - * (function() { return _.isArguments(arguments); })(1, 2, 3); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - function isArguments(value) { - return value && typeof value == 'object' && typeof value.length == 'number' && - toString.call(value) == argsClass || false; - } - - /** - * Checks if `value` is an array. - * - * @static - * @memberOf _ - * @type Function - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is an array, else `false`. - * @example - * - * (function() { return _.isArray(arguments); })(); - * // => false - * - * _.isArray([1, 2, 3]); - * // => true - */ - var isArray = nativeIsArray || function(value) { - return value && typeof value == 'object' && typeof value.length == 'number' && - toString.call(value) == arrayClass || false; - }; - - /** - * A fallback implementation of `Object.keys` which produces an array of the - * given object's own enumerable property names. - * - * @private - * @type Function - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property names. - */ - var shimKeys = function(object) { - var index, iterable = object, result = []; - if (!iterable) return result; - if (!(objectTypes[typeof object])) return result; - for (index in iterable) { - if (hasOwnProperty.call(iterable, index)) { - result.push(index); - } - } - return result - }; - - /** - * Creates an array composed of the own enumerable property names of an object. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property names. - * @example - * - * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); - * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) - */ - var keys = !nativeKeys ? shimKeys : function(object) { - if (!isObject(object)) { - return []; - } - return nativeKeys(object); - }; - - /** - * Used to convert characters to HTML entities: - * - * Though the `>` character is escaped for symmetry, characters like `>` and `/` - * don't require escaping in HTML and have no special meaning unless they're part - * of a tag or an unquoted attribute value. - * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact") - */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' - }; - - /** Used to convert HTML entities to characters */ - var htmlUnescapes = invert(htmlEscapes); - - /** Used to match HTML entities and HTML characters */ - var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'), - reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g'); - - /*--------------------------------------------------------------------------*/ - - /** - * Assigns own enumerable properties of source object(s) to the destination - * object. Subsequent sources will overwrite property assignments of previous - * sources. If a callback is provided it will be executed to produce the - * assigned values. The callback is bound to `thisArg` and invoked with two - * arguments; (objectValue, sourceValue). - * - * @static - * @memberOf _ - * @type Function - * @alias extend - * @category Objects - * @param {Object} object The destination object. - * @param {...Object} [source] The source objects. - * @param {Function} [callback] The function to customize assigning values. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns the destination object. - * @example - * - * _.assign({ 'name': 'fred' }, { 'employer': 'slate' }); - * // => { 'name': 'fred', 'employer': 'slate' } - * - * var defaults = _.partialRight(_.assign, function(a, b) { - * return typeof a == 'undefined' ? b : a; - * }); - * - * var object = { 'name': 'barney' }; - * defaults(object, { 'name': 'fred', 'employer': 'slate' }); - * // => { 'name': 'barney', 'employer': 'slate' } - */ - var assign = function(object, source, guard) { - var index, iterable = object, result = iterable; - if (!iterable) return result; - var args = arguments, - argsIndex = 0, - argsLength = typeof guard == 'number' ? 2 : args.length; - if (argsLength > 3 && typeof args[argsLength - 2] == 'function') { - var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2); - } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') { - callback = args[--argsLength]; - } - while (++argsIndex < argsLength) { - iterable = args[argsIndex]; - if (iterable && objectTypes[typeof iterable]) { - var ownIndex = -1, - ownProps = objectTypes[typeof iterable] && keys(iterable), - length = ownProps ? ownProps.length : 0; - - while (++ownIndex < length) { - index = ownProps[ownIndex]; - result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; - } - } - } - return result - }; - - /** - * Creates a clone of `value`. If `isDeep` is `true` nested objects will also - * be cloned, otherwise they will be assigned by reference. If a callback - * is provided it will be executed to produce the cloned values. If the - * callback returns `undefined` cloning will be handled by the method instead. - * The callback is bound to `thisArg` and invoked with one argument; (value). - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to clone. - * @param {boolean} [isDeep=false] Specify a deep clone. - * @param {Function} [callback] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the cloned value. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * var shallow = _.clone(characters); - * shallow[0] === characters[0]; - * // => true - * - * var deep = _.clone(characters, true); - * deep[0] === characters[0]; - * // => false - * - * _.mixin({ - * 'clone': _.partialRight(_.clone, function(value) { - * return _.isElement(value) ? value.cloneNode(false) : undefined; - * }) - * }); - * - * var clone = _.clone(document.body); - * clone.childNodes.length; - * // => 0 - */ - function clone(value, isDeep, callback, thisArg) { - // allows working with "Collections" methods without using their `index` - // and `collection` arguments for `isDeep` and `callback` - if (typeof isDeep != 'boolean' && isDeep != null) { - thisArg = callback; - callback = isDeep; - isDeep = false; - } - return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); - } - - /** - * Creates a deep clone of `value`. If a callback is provided it will be - * executed to produce the cloned values. If the callback returns `undefined` - * cloning will be handled by the method instead. The callback is bound to - * `thisArg` and invoked with one argument; (value). - * - * Note: This method is loosely based on the structured clone algorithm. Functions - * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and - * objects created by constructors other than `Object` are cloned to plain `Object` objects. - * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to deep clone. - * @param {Function} [callback] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the deep cloned value. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * var deep = _.cloneDeep(characters); - * deep[0] === characters[0]; - * // => false - * - * var view = { - * 'label': 'docs', - * 'node': element - * }; - * - * var clone = _.cloneDeep(view, function(value) { - * return _.isElement(value) ? value.cloneNode(true) : undefined; - * }); - * - * clone.node == view.node; - * // => false - */ - function cloneDeep(value, callback, thisArg) { - return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); - } - - /** - * Creates an object that inherits from the given `prototype` object. If a - * `properties` object is provided its own enumerable properties are assigned - * to the created object. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties) { - var result = baseCreate(prototype); - return properties ? assign(result, properties) : result; - } - - /** - * Assigns own enumerable properties of source object(s) to the destination - * object for all destination properties that resolve to `undefined`. Once a - * property is set, additional defaults of the same property will be ignored. - * - * @static - * @memberOf _ - * @type Function - * @category Objects - * @param {Object} object The destination object. - * @param {...Object} [source] The source objects. - * @param- {Object} [guard] Allows working with `_.reduce` without using its - * `key` and `object` arguments as sources. - * @returns {Object} Returns the destination object. - * @example - * - * var object = { 'name': 'barney' }; - * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); - * // => { 'name': 'barney', 'employer': 'slate' } - */ - var defaults = function(object, source, guard) { - var index, iterable = object, result = iterable; - if (!iterable) return result; - var args = arguments, - argsIndex = 0, - argsLength = typeof guard == 'number' ? 2 : args.length; - while (++argsIndex < argsLength) { - iterable = args[argsIndex]; - if (iterable && objectTypes[typeof iterable]) { - var ownIndex = -1, - ownProps = objectTypes[typeof iterable] && keys(iterable), - length = ownProps ? ownProps.length : 0; - - while (++ownIndex < length) { - index = ownProps[ownIndex]; - if (typeof result[index] == 'undefined') result[index] = iterable[index]; - } - } - } - return result - }; - - /** - * This method is like `_.findIndex` except that it returns the key of the - * first element that passes the callback check, instead of the element itself. - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to search. - * @param {Function|Object|string} [callback=identity] The function called per - * iteration. If a property name or object is provided it will be used to - * create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {string|undefined} Returns the key of the found element, else `undefined`. - * @example - * - * var characters = { - * 'barney': { 'age': 36, 'blocked': false }, - * 'fred': { 'age': 40, 'blocked': true }, - * 'pebbles': { 'age': 1, 'blocked': false } - * }; - * - * _.findKey(characters, function(chr) { - * return chr.age < 40; - * }); - * // => 'barney' (property order is not guaranteed across environments) - * - * // using "_.where" callback shorthand - * _.findKey(characters, { 'age': 1 }); - * // => 'pebbles' - * - * // using "_.pluck" callback shorthand - * _.findKey(characters, 'blocked'); - * // => 'fred' - */ - function findKey(object, callback, thisArg) { - var result; - callback = lodash.createCallback(callback, thisArg, 3); - forOwn(object, function(value, key, object) { - if (callback(value, key, object)) { - result = key; - return false; - } - }); - return result; - } - - /** - * This method is like `_.findKey` except that it iterates over elements - * of a `collection` in the opposite order. - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to search. - * @param {Function|Object|string} [callback=identity] The function called per - * iteration. If a property name or object is provided it will be used to - * create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {string|undefined} Returns the key of the found element, else `undefined`. - * @example - * - * var characters = { - * 'barney': { 'age': 36, 'blocked': true }, - * 'fred': { 'age': 40, 'blocked': false }, - * 'pebbles': { 'age': 1, 'blocked': true } - * }; - * - * _.findLastKey(characters, function(chr) { - * return chr.age < 40; - * }); - * // => returns `pebbles`, assuming `_.findKey` returns `barney` - * - * // using "_.where" callback shorthand - * _.findLastKey(characters, { 'age': 40 }); - * // => 'fred' - * - * // using "_.pluck" callback shorthand - * _.findLastKey(characters, 'blocked'); - * // => 'pebbles' - */ - function findLastKey(object, callback, thisArg) { - var result; - callback = lodash.createCallback(callback, thisArg, 3); - forOwnRight(object, function(value, key, object) { - if (callback(value, key, object)) { - result = key; - return false; - } - }); - return result; - } - - /** - * Iterates over own and inherited enumerable properties of an object, - * executing the callback for each property. The callback is bound to `thisArg` - * and invoked with three arguments; (value, key, object). Callbacks may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @type Function - * @category Objects - * @param {Object} object The object to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns `object`. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * Shape.prototype.move = function(x, y) { - * this.x += x; - * this.y += y; - * }; - * - * _.forIn(new Shape, function(value, key) { - * console.log(key); - * }); - * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments) - */ - var forIn = function(collection, callback, thisArg) { - var index, iterable = collection, result = iterable; - if (!iterable) return result; - if (!objectTypes[typeof iterable]) return result; - callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); - for (index in iterable) { - if (callback(iterable[index], index, collection) === false) return result; - } - return result - }; - - /** - * This method is like `_.forIn` except that it iterates over elements - * of a `collection` in the opposite order. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns `object`. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * Shape.prototype.move = function(x, y) { - * this.x += x; - * this.y += y; - * }; - * - * _.forInRight(new Shape, function(value, key) { - * console.log(key); - * }); - * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move' - */ - function forInRight(object, callback, thisArg) { - var pairs = []; - - forIn(object, function(value, key) { - pairs.push(key, value); - }); - - var length = pairs.length; - callback = baseCreateCallback(callback, thisArg, 3); - while (length--) { - if (callback(pairs[length--], pairs[length], object) === false) { - break; - } - } - return object; - } - - /** - * Iterates over own enumerable properties of an object, executing the callback - * for each property. The callback is bound to `thisArg` and invoked with three - * arguments; (value, key, object). Callbacks may exit iteration early by - * explicitly returning `false`. - * - * @static - * @memberOf _ - * @type Function - * @category Objects - * @param {Object} object The object to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns `object`. - * @example - * - * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { - * console.log(key); - * }); - * // => logs '0', '1', and 'length' (property order is not guaranteed across environments) - */ - var forOwn = function(collection, callback, thisArg) { - var index, iterable = collection, result = iterable; - if (!iterable) return result; - if (!objectTypes[typeof iterable]) return result; - callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); - var ownIndex = -1, - ownProps = objectTypes[typeof iterable] && keys(iterable), - length = ownProps ? ownProps.length : 0; - - while (++ownIndex < length) { - index = ownProps[ownIndex]; - if (callback(iterable[index], index, collection) === false) return result; - } - return result - }; - - /** - * This method is like `_.forOwn` except that it iterates over elements - * of a `collection` in the opposite order. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns `object`. - * @example - * - * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { - * console.log(key); - * }); - * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length' - */ - function forOwnRight(object, callback, thisArg) { - var props = keys(object), - length = props.length; - - callback = baseCreateCallback(callback, thisArg, 3); - while (length--) { - var key = props[length]; - if (callback(object[key], key, object) === false) { - break; - } - } - return object; - } - - /** - * Creates a sorted array of property names of all enumerable properties, - * own and inherited, of `object` that have function values. - * - * @static - * @memberOf _ - * @alias methods - * @category Objects - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property names that have function values. - * @example - * - * _.functions(_); - * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] - */ - function functions(object) { - var result = []; - forIn(object, function(value, key) { - if (isFunction(value)) { - result.push(key); - } - }); - return result.sort(); - } - - /** - * Checks if the specified property name exists as a direct property of `object`, - * instead of an inherited property. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to inspect. - * @param {string} key The name of the property to check. - * @returns {boolean} Returns `true` if key is a direct property, else `false`. - * @example - * - * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); - * // => true - */ - function has(object, key) { - return object ? hasOwnProperty.call(object, key) : false; - } - - /** - * Creates an object composed of the inverted keys and values of the given object. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to invert. - * @returns {Object} Returns the created inverted object. - * @example - * - * _.invert({ 'first': 'fred', 'second': 'barney' }); - * // => { 'fred': 'first', 'barney': 'second' } - */ - function invert(object) { - var index = -1, - props = keys(object), - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index]; - result[object[key]] = key; - } - return result; - } - - /** - * Checks if `value` is a boolean value. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`. - * @example - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || - value && typeof value == 'object' && toString.call(value) == boolClass || false; - } - - /** - * Checks if `value` is a date. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a date, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - */ - function isDate(value) { - return value && typeof value == 'object' && toString.call(value) == dateClass || false; - } - - /** - * Checks if `value` is a DOM element. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - */ - function isElement(value) { - return value && value.nodeType === 1 || false; - } - - /** - * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a - * length of `0` and objects with no own enumerable properties are considered - * "empty". - * - * @static - * @memberOf _ - * @category Objects - * @param {Array|Object|string} value The value to inspect. - * @returns {boolean} Returns `true` if the `value` is empty, else `false`. - * @example - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({}); - * // => true - * - * _.isEmpty(''); - * // => true - */ - function isEmpty(value) { - var result = true; - if (!value) { - return result; - } - var className = toString.call(value), - length = value.length; - - if ((className == arrayClass || className == stringClass || className == argsClass ) || - (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { - return !length; - } - forOwn(value, function() { - return (result = false); - }); - return result; - } - - /** - * Performs a deep comparison between two values to determine if they are - * equivalent to each other. If a callback is provided it will be executed - * to compare values. If the callback returns `undefined` comparisons will - * be handled by the method instead. The callback is bound to `thisArg` and - * invoked with two arguments; (a, b). - * - * @static - * @memberOf _ - * @category Objects - * @param {*} a The value to compare. - * @param {*} b The other value to compare. - * @param {Function} [callback] The function to customize comparing values. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'name': 'fred' }; - * var copy = { 'name': 'fred' }; - * - * object == copy; - * // => false - * - * _.isEqual(object, copy); - * // => true - * - * var words = ['hello', 'goodbye']; - * var otherWords = ['hi', 'goodbye']; - * - * _.isEqual(words, otherWords, function(a, b) { - * var reGreet = /^(?:hello|hi)$/i, - * aGreet = _.isString(a) && reGreet.test(a), - * bGreet = _.isString(b) && reGreet.test(b); - * - * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined; - * }); - * // => true - */ - function isEqual(a, b, callback, thisArg) { - return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2)); - } - - /** - * Checks if `value` is, or can be coerced to, a finite number. - * - * Note: This is not the same as native `isFinite` which will return true for - * booleans and empty strings. See http://es5.github.io/#x15.1.2.5. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is finite, else `false`. - * @example - * - * _.isFinite(-101); - * // => true - * - * _.isFinite('10'); - * // => true - * - * _.isFinite(true); - * // => false - * - * _.isFinite(''); - * // => false - * - * _.isFinite(Infinity); - * // => false - */ - function isFinite(value) { - return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); - } - - /** - * Checks if `value` is a function. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - */ - function isFunction(value) { - return typeof value == 'function'; - } - - /** - * Checks if `value` is the language type of Object. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ - function isObject(value) { - // check if the value is the ECMAScript language type of Object - // http://es5.github.io/#x8 - // and avoid a V8 bug - // http://code.google.com/p/v8/issues/detail?id=2291 - return !!(value && objectTypes[typeof value]); - } - - /** - * Checks if `value` is `NaN`. - * - * Note: This is not the same as native `isNaN` which will return `true` for - * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // `NaN` as a primitive is the only value that is not equal to itself - // (perform the [[Class]] check first to avoid errors with some host objects in IE) - return isNumber(value) && value != +value; - } - - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(undefined); - * // => false - */ - function isNull(value) { - return value === null; - } - - /** - * Checks if `value` is a number. - * - * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a number, else `false`. - * @example - * - * _.isNumber(8.4 * 5); - * // => true - */ - function isNumber(value) { - return typeof value == 'number' || - value && typeof value == 'object' && toString.call(value) == numberClass || false; - } - - /** - * Checks if `value` is an object created by the `Object` constructor. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * _.isPlainObject(new Shape); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - */ - var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { - if (!(value && toString.call(value) == objectClass)) { - return false; - } - var valueOf = value.valueOf, - objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); - - return objProto - ? (value == objProto || getPrototypeOf(value) == objProto) - : shimIsPlainObject(value); - }; - - /** - * Checks if `value` is a regular expression. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`. - * @example - * - * _.isRegExp(/fred/); - * // => true - */ - function isRegExp(value) { - return value && typeof value == 'object' && toString.call(value) == regexpClass || false; - } - - /** - * Checks if `value` is a string. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a string, else `false`. - * @example - * - * _.isString('fred'); - * // => true - */ - function isString(value) { - return typeof value == 'string' || - value && typeof value == 'object' && toString.call(value) == stringClass || false; - } - - /** - * Checks if `value` is `undefined`. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - */ - function isUndefined(value) { - return typeof value == 'undefined'; - } - - /** - * Creates an object with the same keys as `object` and values generated by - * running each own enumerable property of `object` through the callback. - * The callback is bound to `thisArg` and invoked with three arguments; - * (value, key, object). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a new object with values of the results of each `callback` execution. - * @example - * - * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; }); - * // => { 'a': 3, 'b': 6, 'c': 9 } - * - * var characters = { - * 'fred': { 'name': 'fred', 'age': 40 }, - * 'pebbles': { 'name': 'pebbles', 'age': 1 } - * }; - * - * // using "_.pluck" callback shorthand - * _.mapValues(characters, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } - */ - function mapValues(object, callback, thisArg) { - var result = {}; - callback = lodash.createCallback(callback, thisArg, 3); - - forOwn(object, function(value, key, object) { - result[key] = callback(value, key, object); - }); - return result; - } - - /** - * Recursively merges own enumerable properties of the source object(s), that - * don't resolve to `undefined` into the destination object. Subsequent sources - * will overwrite property assignments of previous sources. If a callback is - * provided it will be executed to produce the merged values of the destination - * and source properties. If the callback returns `undefined` merging will - * be handled by the method instead. The callback is bound to `thisArg` and - * invoked with two arguments; (objectValue, sourceValue). - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The destination object. - * @param {...Object} [source] The source objects. - * @param {Function} [callback] The function to customize merging properties. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns the destination object. - * @example - * - * var names = { - * 'characters': [ - * { 'name': 'barney' }, - * { 'name': 'fred' } - * ] - * }; - * - * var ages = { - * 'characters': [ - * { 'age': 36 }, - * { 'age': 40 } - * ] - * }; - * - * _.merge(names, ages); - * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] } - * - * var food = { - * 'fruits': ['apple'], - * 'vegetables': ['beet'] - * }; - * - * var otherFood = { - * 'fruits': ['banana'], - * 'vegetables': ['carrot'] - * }; - * - * _.merge(food, otherFood, function(a, b) { - * return _.isArray(a) ? a.concat(b) : undefined; - * }); - * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] } - */ - function merge(object) { - var args = arguments, - length = 2; - - if (!isObject(object)) { - return object; - } - // allows working with `_.reduce` and `_.reduceRight` without using - // their `index` and `collection` arguments - if (typeof args[2] != 'number') { - length = args.length; - } - if (length > 3 && typeof args[length - 2] == 'function') { - var callback = baseCreateCallback(args[--length - 1], args[length--], 2); - } else if (length > 2 && typeof args[length - 1] == 'function') { - callback = args[--length]; - } - var sources = slice(arguments, 1, length), - index = -1, - stackA = getArray(), - stackB = getArray(); - - while (++index < length) { - baseMerge(object, sources[index], callback, stackA, stackB); - } - releaseArray(stackA); - releaseArray(stackB); - return object; - } - - /** - * Creates a shallow clone of `object` excluding the specified properties. - * Property names may be specified as individual arguments or as arrays of - * property names. If a callback is provided it will be executed for each - * property of `object` omitting the properties the callback returns truey - * for. The callback is bound to `thisArg` and invoked with three arguments; - * (value, key, object). - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The source object. - * @param {Function|...string|string[]} [callback] The properties to omit or the - * function called per iteration. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns an object without the omitted properties. - * @example - * - * _.omit({ 'name': 'fred', 'age': 40 }, 'age'); - * // => { 'name': 'fred' } - * - * _.omit({ 'name': 'fred', 'age': 40 }, function(value) { - * return typeof value == 'number'; - * }); - * // => { 'name': 'fred' } - */ - function omit(object, callback, thisArg) { - var result = {}; - if (typeof callback != 'function') { - var props = []; - forIn(object, function(value, key) { - props.push(key); - }); - props = baseDifference(props, baseFlatten(arguments, true, false, 1)); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - result[key] = object[key]; - } - } else { - callback = lodash.createCallback(callback, thisArg, 3); - forIn(object, function(value, key, object) { - if (!callback(value, key, object)) { - result[key] = value; - } - }); - } - return result; - } - - /** - * Creates a two dimensional array of an object's key-value pairs, - * i.e. `[[key1, value1], [key2, value2]]`. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to inspect. - * @returns {Array} Returns new array of key-value pairs. - * @example - * - * _.pairs({ 'barney': 36, 'fred': 40 }); - * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments) - */ - function pairs(object) { - var index = -1, - props = keys(object), - length = props.length, - result = Array(length); - - while (++index < length) { - var key = props[index]; - result[index] = [key, object[key]]; - } - return result; - } - - /** - * Creates a shallow clone of `object` composed of the specified properties. - * Property names may be specified as individual arguments or as arrays of - * property names. If a callback is provided it will be executed for each - * property of `object` picking the properties the callback returns truey - * for. The callback is bound to `thisArg` and invoked with three arguments; - * (value, key, object). - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The source object. - * @param {Function|...string|string[]} [callback] The function called per - * iteration or property names to pick, specified as individual property - * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns an object composed of the picked properties. - * @example - * - * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name'); - * // => { 'name': 'fred' } - * - * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) { - * return key.charAt(0) != '_'; - * }); - * // => { 'name': 'fred' } - */ - function pick(object, callback, thisArg) { - var result = {}; - if (typeof callback != 'function') { - var index = -1, - props = baseFlatten(arguments, true, false, 1), - length = isObject(object) ? props.length : 0; - - while (++index < length) { - var key = props[index]; - if (key in object) { - result[key] = object[key]; - } - } - } else { - callback = lodash.createCallback(callback, thisArg, 3); - forIn(object, function(value, key, object) { - if (callback(value, key, object)) { - result[key] = value; - } - }); - } - return result; - } - - /** - * An alternative to `_.reduce` this method transforms `object` to a new - * `accumulator` object which is the result of running each of its own - * enumerable properties through a callback, with each callback execution - * potentially mutating the `accumulator` object. The callback is bound to - * `thisArg` and invoked with four arguments; (accumulator, value, key, object). - * Callbacks may exit iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Objects - * @param {Array|Object} object The object to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [accumulator] The custom accumulator value. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the accumulated value. - * @example - * - * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { - * num *= num; - * if (num % 2) { - * return result.push(num) < 3; - * } - * }); - * // => [1, 9, 25] - * - * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { - * result[key] = num * 3; - * }); - * // => { 'a': 3, 'b': 6, 'c': 9 } - */ - function transform(object, callback, accumulator, thisArg) { - var isArr = isArray(object); - if (accumulator == null) { - if (isArr) { - accumulator = []; - } else { - var ctor = object && object.constructor, - proto = ctor && ctor.prototype; - - accumulator = baseCreate(proto); - } - } - if (callback) { - callback = lodash.createCallback(callback, thisArg, 4); - (isArr ? forEach : forOwn)(object, function(value, index, object) { - return callback(accumulator, value, index, object); - }); - } - return accumulator; - } - - /** - * Creates an array composed of the own enumerable property values of `object`. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property values. - * @example - * - * _.values({ 'one': 1, 'two': 2, 'three': 3 }); - * // => [1, 2, 3] (property order is not guaranteed across environments) - */ - function values(object) { - var index = -1, - props = keys(object), - length = props.length, - result = Array(length); - - while (++index < length) { - result[index] = object[props[index]]; - } - return result; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Creates an array of elements from the specified indexes, or keys, of the - * `collection`. Indexes may be specified as individual arguments or as arrays - * of indexes. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(number|number[]|string|string[])} [index] The indexes of `collection` - * to retrieve, specified as individual indexes or arrays of indexes. - * @returns {Array} Returns a new array of elements corresponding to the - * provided indexes. - * @example - * - * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); - * // => ['a', 'c', 'e'] - * - * _.at(['fred', 'barney', 'pebbles'], 0, 2); - * // => ['fred', 'pebbles'] - */ - function at(collection) { - var args = arguments, - index = -1, - props = baseFlatten(args, true, false, 1), - length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length, - result = Array(length); - - while(++index < length) { - result[index] = collection[props[index]]; - } - return result; - } - - /** - * Checks if a given value is present in a collection using strict equality - * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the - * offset from the end of the collection. - * - * @static - * @memberOf _ - * @alias include - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {*} target The value to check for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {boolean} Returns `true` if the `target` element is found, else `false`. - * @example - * - * _.contains([1, 2, 3], 1); - * // => true - * - * _.contains([1, 2, 3], 1, 2); - * // => false - * - * _.contains({ 'name': 'fred', 'age': 40 }, 'fred'); - * // => true - * - * _.contains('pebbles', 'eb'); - * // => true - */ - function contains(collection, target, fromIndex) { - var index = -1, - indexOf = getIndexOf(), - length = collection ? collection.length : 0, - result = false; - - fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; - if (isArray(collection)) { - result = indexOf(collection, target, fromIndex) > -1; - } else if (typeof length == 'number') { - result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1; - } else { - forOwn(collection, function(value) { - if (++index >= fromIndex) { - return !(result = value === target); - } - }); - } - return result; - } - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through the callback. The corresponding value - * of each key is the number of times the key was returned by the callback. - * The callback is bound to `thisArg` and invoked with three arguments; - * (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); - * // => { '4': 1, '6': 2 } - * - * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); - * // => { '4': 1, '6': 2 } - * - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function(result, value, key) { - (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); - }); - - /** - * Checks if the given callback returns truey value for **all** elements of - * a collection. The callback is bound to `thisArg` and invoked with three - * arguments; (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias all - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {boolean} Returns `true` if all elements passed the callback check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes']); - * // => false - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * // using "_.pluck" callback shorthand - * _.every(characters, 'age'); - * // => true - * - * // using "_.where" callback shorthand - * _.every(characters, { 'age': 36 }); - * // => false - */ - function every(collection, callback, thisArg) { - var result = true; - callback = lodash.createCallback(callback, thisArg, 3); - - var index = -1, - length = collection ? collection.length : 0; - - if (typeof length == 'number') { - while (++index < length) { - if (!(result = !!callback(collection[index], index, collection))) { - break; - } - } - } else { - forOwn(collection, function(value, index, collection) { - return (result = !!callback(value, index, collection)); - }); - } - return result; - } - - /** - * Iterates over elements of a collection, returning an array of all elements - * the callback returns truey for. The callback is bound to `thisArg` and - * invoked with three arguments; (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias select - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a new array of elements that passed the callback check. - * @example - * - * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); - * // => [2, 4, 6] - * - * var characters = [ - * { 'name': 'barney', 'age': 36, 'blocked': false }, - * { 'name': 'fred', 'age': 40, 'blocked': true } - * ]; - * - * // using "_.pluck" callback shorthand - * _.filter(characters, 'blocked'); - * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] - * - * // using "_.where" callback shorthand - * _.filter(characters, { 'age': 36 }); - * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] - */ - function filter(collection, callback, thisArg) { - var result = []; - callback = lodash.createCallback(callback, thisArg, 3); - - var index = -1, - length = collection ? collection.length : 0; - - if (typeof length == 'number') { - while (++index < length) { - var value = collection[index]; - if (callback(value, index, collection)) { - result.push(value); - } - } - } else { - forOwn(collection, function(value, index, collection) { - if (callback(value, index, collection)) { - result.push(value); - } - }); - } - return result; - } - - /** - * Iterates over elements of a collection, returning the first element that - * the callback returns truey for. The callback is bound to `thisArg` and - * invoked with three arguments; (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias detect, findWhere - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the found element, else `undefined`. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36, 'blocked': false }, - * { 'name': 'fred', 'age': 40, 'blocked': true }, - * { 'name': 'pebbles', 'age': 1, 'blocked': false } - * ]; - * - * _.find(characters, function(chr) { - * return chr.age < 40; - * }); - * // => { 'name': 'barney', 'age': 36, 'blocked': false } - * - * // using "_.where" callback shorthand - * _.find(characters, { 'age': 1 }); - * // => { 'name': 'pebbles', 'age': 1, 'blocked': false } - * - * // using "_.pluck" callback shorthand - * _.find(characters, 'blocked'); - * // => { 'name': 'fred', 'age': 40, 'blocked': true } - */ - function find(collection, callback, thisArg) { - callback = lodash.createCallback(callback, thisArg, 3); - - var index = -1, - length = collection ? collection.length : 0; - - if (typeof length == 'number') { - while (++index < length) { - var value = collection[index]; - if (callback(value, index, collection)) { - return value; - } - } - } else { - var result; - forOwn(collection, function(value, index, collection) { - if (callback(value, index, collection)) { - result = value; - return false; - } - }); - return result; - } - } - - /** - * This method is like `_.find` except that it iterates over elements - * of a `collection` from right to left. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the found element, else `undefined`. - * @example - * - * _.findLast([1, 2, 3, 4], function(num) { - * return num % 2 == 1; - * }); - * // => 3 - */ - function findLast(collection, callback, thisArg) { - var result; - callback = lodash.createCallback(callback, thisArg, 3); - forEachRight(collection, function(value, index, collection) { - if (callback(value, index, collection)) { - result = value; - return false; - } - }); - return result; - } - - /** - * Iterates over elements of a collection, executing the callback for each - * element. The callback is bound to `thisArg` and invoked with three arguments; - * (value, index|key, collection). Callbacks may exit iteration early by - * explicitly returning `false`. - * - * Note: As with other "Collections" methods, objects with a `length` property - * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` - * may be used for object iteration. - * - * @static - * @memberOf _ - * @alias each - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(','); - * // => logs each number and returns '1,2,3' - * - * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); }); - * // => logs each number and returns the object (property order is not guaranteed across environments) - */ - function forEach(collection, callback, thisArg) { - var index = -1, - length = collection ? collection.length : 0; - - callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); - if (typeof length == 'number') { - while (++index < length) { - if (callback(collection[index], index, collection) === false) { - break; - } - } - } else { - forOwn(collection, callback); - } - return collection; - } - - /** - * This method is like `_.forEach` except that it iterates over elements - * of a `collection` from right to left. - * - * @static - * @memberOf _ - * @alias eachRight - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(','); - * // => logs each number from right to left and returns '3,2,1' - */ - function forEachRight(collection, callback, thisArg) { - var length = collection ? collection.length : 0; - callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); - if (typeof length == 'number') { - while (length--) { - if (callback(collection[length], length, collection) === false) { - break; - } - } - } else { - var props = keys(collection); - length = props.length; - forOwn(collection, function(value, key, collection) { - key = props ? props[--length] : --length; - return callback(collection[key], key, collection); - }); - } - return collection; - } - - /** - * Creates an object composed of keys generated from the results of running - * each element of a collection through the callback. The corresponding value - * of each key is an array of the elements responsible for generating the key. - * The callback is bound to `thisArg` and invoked with three arguments; - * (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false` - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * // using "_.pluck" callback shorthand - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); - }); - - /** - * Creates an object composed of keys generated from the results of running - * each element of the collection through the given callback. The corresponding - * value of each key is the last element responsible for generating the key. - * The callback is bound to `thisArg` and invoked with three arguments; - * (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var keys = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.indexBy(keys, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - */ - var indexBy = createAggregator(function(result, value, key) { - result[key] = value; - }); - - /** - * Invokes the method named by `methodName` on each element in the `collection` - * returning an array of the results of each invoked method. Additional arguments - * will be provided to each invoked method. If `methodName` is a function it - * will be invoked for, and `this` bound to, each element in the `collection`. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|string} methodName The name of the method to invoke or - * the function invoked per iteration. - * @param {...*} [arg] Arguments to invoke the method with. - * @returns {Array} Returns a new array of the results of each invoked method. - * @example - * - * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invoke([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - function invoke(collection, methodName) { - var args = slice(arguments, 2), - index = -1, - isFunc = typeof methodName == 'function', - length = collection ? collection.length : 0, - result = Array(typeof length == 'number' ? length : 0); - - forEach(collection, function(value) { - result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args); - }); - return result; - } - - /** - * Creates an array of values by running each element in the collection - * through the callback. The callback is bound to `thisArg` and invoked with - * three arguments; (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias collect - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a new array of the results of each `callback` execution. - * @example - * - * _.map([1, 2, 3], function(num) { return num * 3; }); - * // => [3, 6, 9] - * - * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); - * // => [3, 6, 9] (property order is not guaranteed across environments) - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * // using "_.pluck" callback shorthand - * _.map(characters, 'name'); - * // => ['barney', 'fred'] - */ - function map(collection, callback, thisArg) { - var index = -1, - length = collection ? collection.length : 0; - - callback = lodash.createCallback(callback, thisArg, 3); - if (typeof length == 'number') { - var result = Array(length); - while (++index < length) { - result[index] = callback(collection[index], index, collection); - } - } else { - result = []; - forOwn(collection, function(value, key, collection) { - result[++index] = callback(value, key, collection); - }); - } - return result; - } - - /** - * Retrieves the maximum value of a collection. If the collection is empty or - * falsey `-Infinity` is returned. If a callback is provided it will be executed - * for each value in the collection to generate the criterion by which the value - * is ranked. The callback is bound to `thisArg` and invoked with three - * arguments; (value, index, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the maximum value. - * @example - * - * _.max([4, 2, 8, 6]); - * // => 8 - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * _.max(characters, function(chr) { return chr.age; }); - * // => { 'name': 'fred', 'age': 40 }; - * - * // using "_.pluck" callback shorthand - * _.max(characters, 'age'); - * // => { 'name': 'fred', 'age': 40 }; - */ - function max(collection, callback, thisArg) { - var computed = -Infinity, - result = computed; - - // allows working with functions like `_.map` without using - // their `index` argument as a callback - if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { - callback = null; - } - if (callback == null && isArray(collection)) { - var index = -1, - length = collection.length; - - while (++index < length) { - var value = collection[index]; - if (value > result) { - result = value; - } - } - } else { - callback = (callback == null && isString(collection)) - ? charAtCallback - : lodash.createCallback(callback, thisArg, 3); - - forEach(collection, function(value, index, collection) { - var current = callback(value, index, collection); - if (current > computed) { - computed = current; - result = value; - } - }); - } - return result; - } - - /** - * Retrieves the minimum value of a collection. If the collection is empty or - * falsey `Infinity` is returned. If a callback is provided it will be executed - * for each value in the collection to generate the criterion by which the value - * is ranked. The callback is bound to `thisArg` and invoked with three - * arguments; (value, index, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the minimum value. - * @example - * - * _.min([4, 2, 8, 6]); - * // => 2 - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * _.min(characters, function(chr) { return chr.age; }); - * // => { 'name': 'barney', 'age': 36 }; - * - * // using "_.pluck" callback shorthand - * _.min(characters, 'age'); - * // => { 'name': 'barney', 'age': 36 }; - */ - function min(collection, callback, thisArg) { - var computed = Infinity, - result = computed; - - // allows working with functions like `_.map` without using - // their `index` argument as a callback - if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { - callback = null; - } - if (callback == null && isArray(collection)) { - var index = -1, - length = collection.length; - - while (++index < length) { - var value = collection[index]; - if (value < result) { - result = value; - } - } - } else { - callback = (callback == null && isString(collection)) - ? charAtCallback - : lodash.createCallback(callback, thisArg, 3); - - forEach(collection, function(value, index, collection) { - var current = callback(value, index, collection); - if (current < computed) { - computed = current; - result = value; - } - }); - } - return result; - } - - /** - * Retrieves the value of a specified property from all elements in the collection. - * - * @static - * @memberOf _ - * @type Function - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {string} property The name of the property to pluck. - * @returns {Array} Returns a new array of property values. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * _.pluck(characters, 'name'); - * // => ['barney', 'fred'] - */ - var pluck = map; - - /** - * Reduces a collection to a value which is the accumulated result of running - * each element in the collection through the callback, where each successive - * callback execution consumes the return value of the previous execution. If - * `accumulator` is not provided the first element of the collection will be - * used as the initial `accumulator` value. The callback is bound to `thisArg` - * and invoked with four arguments; (accumulator, value, index|key, collection). - * - * @static - * @memberOf _ - * @alias foldl, inject - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [accumulator] Initial value of the accumulator. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the accumulated value. - * @example - * - * var sum = _.reduce([1, 2, 3], function(sum, num) { - * return sum + num; - * }); - * // => 6 - * - * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { - * result[key] = num * 3; - * return result; - * }, {}); - * // => { 'a': 3, 'b': 6, 'c': 9 } - */ - function reduce(collection, callback, accumulator, thisArg) { - if (!collection) return accumulator; - var noaccum = arguments.length < 3; - callback = lodash.createCallback(callback, thisArg, 4); - - var index = -1, - length = collection.length; - - if (typeof length == 'number') { - if (noaccum) { - accumulator = collection[++index]; - } - while (++index < length) { - accumulator = callback(accumulator, collection[index], index, collection); - } - } else { - forOwn(collection, function(value, index, collection) { - accumulator = noaccum - ? (noaccum = false, value) - : callback(accumulator, value, index, collection) - }); - } - return accumulator; - } - - /** - * This method is like `_.reduce` except that it iterates over elements - * of a `collection` from right to left. - * - * @static - * @memberOf _ - * @alias foldr - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [callback=identity] The function called per iteration. - * @param {*} [accumulator] Initial value of the accumulator. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the accumulated value. - * @example - * - * var list = [[0, 1], [2, 3], [4, 5]]; - * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - function reduceRight(collection, callback, accumulator, thisArg) { - var noaccum = arguments.length < 3; - callback = lodash.createCallback(callback, thisArg, 4); - forEachRight(collection, function(value, index, collection) { - accumulator = noaccum - ? (noaccum = false, value) - : callback(accumulator, value, index, collection); - }); - return accumulator; - } - - /** - * The opposite of `_.filter` this method returns the elements of a - * collection that the callback does **not** return truey for. - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a new array of elements that failed the callback check. - * @example - * - * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); - * // => [1, 3, 5] - * - * var characters = [ - * { 'name': 'barney', 'age': 36, 'blocked': false }, - * { 'name': 'fred', 'age': 40, 'blocked': true } - * ]; - * - * // using "_.pluck" callback shorthand - * _.reject(characters, 'blocked'); - * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] - * - * // using "_.where" callback shorthand - * _.reject(characters, { 'age': 36 }); - * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] - */ - function reject(collection, callback, thisArg) { - callback = lodash.createCallback(callback, thisArg, 3); - return filter(collection, function(value, index, collection) { - return !callback(value, index, collection); - }); - } - - /** - * Retrieves a random element or `n` random elements from a collection. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to sample. - * @param {number} [n] The number of elements to sample. - * @param- {Object} [guard] Allows working with functions like `_.map` - * without using their `index` arguments as `n`. - * @returns {Array} Returns the random sample(s) of `collection`. - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - * - * _.sample([1, 2, 3, 4], 2); - * // => [3, 1] - */ - function sample(collection, n, guard) { - if (collection && typeof collection.length != 'number') { - collection = values(collection); - } - if (n == null || guard) { - return collection ? collection[baseRandom(0, collection.length - 1)] : undefined; - } - var result = shuffle(collection); - result.length = nativeMin(nativeMax(0, n), result.length); - return result; - } - - /** - * Creates an array of shuffled values, using a version of the Fisher-Yates - * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to shuffle. - * @returns {Array} Returns a new shuffled collection. - * @example - * - * _.shuffle([1, 2, 3, 4, 5, 6]); - * // => [4, 1, 6, 3, 5, 2] - */ - function shuffle(collection) { - var index = -1, - length = collection ? collection.length : 0, - result = Array(typeof length == 'number' ? length : 0); - - forEach(collection, function(value) { - var rand = baseRandom(0, ++index); - result[index] = result[rand]; - result[rand] = value; - }); - return result; - } - - /** - * Gets the size of the `collection` by returning `collection.length` for arrays - * and array-like objects or the number of own enumerable properties for objects. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns `collection.length` or number of own enumerable properties. - * @example - * - * _.size([1, 2]); - * // => 2 - * - * _.size({ 'one': 1, 'two': 2, 'three': 3 }); - * // => 3 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - var length = collection ? collection.length : 0; - return typeof length == 'number' ? length : keys(collection).length; - } - - /** - * Checks if the callback returns a truey value for **any** element of a - * collection. The function returns as soon as it finds a passing value and - * does not iterate over the entire collection. The callback is bound to - * `thisArg` and invoked with three arguments; (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias any - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {boolean} Returns `true` if any element passed the callback check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var characters = [ - * { 'name': 'barney', 'age': 36, 'blocked': false }, - * { 'name': 'fred', 'age': 40, 'blocked': true } - * ]; - * - * // using "_.pluck" callback shorthand - * _.some(characters, 'blocked'); - * // => true - * - * // using "_.where" callback shorthand - * _.some(characters, { 'age': 1 }); - * // => false - */ - function some(collection, callback, thisArg) { - var result; - callback = lodash.createCallback(callback, thisArg, 3); - - var index = -1, - length = collection ? collection.length : 0; - - if (typeof length == 'number') { - while (++index < length) { - if ((result = callback(collection[index], index, collection))) { - break; - } - } - } else { - forOwn(collection, function(value, index, collection) { - return !(result = callback(value, index, collection)); - }); - } - return !!result; - } - - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection through the callback. This method - * performs a stable sort, that is, it will preserve the original sort order - * of equal elements. The callback is bound to `thisArg` and invoked with - * three arguments; (value, index|key, collection). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an array of property names is provided for `callback` the collection - * will be sorted by each property value. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a new array of sorted elements. - * @example - * - * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); - * // => [3, 1, 2] - * - * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); - * // => [3, 1, 2] - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 }, - * { 'name': 'barney', 'age': 26 }, - * { 'name': 'fred', 'age': 30 } - * ]; - * - * // using "_.pluck" callback shorthand - * _.map(_.sortBy(characters, 'age'), _.values); - * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] - * - * // sorting by multiple properties - * _.map(_.sortBy(characters, ['name', 'age']), _.values); - * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] - */ - function sortBy(collection, callback, thisArg) { - var index = -1, - isArr = isArray(callback), - length = collection ? collection.length : 0, - result = Array(typeof length == 'number' ? length : 0); - - if (!isArr) { - callback = lodash.createCallback(callback, thisArg, 3); - } - forEach(collection, function(value, key, collection) { - var object = result[++index] = getObject(); - if (isArr) { - object.criteria = map(callback, function(key) { return value[key]; }); - } else { - (object.criteria = getArray())[0] = callback(value, key, collection); - } - object.index = index; - object.value = value; - }); - - length = result.length; - result.sort(compareAscending); - while (length--) { - var object = result[length]; - result[length] = object.value; - if (!isArr) { - releaseArray(object.criteria); - } - releaseObject(object); - } - return result; - } - - /** - * Converts the `collection` to an array. - * - * @static - * @memberOf _ - * @category Collections - * @param {Array|Object|string} collection The collection to convert. - * @returns {Array} Returns the new converted array. - * @example - * - * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); - * // => [2, 3, 4] - */ - function toArray(collection) { - if (collection && typeof collection.length == 'number') { - return slice(collection); - } - return values(collection); - } - - /** - * Performs a deep comparison of each element in a `collection` to the given - * `properties` object, returning an array of all elements that have equivalent - * property values. - * - * @static - * @memberOf _ - * @type Function - * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Object} props The object of property values to filter by. - * @returns {Array} Returns a new array of elements that have the given properties. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }, - * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } - * ]; - * - * _.where(characters, { 'age': 36 }); - * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }] - * - * _.where(characters, { 'pets': ['dino'] }); - * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }] - */ - var where = filter; - - /*--------------------------------------------------------------------------*/ - - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are all falsey. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to compact. - * @returns {Array} Returns a new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array ? array.length : 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result.push(value); - } - } - return result; - } - - /** - * Creates an array excluding all values of the provided arrays using strict - * equality for comparisons, i.e. `===`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to process. - * @param {...Array} [values] The arrays of values to exclude. - * @returns {Array} Returns a new array of filtered values. - * @example - * - * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); - * // => [1, 3, 4] - */ - function difference(array) { - return baseDifference(array, baseFlatten(arguments, true, true, 1)); - } - - /** - * This method is like `_.find` except that it returns the index of the first - * element that passes the callback check, instead of the element itself. - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to search. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36, 'blocked': false }, - * { 'name': 'fred', 'age': 40, 'blocked': true }, - * { 'name': 'pebbles', 'age': 1, 'blocked': false } - * ]; - * - * _.findIndex(characters, function(chr) { - * return chr.age < 20; - * }); - * // => 2 - * - * // using "_.where" callback shorthand - * _.findIndex(characters, { 'age': 36 }); - * // => 0 - * - * // using "_.pluck" callback shorthand - * _.findIndex(characters, 'blocked'); - * // => 1 - */ - function findIndex(array, callback, thisArg) { - var index = -1, - length = array ? array.length : 0; - - callback = lodash.createCallback(callback, thisArg, 3); - while (++index < length) { - if (callback(array[index], index, array)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.findIndex` except that it iterates over elements - * of a `collection` from right to left. - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to search. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36, 'blocked': true }, - * { 'name': 'fred', 'age': 40, 'blocked': false }, - * { 'name': 'pebbles', 'age': 1, 'blocked': true } - * ]; - * - * _.findLastIndex(characters, function(chr) { - * return chr.age > 30; - * }); - * // => 1 - * - * // using "_.where" callback shorthand - * _.findLastIndex(characters, { 'age': 36 }); - * // => 0 - * - * // using "_.pluck" callback shorthand - * _.findLastIndex(characters, 'blocked'); - * // => 2 - */ - function findLastIndex(array, callback, thisArg) { - var length = array ? array.length : 0; - callback = lodash.createCallback(callback, thisArg, 3); - while (length--) { - if (callback(array[length], length, array)) { - return length; - } - } - return -1; - } - - /** - * Gets the first element or first `n` elements of an array. If a callback - * is provided elements at the beginning of the array are returned as long - * as the callback returns truey. The callback is bound to `thisArg` and - * invoked with three arguments; (value, index, array). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias head, take - * @category Arrays - * @param {Array} array The array to query. - * @param {Function|Object|number|string} [callback] The function called - * per element or the number of elements to return. If a property name or - * object is provided it will be used to create a "_.pluck" or "_.where" - * style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the first element(s) of `array`. - * @example - * - * _.first([1, 2, 3]); - * // => 1 - * - * _.first([1, 2, 3], 2); - * // => [1, 2] - * - * _.first([1, 2, 3], function(num) { - * return num < 3; - * }); - * // => [1, 2] - * - * var characters = [ - * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, - * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, - * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } - * ]; - * - * // using "_.pluck" callback shorthand - * _.first(characters, 'blocked'); - * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }] - * - * // using "_.where" callback shorthand - * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name'); - * // => ['barney', 'fred'] - */ - function first(array, callback, thisArg) { - var n = 0, - length = array ? array.length : 0; - - if (typeof callback != 'number' && callback != null) { - var index = -1; - callback = lodash.createCallback(callback, thisArg, 3); - while (++index < length && callback(array[index], index, array)) { - n++; - } - } else { - n = callback; - if (n == null || thisArg) { - return array ? array[0] : undefined; - } - } - return slice(array, 0, nativeMin(nativeMax(0, n), length)); - } - - /** - * Flattens a nested array (the nesting can be to any depth). If `isShallow` - * is truey, the array will only be flattened a single level. If a callback - * is provided each element of the array is passed through the callback before - * flattening. The callback is bound to `thisArg` and invoked with three - * arguments; (value, index, array). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to flatten. - * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a new flattened array. - * @example - * - * _.flatten([1, [2], [3, [[4]]]]); - * // => [1, 2, 3, 4]; - * - * _.flatten([1, [2], [3, [[4]]]], true); - * // => [1, 2, 3, [[4]]]; - * - * var characters = [ - * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] }, - * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } - * ]; - * - * // using "_.pluck" callback shorthand - * _.flatten(characters, 'pets'); - * // => ['hoppy', 'baby puss', 'dino'] - */ - function flatten(array, isShallow, callback, thisArg) { - // juggle arguments - if (typeof isShallow != 'boolean' && isShallow != null) { - thisArg = callback; - callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow; - isShallow = false; - } - if (callback != null) { - array = map(array, callback, thisArg); - } - return baseFlatten(array, isShallow); - } - - /** - * Gets the index at which the first occurrence of `value` is found using - * strict equality for comparisons, i.e. `===`. If the array is already sorted - * providing `true` for `fromIndex` will run a faster binary search. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {boolean|number} [fromIndex=0] The index to search from or `true` - * to perform a binary search on a sorted array. - * @returns {number} Returns the index of the matched value or `-1`. - * @example - * - * _.indexOf([1, 2, 3, 1, 2, 3], 2); - * // => 1 - * - * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); - * // => 4 - * - * _.indexOf([1, 1, 2, 2, 3, 3], 2, true); - * // => 2 - */ - function indexOf(array, value, fromIndex) { - if (typeof fromIndex == 'number') { - var length = array ? array.length : 0; - fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); - } else if (fromIndex) { - var index = sortedIndex(array, value); - return array[index] === value ? index : -1; - } - return baseIndexOf(array, value, fromIndex); - } - - /** - * Gets all but the last element or last `n` elements of an array. If a - * callback is provided elements at the end of the array are excluded from - * the result as long as the callback returns truey. The callback is bound - * to `thisArg` and invoked with three arguments; (value, index, array). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to query. - * @param {Function|Object|number|string} [callback=1] The function called - * per element or the number of elements to exclude. If a property name or - * object is provided it will be used to create a "_.pluck" or "_.where" - * style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - * - * _.initial([1, 2, 3], 2); - * // => [1] - * - * _.initial([1, 2, 3], function(num) { - * return num > 1; - * }); - * // => [1] - * - * var characters = [ - * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, - * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, - * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } - * ]; - * - * // using "_.pluck" callback shorthand - * _.initial(characters, 'blocked'); - * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }] - * - * // using "_.where" callback shorthand - * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name'); - * // => ['barney', 'fred'] - */ - function initial(array, callback, thisArg) { - var n = 0, - length = array ? array.length : 0; - - if (typeof callback != 'number' && callback != null) { - var index = length; - callback = lodash.createCallback(callback, thisArg, 3); - while (index-- && callback(array[index], index, array)) { - n++; - } - } else { - n = (callback == null || thisArg) ? 1 : callback || n; - } - return slice(array, 0, nativeMin(nativeMax(0, length - n), length)); - } - - /** - * Creates an array of unique values present in all provided arrays using - * strict equality for comparisons, i.e. `===`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {...Array} [array] The arrays to inspect. - * @returns {Array} Returns an array of shared values. - * @example - * - * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]); - * // => [1, 2] - */ - function intersection() { - var args = [], - argsIndex = -1, - argsLength = arguments.length, - caches = getArray(), - indexOf = getIndexOf(), - trustIndexOf = indexOf === baseIndexOf, - seen = getArray(); - - while (++argsIndex < argsLength) { - var value = arguments[argsIndex]; - if (isArray(value) || isArguments(value)) { - args.push(value); - caches.push(trustIndexOf && value.length >= largeArraySize && - createCache(argsIndex ? args[argsIndex] : seen)); - } - } - var array = args[0], - index = -1, - length = array ? array.length : 0, - result = []; - - outer: - while (++index < length) { - var cache = caches[0]; - value = array[index]; - - if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { - argsIndex = argsLength; - (cache || seen).push(value); - while (--argsIndex) { - cache = caches[argsIndex]; - if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { - continue outer; - } - } - result.push(value); - } - } - while (argsLength--) { - cache = caches[argsLength]; - if (cache) { - releaseObject(cache); - } - } - releaseArray(caches); - releaseArray(seen); - return result; - } - - /** - * Gets the last element or last `n` elements of an array. If a callback is - * provided elements at the end of the array are returned as long as the - * callback returns truey. The callback is bound to `thisArg` and invoked - * with three arguments; (value, index, array). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to query. - * @param {Function|Object|number|string} [callback] The function called - * per element or the number of elements to return. If a property name or - * object is provided it will be used to create a "_.pluck" or "_.where" - * style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {*} Returns the last element(s) of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - * - * _.last([1, 2, 3], 2); - * // => [2, 3] - * - * _.last([1, 2, 3], function(num) { - * return num > 1; - * }); - * // => [2, 3] - * - * var characters = [ - * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, - * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, - * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } - * ]; - * - * // using "_.pluck" callback shorthand - * _.pluck(_.last(characters, 'blocked'), 'name'); - * // => ['fred', 'pebbles'] - * - * // using "_.where" callback shorthand - * _.last(characters, { 'employer': 'na' }); - * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] - */ - function last(array, callback, thisArg) { - var n = 0, - length = array ? array.length : 0; - - if (typeof callback != 'number' && callback != null) { - var index = length; - callback = lodash.createCallback(callback, thisArg, 3); - while (index-- && callback(array[index], index, array)) { - n++; - } - } else { - n = callback; - if (n == null || thisArg) { - return array ? array[length - 1] : undefined; - } - } - return slice(array, nativeMax(0, length - n)); - } - - /** - * Gets the index at which the last occurrence of `value` is found using strict - * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used - * as the offset from the end of the collection. - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the matched value or `-1`. - * @example - * - * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); - * // => 4 - * - * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); - * // => 1 - */ - function lastIndexOf(array, value, fromIndex) { - var index = array ? array.length : 0; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; - } - while (index--) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * Removes all provided values from the given array using strict equality for - * comparisons, i.e. `===`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to modify. - * @param {...*} [value] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3, 1, 2, 3]; - * _.pull(array, 2, 3); - * console.log(array); - * // => [1, 1] - */ - function pull(array) { - var args = arguments, - argsIndex = 0, - argsLength = args.length, - length = array ? array.length : 0; - - while (++argsIndex < argsLength) { - var index = -1, - value = args[argsIndex]; - while (++index < length) { - if (array[index] === value) { - splice.call(array, index--, 1); - length--; - } - } - } - return array; - } - - /** - * Creates an array of numbers (positive and/or negative) progressing from - * `start` up to but not including `end`. If `start` is less than `stop` a - * zero-length range is created unless a negative `step` is specified. - * - * @static - * @memberOf _ - * @category Arrays - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @param {number} [step=1] The value to increment or decrement by. - * @returns {Array} Returns a new range array. - * @example - * - * _.range(4); - * // => [0, 1, 2, 3] - * - * _.range(1, 5); - * // => [1, 2, 3, 4] - * - * _.range(0, 20, 5); - * // => [0, 5, 10, 15] - * - * _.range(0, -4, -1); - * // => [0, -1, -2, -3] - * - * _.range(1, 4, 0); - * // => [1, 1, 1] - * - * _.range(0); - * // => [] - */ - function range(start, end, step) { - start = +start || 0; - step = typeof step == 'number' ? step : (+step || 1); - - if (end == null) { - end = start; - start = 0; - } - // use `Array(length)` so engines like Chakra and V8 avoid slower modes - // http://youtu.be/XAqIpGU8ZZk#t=17m25s - var index = -1, - length = nativeMax(0, ceil((end - start) / (step || 1))), - result = Array(length); - - while (++index < length) { - result[index] = start; - start += step; - } - return result; - } - - /** - * Removes all elements from an array that the callback returns truey for - * and returns an array of removed elements. The callback is bound to `thisArg` - * and invoked with three arguments; (value, index, array). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to modify. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4, 5, 6]; - * var evens = _.remove(array, function(num) { return num % 2 == 0; }); - * - * console.log(array); - * // => [1, 3, 5] - * - * console.log(evens); - * // => [2, 4, 6] - */ - function remove(array, callback, thisArg) { - var index = -1, - length = array ? array.length : 0, - result = []; - - callback = lodash.createCallback(callback, thisArg, 3); - while (++index < length) { - var value = array[index]; - if (callback(value, index, array)) { - result.push(value); - splice.call(array, index--, 1); - length--; - } - } - return result; - } - - /** - * The opposite of `_.initial` this method gets all but the first element or - * first `n` elements of an array. If a callback function is provided elements - * at the beginning of the array are excluded from the result as long as the - * callback returns truey. The callback is bound to `thisArg` and invoked - * with three arguments; (value, index, array). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias drop, tail - * @category Arrays - * @param {Array} array The array to query. - * @param {Function|Object|number|string} [callback=1] The function called - * per element or the number of elements to exclude. If a property name or - * object is provided it will be used to create a "_.pluck" or "_.where" - * style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a slice of `array`. - * @example - * - * _.rest([1, 2, 3]); - * // => [2, 3] - * - * _.rest([1, 2, 3], 2); - * // => [3] - * - * _.rest([1, 2, 3], function(num) { - * return num < 3; - * }); - * // => [3] - * - * var characters = [ - * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, - * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, - * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } - * ]; - * - * // using "_.pluck" callback shorthand - * _.pluck(_.rest(characters, 'blocked'), 'name'); - * // => ['fred', 'pebbles'] - * - * // using "_.where" callback shorthand - * _.rest(characters, { 'employer': 'slate' }); - * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] - */ - function rest(array, callback, thisArg) { - if (typeof callback != 'number' && callback != null) { - var n = 0, - index = -1, - length = array ? array.length : 0; - - callback = lodash.createCallback(callback, thisArg, 3); - while (++index < length && callback(array[index], index, array)) { - n++; - } - } else { - n = (callback == null || thisArg) ? 1 : nativeMax(0, callback); - } - return slice(array, n); - } - - /** - * Uses a binary search to determine the smallest index at which a value - * should be inserted into a given sorted array in order to maintain the sort - * order of the array. If a callback is provided it will be executed for - * `value` and each element of `array` to compute their sort ranking. The - * callback is bound to `thisArg` and invoked with one argument; (value). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to inspect. - * @param {*} value The value to evaluate. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([20, 30, 50], 40); - * // => 2 - * - * // using "_.pluck" callback shorthand - * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); - * // => 2 - * - * var dict = { - * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } - * }; - * - * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { - * return dict.wordToNumber[word]; - * }); - * // => 2 - * - * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { - * return this.wordToNumber[word]; - * }, dict); - * // => 2 - */ - function sortedIndex(array, value, callback, thisArg) { - var low = 0, - high = array ? array.length : low; - - // explicitly reference `identity` for better inlining in Firefox - callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity; - value = callback(value); - - while (low < high) { - var mid = (low + high) >>> 1; - (callback(array[mid]) < value) - ? low = mid + 1 - : high = mid; - } - return low; - } - - /** - * Creates an array of unique values, in order, of the provided arrays using - * strict equality for comparisons, i.e. `===`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {...Array} [array] The arrays to inspect. - * @returns {Array} Returns an array of combined values. - * @example - * - * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]); - * // => [1, 2, 3, 5, 4] - */ - function union() { - return baseUniq(baseFlatten(arguments, true, true)); - } - - /** - * Creates a duplicate-value-free version of an array using strict equality - * for comparisons, i.e. `===`. If the array is sorted, providing - * `true` for `isSorted` will use a faster algorithm. If a callback is provided - * each element of `array` is passed through the callback before uniqueness - * is computed. The callback is bound to `thisArg` and invoked with three - * arguments; (value, index, array). - * - * If a property name is provided for `callback` the created "_.pluck" style - * callback will return the property value of the given element. - * - * If an object is provided for `callback` the created "_.where" style callback - * will return `true` for elements that have the properties of the given object, - * else `false`. - * - * @static - * @memberOf _ - * @alias unique - * @category Arrays - * @param {Array} array The array to process. - * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted. - * @param {Function|Object|string} [callback=identity] The function called - * per iteration. If a property name or object is provided it will be used - * to create a "_.pluck" or "_.where" style callback, respectively. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Array} Returns a duplicate-value-free array. - * @example - * - * _.uniq([1, 2, 1, 3, 1]); - * // => [1, 2, 3] - * - * _.uniq([1, 1, 2, 2, 3], true); - * // => [1, 2, 3] - * - * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); - * // => ['A', 'b', 'C'] - * - * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); - * // => [1, 2.5, 3] - * - * // using "_.pluck" callback shorthand - * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniq(array, isSorted, callback, thisArg) { - // juggle arguments - if (typeof isSorted != 'boolean' && isSorted != null) { - thisArg = callback; - callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted; - isSorted = false; - } - if (callback != null) { - callback = lodash.createCallback(callback, thisArg, 3); - } - return baseUniq(array, isSorted, callback); - } - - /** - * Creates an array excluding all provided values using strict equality for - * comparisons, i.e. `===`. - * - * @static - * @memberOf _ - * @category Arrays - * @param {Array} array The array to filter. - * @param {...*} [value] The values to exclude. - * @returns {Array} Returns a new array of filtered values. - * @example - * - * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); - * // => [2, 3, 4] - */ - function without(array) { - return baseDifference(array, slice(arguments, 1)); - } - - /** - * Creates an array that is the symmetric difference of the provided arrays. - * See http://en.wikipedia.org/wiki/Symmetric_difference. - * - * @static - * @memberOf _ - * @category Arrays - * @param {...Array} [array] The arrays to inspect. - * @returns {Array} Returns an array of values. - * @example - * - * _.xor([1, 2, 3], [5, 2, 1, 4]); - * // => [3, 5, 4] - * - * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]); - * // => [1, 4, 5] - */ - function xor() { - var index = -1, - length = arguments.length; - - while (++index < length) { - var array = arguments[index]; - if (isArray(array) || isArguments(array)) { - var result = result - ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result))) - : array; - } - } - return result || []; - } - - /** - * Creates an array of grouped elements, the first of which contains the first - * elements of the given arrays, the second of which contains the second - * elements of the given arrays, and so on. - * - * @static - * @memberOf _ - * @alias unzip - * @category Arrays - * @param {...Array} [array] Arrays to process. - * @returns {Array} Returns a new array of grouped elements. - * @example - * - * _.zip(['fred', 'barney'], [30, 40], [true, false]); - * // => [['fred', 30, true], ['barney', 40, false]] - */ - function zip() { - var array = arguments.length > 1 ? arguments : arguments[0], - index = -1, - length = array ? max(pluck(array, 'length')) : 0, - result = Array(length < 0 ? 0 : length); - - while (++index < length) { - result[index] = pluck(array, index); - } - return result; - } - - /** - * Creates an object composed from arrays of `keys` and `values`. Provide - * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]` - * or two arrays, one of `keys` and one of corresponding `values`. - * - * @static - * @memberOf _ - * @alias object - * @category Arrays - * @param {Array} keys The array of keys. - * @param {Array} [values=[]] The array of values. - * @returns {Object} Returns an object composed of the given keys and - * corresponding values. - * @example - * - * _.zipObject(['fred', 'barney'], [30, 40]); - * // => { 'fred': 30, 'barney': 40 } - */ - function zipObject(keys, values) { - var index = -1, - length = keys ? keys.length : 0, - result = {}; - - if (!values && length && !isArray(keys[0])) { - values = []; - } - while (++index < length) { - var key = keys[index]; - if (values) { - result[key] = values[index]; - } else if (key) { - result[key[0]] = key[1]; - } - } - return result; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Creates a function that executes `func`, with the `this` binding and - * arguments of the created function, only after being called `n` times. - * - * @static - * @memberOf _ - * @category Functions - * @param {number} n The number of times the function must be called before - * `func` is executed. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('Done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => logs 'Done saving!', after all saves have completed - */ - function after(n, func) { - if (!isFunction(func)) { - throw new TypeError; - } - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } - - /** - * Creates a function that, when called, invokes `func` with the `this` - * binding of `thisArg` and prepends any additional `bind` arguments to those - * provided to the bound function. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to bind. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {...*} [arg] Arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var func = function(greeting) { - * return greeting + ' ' + this.name; - * }; - * - * func = _.bind(func, { 'name': 'fred' }, 'hi'); - * func(); - * // => 'hi fred' - */ - function bind(func, thisArg) { - return arguments.length > 2 - ? createWrapper(func, 17, slice(arguments, 2), null, thisArg) - : createWrapper(func, 1, null, null, thisArg); - } - - /** - * Binds methods of an object to the object itself, overwriting the existing - * method. Method names may be specified as individual arguments or as arrays - * of method names. If no method names are provided all the function properties - * of `object` will be bound. - * - * @static - * @memberOf _ - * @category Functions - * @param {Object} object The object to bind and assign the bound methods to. - * @param {...string} [methodName] The object method names to - * bind, specified as individual method names or arrays of method names. - * @returns {Object} Returns `object`. - * @example - * - * var view = { - * 'label': 'docs', - * 'onClick': function() { console.log('clicked ' + this.label); } - * }; - * - * _.bindAll(view); - * jQuery('#docs').on('click', view.onClick); - * // => logs 'clicked docs', when the button is clicked - */ - function bindAll(object) { - var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object), - index = -1, - length = funcs.length; - - while (++index < length) { - var key = funcs[index]; - object[key] = createWrapper(object[key], 1, null, null, object); - } - return object; - } - - /** - * Creates a function that, when called, invokes the method at `object[key]` - * and prepends any additional `bindKey` arguments to those provided to the bound - * function. This method differs from `_.bind` by allowing bound functions to - * reference methods that will be redefined or don't yet exist. - * See http://michaux.ca/articles/lazy-function-definition-pattern. - * - * @static - * @memberOf _ - * @category Functions - * @param {Object} object The object the method belongs to. - * @param {string} key The key of the method. - * @param {...*} [arg] Arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'name': 'fred', - * 'greet': function(greeting) { - * return greeting + ' ' + this.name; - * } - * }; - * - * var func = _.bindKey(object, 'greet', 'hi'); - * func(); - * // => 'hi fred' - * - * object.greet = function(greeting) { - * return greeting + 'ya ' + this.name + '!'; - * }; - * - * func(); - * // => 'hiya fred!' - */ - function bindKey(object, key) { - return arguments.length > 2 - ? createWrapper(key, 19, slice(arguments, 2), null, object) - : createWrapper(key, 3, null, null, object); - } - - /** - * Creates a function that is the composition of the provided functions, - * where each function consumes the return value of the function that follows. - * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. - * Each function is executed with the `this` binding of the composed function. - * - * @static - * @memberOf _ - * @category Functions - * @param {...Function} [func] Functions to compose. - * @returns {Function} Returns the new composed function. - * @example - * - * var realNameMap = { - * 'pebbles': 'penelope' - * }; - * - * var format = function(name) { - * name = realNameMap[name.toLowerCase()] || name; - * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase(); - * }; - * - * var greet = function(formatted) { - * return 'Hiya ' + formatted + '!'; - * }; - * - * var welcome = _.compose(greet, format); - * welcome('pebbles'); - * // => 'Hiya Penelope!' - */ - function compose() { - var funcs = arguments, - length = funcs.length; - - while (length--) { - if (!isFunction(funcs[length])) { - throw new TypeError; - } - } - return function() { - var args = arguments, - length = funcs.length; - - while (length--) { - args = [funcs[length].apply(this, args)]; - } - return args[0]; - }; - } - - /** - * Creates a function which accepts one or more arguments of `func` that when - * invoked either executes `func` returning its result, if all `func` arguments - * have been provided, or returns a function that accepts one or more of the - * remaining `func` arguments, and so on. The arity of `func` can be specified - * if `func.length` is not sufficient. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @returns {Function} Returns the new curried function. - * @example - * - * var curried = _.curry(function(a, b, c) { - * console.log(a + b + c); - * }); - * - * curried(1)(2)(3); - * // => 6 - * - * curried(1, 2)(3); - * // => 6 - * - * curried(1, 2, 3); - * // => 6 - */ - function curry(func, arity) { - arity = typeof arity == 'number' ? arity : (+arity || func.length); - return createWrapper(func, 4, null, null, null, arity); - } - - /** - * Creates a function that will delay the execution of `func` until after - * `wait` milliseconds have elapsed since the last time it was invoked. - * Provide an options object to indicate that `func` should be invoked on - * the leading and/or trailing edge of the `wait` timeout. Subsequent calls - * to the debounced function will return the result of the last `func` call. - * - * Note: If `leading` and `trailing` options are `true` `func` will be called - * on the trailing edge of the timeout only if the the debounced function is - * invoked more than once during the `wait` timeout. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to debounce. - * @param {number} wait The number of milliseconds to delay. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout. - * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called. - * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // avoid costly calculations while the window size is in flux - * var lazyLayout = _.debounce(calculateLayout, 150); - * jQuery(window).on('resize', lazyLayout); - * - * // execute `sendMail` when the click event is fired, debouncing subsequent calls - * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * }); - * - * // ensure `batchLog` is executed once after 1 second of debounced calls - * var source = new EventSource('/stream'); - * source.addEventListener('message', _.debounce(batchLog, 250, { - * 'maxWait': 1000 - * }, false); - */ - function debounce(func, wait, options) { - var args, - maxTimeoutId, - result, - stamp, - thisArg, - timeoutId, - trailingCall, - lastCalled = 0, - maxWait = false, - trailing = true; - - if (!isFunction(func)) { - throw new TypeError; - } - wait = nativeMax(0, wait) || 0; - if (options === true) { - var leading = true; - trailing = false; - } else if (isObject(options)) { - leading = options.leading; - maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0); - trailing = 'trailing' in options ? options.trailing : trailing; - } - var delayed = function() { - var remaining = wait - (now() - stamp); - if (remaining <= 0) { - if (maxTimeoutId) { - clearTimeout(maxTimeoutId); - } - var isCalled = trailingCall; - maxTimeoutId = timeoutId = trailingCall = undefined; - if (isCalled) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = null; - } - } - } else { - timeoutId = setTimeout(delayed, remaining); - } - }; - - var maxDelayed = function() { - if (timeoutId) { - clearTimeout(timeoutId); - } - maxTimeoutId = timeoutId = trailingCall = undefined; - if (trailing || (maxWait !== wait)) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = null; - } - } - }; - - return function() { - args = arguments; - stamp = now(); - thisArg = this; - trailingCall = trailing && (timeoutId || !leading); - - if (maxWait === false) { - var leadingCall = leading && !timeoutId; - } else { - if (!maxTimeoutId && !leading) { - lastCalled = stamp; - } - var remaining = maxWait - (stamp - lastCalled), - isCalled = remaining <= 0; - - if (isCalled) { - if (maxTimeoutId) { - maxTimeoutId = clearTimeout(maxTimeoutId); - } - lastCalled = stamp; - result = func.apply(thisArg, args); - } - else if (!maxTimeoutId) { - maxTimeoutId = setTimeout(maxDelayed, remaining); - } - } - if (isCalled && timeoutId) { - timeoutId = clearTimeout(timeoutId); - } - else if (!timeoutId && wait !== maxWait) { - timeoutId = setTimeout(delayed, wait); - } - if (leadingCall) { - isCalled = true; - result = func.apply(thisArg, args); - } - if (isCalled && !timeoutId && !maxTimeoutId) { - args = thisArg = null; - } - return result; - }; - } - - /** - * Defers executing the `func` function until the current call stack has cleared. - * Additional arguments will be provided to `func` when it is invoked. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to defer. - * @param {...*} [arg] Arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { console.log(text); }, 'deferred'); - * // logs 'deferred' after one or more milliseconds - */ - function defer(func) { - if (!isFunction(func)) { - throw new TypeError; - } - var args = slice(arguments, 1); - return setTimeout(function() { func.apply(undefined, args); }, 1); - } - - /** - * Executes the `func` function after `wait` milliseconds. Additional arguments - * will be provided to `func` when it is invoked. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay execution. - * @param {...*} [arg] Arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { console.log(text); }, 1000, 'later'); - * // => logs 'later' after one second - */ - function delay(func, wait) { - if (!isFunction(func)) { - throw new TypeError; - } - var args = slice(arguments, 2); - return setTimeout(function() { func.apply(undefined, args); }, wait); - } - - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided it will be used to determine the cache key for storing the result - * based on the arguments provided to the memoized function. By default, the - * first argument provided to the memoized function is used as the cache key. - * The `func` is executed with the `this` binding of the memoized function. - * The result cache is exposed as the `cache` property on the memoized function. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] A function used to resolve the cache key. - * @returns {Function} Returns the new memoizing function. - * @example - * - * var fibonacci = _.memoize(function(n) { - * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); - * }); - * - * fibonacci(9) - * // => 34 - * - * var data = { - * 'fred': { 'name': 'fred', 'age': 40 }, - * 'pebbles': { 'name': 'pebbles', 'age': 1 } - * }; - * - * // modifying the result cache - * var get = _.memoize(function(name) { return data[name]; }, _.identity); - * get('pebbles'); - * // => { 'name': 'pebbles', 'age': 1 } - * - * get.cache.pebbles.name = 'penelope'; - * get('pebbles'); - * // => { 'name': 'penelope', 'age': 1 } - */ - function memoize(func, resolver) { - if (!isFunction(func)) { - throw new TypeError; - } - var memoized = function() { - var cache = memoized.cache, - key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0]; - - return hasOwnProperty.call(cache, key) - ? cache[key] - : (cache[key] = func.apply(this, arguments)); - } - memoized.cache = {}; - return memoized; - } - - /** - * Creates a function that is restricted to execute `func` once. Repeat calls to - * the function will return the value of the first call. The `func` is executed - * with the `this` binding of the created function. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // `initialize` executes `createApplication` once - */ - function once(func) { - var ran, - result; - - if (!isFunction(func)) { - throw new TypeError; - } - return function() { - if (ran) { - return result; - } - ran = true; - result = func.apply(this, arguments); - - // clear the `func` variable so the function may be garbage collected - func = null; - return result; - }; - } - - /** - * Creates a function that, when called, invokes `func` with any additional - * `partial` arguments prepended to those provided to the new function. This - * method is similar to `_.bind` except it does **not** alter the `this` binding. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [arg] Arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var greet = function(greeting, name) { return greeting + ' ' + name; }; - * var hi = _.partial(greet, 'hi'); - * hi('fred'); - * // => 'hi fred' - */ - function partial(func) { - return createWrapper(func, 16, slice(arguments, 1)); - } - - /** - * This method is like `_.partial` except that `partial` arguments are - * appended to those provided to the new function. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [arg] Arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var defaultsDeep = _.partialRight(_.merge, _.defaults); - * - * var options = { - * 'variable': 'data', - * 'imports': { 'jq': $ } - * }; - * - * defaultsDeep(options, _.templateSettings); - * - * options.variable - * // => 'data' - * - * options.imports - * // => { '_': _, 'jq': $ } - */ - function partialRight(func) { - return createWrapper(func, 32, null, slice(arguments, 1)); - } - - /** - * Creates a function that, when executed, will only call the `func` function - * at most once per every `wait` milliseconds. Provide an options object to - * indicate that `func` should be invoked on the leading and/or trailing edge - * of the `wait` timeout. Subsequent calls to the throttled function will - * return the result of the last `func` call. - * - * Note: If `leading` and `trailing` options are `true` `func` will be called - * on the trailing edge of the timeout only if the the throttled function is - * invoked more than once during the `wait` timeout. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to throttle. - * @param {number} wait The number of milliseconds to throttle executions to. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // avoid excessively updating the position while scrolling - * var throttled = _.throttle(updatePosition, 100); - * jQuery(window).on('scroll', throttled); - * - * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes - * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { - * 'trailing': false - * })); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (!isFunction(func)) { - throw new TypeError; - } - if (options === false) { - leading = false; - } else if (isObject(options)) { - leading = 'leading' in options ? options.leading : leading; - trailing = 'trailing' in options ? options.trailing : trailing; - } - debounceOptions.leading = leading; - debounceOptions.maxWait = wait; - debounceOptions.trailing = trailing; - - return debounce(func, wait, debounceOptions); - } - - /** - * Creates a function that provides `value` to the wrapper function as its - * first argument. Additional arguments provided to the function are appended - * to those provided to the wrapper function. The wrapper is executed with - * the `this` binding of the created function. - * - * @static - * @memberOf _ - * @category Functions - * @param {*} value The value to wrap. - * @param {Function} wrapper The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

    ' + func(text) + '

    '; - * }); - * - * p('Fred, Wilma, & Pebbles'); - * // => '

    Fred, Wilma, & Pebbles

    ' - */ - function wrap(value, wrapper) { - return createWrapper(wrapper, 16, [value]); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Creates a function that returns `value`. - * - * @static - * @memberOf _ - * @category Utilities - * @param {*} value The value to return from the new function. - * @returns {Function} Returns the new function. - * @example - * - * var object = { 'name': 'fred' }; - * var getter = _.constant(object); - * getter() === object; - * // => true - */ - function constant(value) { - return function() { - return value; - }; - } - - /** - * Produces a callback bound to an optional `thisArg`. If `func` is a property - * name the created callback will return the property value for a given element. - * If `func` is an object the created callback will return `true` for elements - * that contain the equivalent object properties, otherwise it will return `false`. - * - * @static - * @memberOf _ - * @category Utilities - * @param {*} [func=identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of the created callback. - * @param {number} [argCount] The number of arguments the callback accepts. - * @returns {Function} Returns a callback function. - * @example - * - * var characters = [ - * { 'name': 'barney', 'age': 36 }, - * { 'name': 'fred', 'age': 40 } - * ]; - * - * // wrap to create custom callback shorthands - * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) { - * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback); - * return !match ? func(callback, thisArg) : function(object) { - * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3]; - * }; - * }); - * - * _.filter(characters, 'age__gt38'); - * // => [{ 'name': 'fred', 'age': 40 }] - */ - function createCallback(func, thisArg, argCount) { - var type = typeof func; - if (func == null || type == 'function') { - return baseCreateCallback(func, thisArg, argCount); - } - // handle "_.pluck" style callback shorthands - if (type != 'object') { - return property(func); - } - var props = keys(func), - key = props[0], - a = func[key]; - - // handle "_.where" style callback shorthands - if (props.length == 1 && a === a && !isObject(a)) { - // fast path the common case of providing an object with a single - // property containing a primitive value - return function(object) { - var b = object[key]; - return a === b && (a !== 0 || (1 / a == 1 / b)); - }; - } - return function(object) { - var length = props.length, - result = false; - - while (length--) { - if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) { - break; - } - } - return result; - }; - } - - /** - * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their - * corresponding HTML entities. - * - * @static - * @memberOf _ - * @category Utilities - * @param {string} string The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('Fred, Wilma, & Pebbles'); - * // => 'Fred, Wilma, & Pebbles' - */ - function escape(string) { - return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar); - } - - /** - * This method returns the first argument provided to it. - * - * @static - * @memberOf _ - * @category Utilities - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'name': 'fred' }; - * _.identity(object) === object; - * // => true - */ - function identity(value) { - return value; - } - - /** - * Adds function properties of a source object to the destination object. - * If `object` is a function methods will be added to its prototype as well. - * - * @static - * @memberOf _ - * @category Utilities - * @param {Function|Object} [object=lodash] object The destination object. - * @param {Object} source The object of functions to add. - * @param {Object} [options] The options object. - * @param {boolean} [options.chain=true] Specify whether the functions added are chainable. - * @example - * - * function capitalize(string) { - * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); - * } - * - * _.mixin({ 'capitalize': capitalize }); - * _.capitalize('fred'); - * // => 'Fred' - * - * _('fred').capitalize().value(); - * // => 'Fred' - * - * _.mixin({ 'capitalize': capitalize }, { 'chain': false }); - * _('fred').capitalize(); - * // => 'Fred' - */ - function mixin(object, source, options) { - var chain = true, - methodNames = source && functions(source); - - if (!source || (!options && !methodNames.length)) { - if (options == null) { - options = source; - } - ctor = lodashWrapper; - source = object; - object = lodash; - methodNames = functions(source); - } - if (options === false) { - chain = false; - } else if (isObject(options) && 'chain' in options) { - chain = options.chain; - } - var ctor = object, - isFunc = isFunction(ctor); - - forEach(methodNames, function(methodName) { - var func = object[methodName] = source[methodName]; - if (isFunc) { - ctor.prototype[methodName] = function() { - var chainAll = this.__chain__, - value = this.__wrapped__, - args = [value]; - - push.apply(args, arguments); - var result = func.apply(object, args); - if (chain || chainAll) { - if (value === result && isObject(result)) { - return this; - } - result = new ctor(result); - result.__chain__ = chainAll; - } - return result; - }; - } - }); - } - - /** - * Reverts the '_' variable to its previous value and returns a reference to - * the `lodash` function. - * - * @static - * @memberOf _ - * @category Utilities - * @returns {Function} Returns the `lodash` function. - * @example - * - * var lodash = _.noConflict(); - */ - function noConflict() { - context._ = oldDash; - return this; - } - - /** - * A no-operation function. - * - * @static - * @memberOf _ - * @category Utilities - * @example - * - * var object = { 'name': 'fred' }; - * _.noop(object) === undefined; - * // => true - */ - function noop() { - // no operation performed - } - - /** - * Gets the number of milliseconds that have elapsed since the Unix epoch - * (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @category Utilities - * @example - * - * var stamp = _.now(); - * _.defer(function() { console.log(_.now() - stamp); }); - * // => logs the number of milliseconds it took for the deferred function to be called - */ - var now = isNative(now = Date.now) && now || function() { - return new Date().getTime(); - }; - - /** - * Converts the given value into an integer of the specified radix. - * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the - * `value` is a hexadecimal, in which case a `radix` of `16` is used. - * - * Note: This method avoids differences in native ES3 and ES5 `parseInt` - * implementations. See http://es5.github.io/#E. - * - * @static - * @memberOf _ - * @category Utilities - * @param {string} value The value to parse. - * @param {number} [radix] The radix used to interpret the value to parse. - * @returns {number} Returns the new integer value. - * @example - * - * _.parseInt('08'); - * // => 8 - */ - var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) { - // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt` - return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0); - }; - - /** - * Creates a "_.pluck" style function, which returns the `key` value of a - * given object. - * - * @static - * @memberOf _ - * @category Utilities - * @param {string} key The name of the property to retrieve. - * @returns {Function} Returns the new function. - * @example - * - * var characters = [ - * { 'name': 'fred', 'age': 40 }, - * { 'name': 'barney', 'age': 36 } - * ]; - * - * var getName = _.property('name'); - * - * _.map(characters, getName); - * // => ['barney', 'fred'] - * - * _.sortBy(characters, getName); - * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] - */ - function property(key) { - return function(object) { - return object[key]; - }; - } - - /** - * Produces a random number between `min` and `max` (inclusive). If only one - * argument is provided a number between `0` and the given number will be - * returned. If `floating` is truey or either `min` or `max` are floats a - * floating-point number will be returned instead of an integer. - * - * @static - * @memberOf _ - * @category Utilities - * @param {number} [min=0] The minimum possible value. - * @param {number} [max=1] The maximum possible value. - * @param {boolean} [floating=false] Specify returning a floating-point number. - * @returns {number} Returns a random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(min, max, floating) { - var noMin = min == null, - noMax = max == null; - - if (floating == null) { - if (typeof min == 'boolean' && noMax) { - floating = min; - min = 1; - } - else if (!noMax && typeof max == 'boolean') { - floating = max; - noMax = true; - } - } - if (noMin && noMax) { - max = 1; - } - min = +min || 0; - if (noMax) { - max = min; - min = 0; - } else { - max = +max || 0; - } - if (floating || min % 1 || max % 1) { - var rand = nativeRandom(); - return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max); - } - return baseRandom(min, max); - } - - /** - * Resolves the value of property `key` on `object`. If `key` is a function - * it will be invoked with the `this` binding of `object` and its result returned, - * else the property value is returned. If `object` is falsey then `undefined` - * is returned. - * - * @static - * @memberOf _ - * @category Utilities - * @param {Object} object The object to inspect. - * @param {string} key The name of the property to resolve. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { - * 'cheese': 'crumpets', - * 'stuff': function() { - * return 'nonsense'; - * } - * }; - * - * _.result(object, 'cheese'); - * // => 'crumpets' - * - * _.result(object, 'stuff'); - * // => 'nonsense' - */ - function result(object, key) { - if (object) { - var value = object[key]; - return isFunction(value) ? object[key]() : value; - } - } - - /** - * A micro-templating method that handles arbitrary delimiters, preserves - * whitespace, and correctly escapes quotes within interpolated code. - * - * Note: In the development build, `_.template` utilizes sourceURLs for easier - * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl - * - * For more information on precompiling templates see: - * https://lodash.com/custom-builds - * - * For more information on Chrome extension sandboxes see: - * http://developer.chrome.com/stable/extensions/sandboxingEval.html - * - * @static - * @memberOf _ - * @category Utilities - * @param {string} text The template text. - * @param {Object} data The data object used to populate the text. - * @param {Object} [options] The options object. - * @param {RegExp} [options.escape] The "escape" delimiter. - * @param {RegExp} [options.evaluate] The "evaluate" delimiter. - * @param {Object} [options.imports] An object to import into the template as local variables. - * @param {RegExp} [options.interpolate] The "interpolate" delimiter. - * @param {string} [sourceURL] The sourceURL of the template's compiled source. - * @param {string} [variable] The data object variable name. - * @returns {Function|string} Returns a compiled function when no `data` object - * is given, else it returns the interpolated text. - * @example - * - * // using the "interpolate" delimiter to create a compiled template - * var compiled = _.template('hello <%= name %>'); - * compiled({ 'name': 'fred' }); - * // => 'hello fred' - * - * // using the "escape" delimiter to escape HTML in data property values - * _.template('<%- value %>', { 'value': ' + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +
    +
    +

    + Browse to a module or class using the sidebar to view its API documentation. +

    + +

    Keyboard Shortcuts

    + +
      +
    • Press s to focus the API search box.

    • + +
    • Use Up and Down to select classes, modules, and search results.

    • + +
    • With the API search box or sidebar focused, use -Left or -Right to switch sidebar tabs.

    • + +
    • With the API search box or sidebar focused, use Ctrl+Left and Ctrl+Right to switch sidebar tabs.

    • +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/modules/Backbone.html b/modules/Backbone.html new file mode 100644 index 0000000..7e7f368 --- /dev/null +++ b/modules/Backbone.html @@ -0,0 +1,192 @@ + + + + + Backbone - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Backbone Module

    +
    + + + +
    + Requires +
      + +
    • backbone.js ~1.1.2
    • + +
    +
    + + + + + +
    + + + +
    + +
    + + + +
    +
    + +

    This module provides the following classes:

    + + + +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/modules/Hook.Plugin.html b/modules/Hook.Plugin.html new file mode 100644 index 0000000..162dad3 --- /dev/null +++ b/modules/Hook.Plugin.html @@ -0,0 +1,198 @@ + + + + + Hook.Plugin - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook.Plugin Module

    +
    + + + +
    + Requires +
      + +
    • winchan ~ac4b142c
    • + +
    +
    + + + + + +
    + + + +
    + +
    + + + +
    +
    + +

    This module provides the following classes:

    + + + +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/modules/Hook.html b/modules/Hook.html new file mode 100644 index 0000000..89a62ad --- /dev/null +++ b/modules/Hook.html @@ -0,0 +1,252 @@ + + + + + Hook - hook-javascript + + + + + + + + +
    +
    +
    + +

    + +
    +
    + API Docs for: 0.2.1 +
    +
    +
    + + +
    +
    + Show: + + + + + + + +
    + + +
    +
    +
    +

    Hook Module

    +
    + + + + + + + +
    + + + +
    +

    Deals with user registration/authentication

    + +
    + + +
    +

    Example:

    +
    +

    Connecting through websockets.

    +
    var channel = client.channel('messages', { transport: "websockets" });
    +

    Force socket server endpoint.

    +
    var channel = client.channel('messages', {
    +  transport: "websockets",
    +  url: "ws://localhost:8080"
    +});
    + +
    +
    + + +
    + + +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/package.json b/package.json deleted file mode 100644 index 1752732..0000000 --- a/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "hook-javascript", - "title": "hook javascript client", - "description": "hook javascript client", - "version": "0.3.9", - "homepage": "http://github.com/doubleleft/hook-javascript", - "main": "dist/hook.js", - "authors": [{ - "name": "Endel Dreyer", - "email": "endel.dreyer@gmail.com" - }], - "keywords": ["hook", "javascript", "client"], - "repository": { - "type": "git", - "url": "https://github.com/doubleleft/hook-javascript.git" - }, - "bugs": { - "url": "https://github.com/doubleleft/hook-javascript/issues" - }, - "scripts": {}, - "devDependencies": { - "bower": "~1.3.12", - "grunt": "~0.4.5", - "grunt-contrib-yuidoc": "*", - "grunt-contrib-concat": "*", - "grunt-contrib-watch": "*", - "grunt-contrib-jshint": "*", - "grunt-contrib-uglify": "*", - "grunt-contrib-connect": "*", - "grunt-contrib-qunit": "~0.5.2", - "grunt-saucelabs": "~8.6.0", - "grunt-loader": "0.2.1" - } -} diff --git a/src/auth.js b/src/auth.js deleted file mode 100644 index 113f83d..0000000 --- a/src/auth.js +++ /dev/null @@ -1,225 +0,0 @@ -/** - * Deals with user registration/authentication - * @module Hook - * @class Hook.Auth - * @extends Hook.Events - * @param {Hook.Client} client - * @constructor - */ -Hook.Auth = function(client) { - this.client = client; - - /** - * @property currentUser - * @type {Object} - */ - this.currentUser = null; - - var now = new Date(), - tokenExpiration = new Date(window.localStorage.getItem(this.client.app_id + '-' + Hook.Auth.AUTH_TOKEN_EXPIRATION)), - currentUser = window.localStorage.getItem(this.client.app_id + '-' + Hook.Auth.AUTH_DATA_KEY); - - // Fill current user only when it isn't expired yet. - if (currentUser && now.getTime() < tokenExpiration.getTime()) { - this.currentUser = JSON.parse(currentUser); // localStorage only supports recording strings, so we need to parse it - } -}; - -// Inherits from Events -Hook.Auth.prototype = new Hook.Events(); -Hook.Auth.prototype.constructor = Hook.Auth; - -// Constants -Hook.Auth.AUTH_DATA_KEY = 'hook-auth-data'; -Hook.Auth.AUTH_TOKEN_KEY = 'hook-auth-token'; -Hook.Auth.AUTH_TOKEN_EXPIRATION = 'hook-auth-token-expiration'; - -/** - * @method setUserData - * @param {Object} data - * @return {Hook.Auth} this - */ -Hook.Auth.prototype.setCurrentUser = function(data) { - if (!data) { - // trigger logout event - this.trigger('logout', this.currentUser); - this.currentUser = data; - - window.localStorage.removeItem(this.client.app_id + '-' + Hook.Auth.AUTH_TOKEN_KEY); - window.localStorage.removeItem(this.client.app_id + '-' + Hook.Auth.AUTH_DATA_KEY); - } else { - window.localStorage.setItem(this.client.app_id + '-' + Hook.Auth.AUTH_DATA_KEY, JSON.stringify(data)); - - // trigger login event - this.currentUser = data; - this.trigger('login', data); - } - - return this; -}; - -/** - * Register a user. - * @param {Object} data - * @method register - * - * @example Register with email address - * - * client.auth.register({ - * email: "endel@doubleleft.com", - * password: "12345", - * name: "Endel Dreyer" - * }).then(function(user) { - * console.log("Registered user: ", user); - * }); - * - */ -Hook.Auth.prototype.register = function(data) { - var promise, that = this; - if (typeof(data)==="undefined") { data = {}; } - promise = this.client.post('auth/email', data); - promise.then(function(data) { - that._registerToken(data); - }); - return promise; -}; - -/** - * Verify if user is already registered, and log-in if succeed. - * @method login - * @param {Object} data - * @return {Promise} - * - * @example - * - * client.auth.login({email: "edreyer@doubleleft.com", password: "123"}).then(function(data){ - * console.log("User found: ", data); - * }, function(data){ - * console.log("User not found or password invalid.", data); - * }); - */ -Hook.Auth.prototype.login = function(data) { - var promise, that = this; - if (typeof(data)==="undefined") { data = {}; } - promise = this.client.post('auth/email/login', data); - promise.then(function(data) { - that._registerToken(data); - }); - return promise; -}; - -/** - * Update current user info. - * - * @method update - * @param {Object} data - * @return {Promise} - * - * @example - * - * client.auth.update({ score: 100 }).then(function(data){ - * console.log("updated successfully: ", data); - * }).otherwise(function(data){ - * console.log("error: ", data); - * }); - */ -Hook.Auth.prototype.update = function(data) { - if (!this.currentUser) { - throw new Error("not logged in."); - } - - var that = this; - var promise = this.client.post('auth/update', data); - - // update localStorage info - promise.then(function(data) { that.setCurrentUser(data); }); - - return promise; -}; - -/** - * Send a 'forgot password' confirmation email to target user email address. - * @method forgotPassword - * @param {Object} data - * @return {Promise} - * - * @example - * - * client.auth.forgotPassword({ - * email: "edreyer@doubleleft.com", - * subject: "Project name: Forgot your password?", - * template: "Hi {{name}}, click here to reset your password http://custom-project.com/pass-recovery-path.html?token={{token}}" - * }).then(function(data){ - * console.log("Email enviado!", data); - * }, function(data){ - * console.log("User not found: ", data); - * }); - */ -Hook.Auth.prototype.forgotPassword = function(data) { - if (typeof(data)==="undefined") { data = {}; } - return this.client.post('auth/email/forgotPassword', data); -}; - -/** - * Reset user password - * @method resetPassword - * @param {Object} data - * @param {Object} data.password - * @param {Object} data.token [optional] - * @return {Promise} - * - * @example Getting token automatically from query string - * - * client.auth.resetPassword("my-new-password-123").then(function(data){ - * console.log("Password reseted! ", data); - * }, function(data){ - * console.log("Error", data.error); - * }); - * - * @example Providing a token manually - * - * client.auth.resetPassword({token: "xxx", password: "my-new-password-123"}).then(function(data){ - * console.log("Password reseted! ", data); - * }, function(data){ - * console.log("Error", data.error); - * }); - * - */ -Hook.Auth.prototype.resetPassword = function(data) { - if (typeof(data)==="string") { data = { password: data }; } - if (typeof(data.token)==="undefined") { - data.token = window.location.href.match(/[\?|&]token=([a-z0-9]+)/); - data.token = (data.token && data.token[1]); - } - if (typeof(data.token)!=="string") { throw new Error("forgot password token required. Remember to use 'auth.forgotPassword' before 'auth.resetPassword'."); } - if (typeof(data.password)!=="string") { throw new Error("new password required."); } - return this.client.post('auth/email/resetPassword', data); -}; - -/** - * @method logout - * @return {Hook.Auth} this - */ -Hook.Auth.prototype.logout = function() { - return this.setCurrentUser(null); -}; - -/** - * @method getToken - * @return {String|null} - */ -Hook.Auth.prototype.getToken = function() { - return window.localStorage.getItem(this.client.app_id + '-' + Hook.Auth.AUTH_TOKEN_KEY); -}; - -Hook.Auth.prototype._registerToken = function(data) { - if (data.token) { - // register authentication token on localStorage - window.localStorage.setItem(this.client.app_id + '-' + Hook.Auth.AUTH_TOKEN_KEY, data.token.token); - window.localStorage.setItem(this.client.app_id + '-' + Hook.Auth.AUTH_TOKEN_EXPIRATION, data.token.expire_at); - delete data.token; - - // Store curent user - this.setCurrentUser(data); - } -}; diff --git a/src/channel.js b/src/channel.js deleted file mode 100644 index 5b5c11c..0000000 --- a/src/channel.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Channel implementations - */ -Hook.Channel = {}; - -// Hook.Channel.Example = function(client, collection, options) { -// }; - -// Hook.Channel.Example.prototype.subscribe = function(event, callback) { -// }; - -// Hook.Channel.Example.prototype.isConnected = function() { -// }; - -// Hook.Channel.Example.prototype.unsubscribe = function(event) { -// }; - -// Hook.Channel.Example.prototype.publish = function(event, message) { -// }; - -// Hook.Channel.Example.prototype.disconnect = function(sync) { -// }; diff --git a/src/channel/sse.js b/src/channel/sse.js deleted file mode 100644 index f5f8e40..0000000 --- a/src/channel/sse.js +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @module Hook - * @class Hook.Channel.SSE - * - * @param {Client} client - * @param {String} namespace - * @param {Object} options optional - * @constructor - * - */ -Hook.Channel.SSE = function(client, collection, options) { - this.collection = collection; - this.client_id = null; - this.callbacks = {}; - this.options = options || {}; - this.readyState = null; -}; - -/** - * Subscribe to channel. Publishes a 'connected' message on the first time. - * @method subscribe - * @param {String} event (optional) - * @param {Function} callback - * @return {Promise} - * - * @example Registering for all messages - * - * channel.subscribe(function(event, data) { - * console.log("Message: ", event, data); - * }) - * - * @example Registering for a single custom event - * - * channel.subscribe('some-event', function(data) { - * console.log("Custom event triggered: ", data); - * }) - * - * @example Registering for client connected/disconnected events - * - * channel.subscribe('connected', function(data) { - * console.log("New client connected: ", data.client_id); - * }); - * channel.subscribe('disconnected', function(data) { - * console.log("Client disconnected: ", data.client_id); - * }); - * - * - * @example Registering error event - * - * channel.subscribe('state:open', function(e) { - * console.log("Error: ", e); - * }); - * channel.subscribe('state:error', function(e) { - * console.log("Error: ", e); - * }); - * - * - */ -Hook.Channel.SSE.prototype.subscribe = function(event, callback) { - if (typeof(callback)==="undefined") { - callback = event; - event = '_default'; - } - this.callbacks[event] = callback; - - var promise = this.connect(); - - if (this.readyState === EventSource.CONNECTING) { - var that = this; - promise.then(function() { - that.event_source.onopen = function(e) { - that.readyState = e.readyState; - that._trigger.apply(that, ['state:' + e.type, e]); - }; - that.event_source.onerror = function(e) { - that.readyState = e.readyState; - that._trigger.apply(that, ['state:' + e.type, e]); - }; - that.event_source.onmessage = function(e) { - var data = JSON.parse(e.data), - event = data.event; - delete data.event; - that._trigger.apply(that, [event, data]); - }; - }); - } - - return promise; -}; - -/** - */ -Hook.Channel.SSE.prototype._trigger = function(event, data) { - console.log("Trigger: ", event, data); - // always try to dispatch default message handler - if (event.indexOf('state:')===-1 && this.callbacks._default) { - this.callbacks._default.apply(this, [event, data]); - } - // try to dispatch message handler for this event - if (this.callbacks[event]) { - this.callbacks[event].apply(this, [data]); - } -}; - -/** - * Is EventSource listenning to messages? - * @method isConnected - * @return {Boolean} - */ -Hook.Channel.SSE.prototype.isConnected = function() { - return (this.readyState !== null && this.readyState !== EventSource.CLOSED); -}; - -/** - * Unsubscribe to a event listener - * @method unsubscribe - * @param {String} event - */ -Hook.Channel.SSE.prototype.unsubscribe = function(event) { - if (this.callbacks[event]) { - this.callbacks[event] = null; - } -}; - -/** - * Publish event message - * @method publish - * @param {String} event - * @param {Object} message - * @return {Promise} - */ -Hook.Channel.SSE.prototype.publish = function(event, message) { - if (typeof(message)==="undefined") { message = {}; } - message.client_id = this.client_id; - message.event = event; - return this.collection.create(message); -}; - -Hook.Channel.SSE.prototype.connect = function() { - // Return success if already connected. - if (this.readyState !== null) { - var deferred = when.defer(); - deferred.resolver.resolve(); - return deferred.promise; - } - - this.readyState = EventSource.CONNECTING; - this._trigger.apply(this, ['state:connecting']); - - var that = this; - - return this.publish('connected').then(function(data) { - that.collection.where('updated_at', '>', data.updated_at); - - // time to wait for retry, after connection closes - var query = that.collection.buildQuery(); - query.stream = { - 'refresh': that.options.refresh_timeout || 1, - 'retry': that.options.retry_timeout || 1 - }; - - that.client_id = data.client_id; - that.event_source = new EventSource(that.collection.client.url(that.collection.segments) + "&" + JSON.stringify(query), { - withCredentials: true - }); - - // bind unload function to force user disconnection - window.addEventListener('unload', function(e) { - // send synchronous disconnected event - that.disconnect(true); - }); - }, function(data) { - that.readyState = EventSource.CLOSED; - that._trigger.apply(that, ['state:error', data]); - }); -}; - -/** - * Disconnect from channel, publishing a 'disconnected' message. - * @method disconnect - * @param {Boolean} synchronous default = false - * @return {Hook.Channel} this - */ -Hook.Channel.SSE.prototype.disconnect = function(sync) { - if (this.isConnected()) { - this.close(); - this.publish('disconnected', { - _sync: ((typeof(sync)!=="undefined") && sync) - }); - } - return this; -}; - -/** - * Close event source connection. - * @method close - * @return {Channel} this - */ -Hook.Channel.SSE.prototype.close = function() { - if (this.event_source) { - this.event_source.close(); - } - this.readyState = EventSource.CLOSED; - return this; -}; - diff --git a/src/channel/websockets.js b/src/channel/websockets.js deleted file mode 100644 index 54fca40..0000000 --- a/src/channel/websockets.js +++ /dev/null @@ -1,185 +0,0 @@ -/** - * @module Hook - * @class Hook.Channel.WEBSOCKETS - * - * @param {Client} client - * @param {String} namespace - * @param {Object} options optional - * @constructor - * - * @example Connecting through websockets. - * - * var channel = client.channel('messages', { transport: "websockets" }); - * - * @example Force socket server endpoint. - * - * var channel = client.channel('messages', { - * transport: "websockets", - * url: "ws://localhost:8080" - * }); - */ -Hook.Channel.WEBSOCKETS = function(client, collection, options) { - var that = this; - - this.client = client; - this.collection = collection; - this.client_id = null; - - if (!options.url) { - var scheme = window.location.protocol === 'https:' ? 'wss://' : 'ws://', - url = client.url.replace(/(?:https?:)?\/\//, scheme) - - if (url.match(/index\.php/)) { - url = url.replace("index.php", "ws/"); - } else { - url += "ws/"; - } - - options.url = url; - } - - options.url += this.collection.name + "?X-App-Id=" + this.client.app_id + "&X-App-Key=" + this.client.key; - var auth_token = this.client.auth.getToken(); - if (auth_token) { - options.url += '&X-Auth-Token=' + auth_token; - } - - // WAMP message debugging - ab.debug(options.debug === true, options.verbose === true, options.debug === true); - - // subscribe to queued events when successfully connected. - this.queued_subscriptions = {}; - this.on('connected', function() { - for (var event in that.queued_subscriptions) { - if (that.queued_subscriptions.hasOwnProperty(event)) { - that.subscribe(event, that.queued_subscriptions[event]); - } - } - that.queued_subscriptions = null; - }); - - ab.connect(options.url, function(session) { - that.ws = session; - that.client_id = session.sessionid(); - that.trigger('connected'); - }, function(err) { - console.error("Can't connect with WebSocket server: " + options.url, err); - }, { - retryDelay: 1000, - maxRetries: 10 - }); -}; - -// Inherits from Events - -Hook.Channel.WEBSOCKETS.prototype = new Hook.Events(); -Hook.Channel.WEBSOCKETS.prototype.constructor = Hook.Channel.WEBSOCKETS; - -/** - * Subscribe to channel. Publishes a 'connected' message on the first time. - * @method subscribe - * @param {String} event (optional) - * @param {Function} callback - * @return {Hook.Channel} - * - * @example Registering for a single custom event - * - * channel.subscribe('some-event', function(data) { - * console.log("Custom event triggered: ", data); - * }) - * - * @example Registering for client connected/disconnected events - * - * channel.subscribe('connected', function(data) { - * console.log("New client connected: ", data.client_id); - * }); - * channel.subscribe('disconnected', function(data) { - * console.log("Client disconnected: ", data.client_id); - * }); - * - */ -Hook.Channel.WEBSOCKETS.prototype.subscribe = function(event, callback) { - if (!this.ws) { - // not connected yet, let's postpone this subscription. - this.queued_subscriptions[event] = callback; - - } else { - this.ws.subscribe(this.collection.name + '.' + event, function(topic, data) { - callback(data); - }); - } - return this; -}; - -/** - * Is EventSource listenning to messages? - * @method isConnected - * @return {Boolean} - */ -Hook.Channel.WEBSOCKETS.prototype.isConnected = function() { - return this.ws && this.ws._websocket_connected; -}; - -/** - * Unsubscribe to a event listener - * @method unsubscribe - * @param {String} event - * @return {Hook.Channel} - */ -Hook.Channel.WEBSOCKETS.prototype.unsubscribe = function(event) { - if (this.ws && this.ws._subscriptions[this.collection.name + '.' + event]) { - this.ws.unsubscribe(this.collection.name + '.' + event); - } - return this; -}; - -/** - * Publish event message - * @method publish - * @param {String} event - * @param {Object} message - * @param {Object} options 'exclude' and 'elegible' are optional options. - * @return {Hook.Channel} - */ -Hook.Channel.WEBSOCKETS.prototype.publish = function(event, message, options) { - var exclude = [], eligible = []; - - if (typeof(options)==="undefined") { - options = {}; - } - - if (options.exclude && options.exclude instanceof Array) { - exclude = options.exclude; - } - - if (options.eligible && options.eligible instanceof Array) { - eligible = options.eligible; - } - - this.ws.publish(this.collection.name + '.' + event, message, exclude, eligible); - return this; -}; - -/** - * Disconnect from channel, publishing a 'disconnected' message. - * @method disconnect - * @return {Hook.Channel} this - */ -Hook.Channel.WEBSOCKETS.prototype.disconnect = function() { - this.ws.close(); - return this; -}; - -/** - * @method call - * @param {String} procedure - * @return {Promise} - */ -Hook.Channel.WEBSOCKETS.prototype.call = function(procedure, callbacks) { - this.ws.call(procedure, callbacks); - return this; -}; -Hook.Channel.WEBSOCKETS.prototype.connect = function() { - this.ws.connect(); - return this; -}; diff --git a/src/collection.js b/src/collection.js deleted file mode 100644 index 9c7b0f4..0000000 --- a/src/collection.js +++ /dev/null @@ -1,744 +0,0 @@ -/** - * @module Hook - * @class Hook.Collection - * - * @param {Hook.Client} client - * @param {String} name - * @constructor - */ -Hook.Collection = function(client, name) { - this.client = client; - - this.name = this._validateName(name); - this.reset(); - - this.segments = 'collection/' + this.name; -}; - -// Inherits from Hook.Iterable -Hook.Collection.prototype = new Hook.Iterable(); -Hook.Collection.prototype.constructor = Hook.Collection; - -/** - * Create a new resource - * @method create - * @param {Object} data - * @return {Hook.Collection} this - * - * @example Creating an entry - * - * client.collection('posts').create({ - * title: "Post name", - * summary: "My awesome new post", - * stars: 5 - * }); - * - * @example Listening to complete event - * - * // Verbose way - * var c = client.collection('posts'); - * var promise = c.create({ title: "Post name", summary: "Something", stars: 5 }); - * promise.then(function(data) { - * console.log(data); - * }); - * - * // Short way - * client.collection('posts').create({ title: "Post name", summary: "Something", stars: 5 }).then(function(data) { - * console.log(data); - * }); - * - */ -Hook.Collection.prototype.create = function(data) { - this.options.data = data; - return this.client.post(this.segments, this.buildQuery()); -}; - -/** - * Fields that should be retrieved from the database - * @method select - * @return {Hook.Collection} this - */ -Hook.Collection.prototype.select = function() { - this.options.select = arguments; - return this; -}; - -/** - * Get collection data, based on `where` params. - * @method get - * @return {Hook.Collection} this - */ -Hook.Collection.prototype.get = function() { - return this.client.get(this.segments, this.buildQuery()); -}; - -/** - * Add `where` param - * @method where - * @param {Object | String} where params or field name - * @param {String} operation '<', '<=', '>', '>=', '!=', 'in', 'between', 'not_in', 'not_between', 'like', 'not_null' - * @param {String} value value - * @return {Hook.Collection} this - * - * @example Multiple 'where' calls - * - * var c = client.collection('posts'); - * c.where('author','Vicente'); // equal operator may be omitted - * c.where('stars','>',10); // support '<' and '>' operators - * c.then(function(result) { - * console.log(result); - * }); - * - * @example One 'where' call - * - * client.collection('posts').where({ - * author: 'Vicente', - * stars: ['>', 10] - * }).then(function(result) { - * console.log(result); - * }) - * - * @example Filtering 'in' value list. - * - * client.collection('posts').where('author_id', 'in', [500, 501]).then(function(result) { - * console.log(result); - * }) - * - * @example Partial String matching - * - * client.collection('posts').where('author', 'like', '%Silva%').then(function(result) { - * console.log(result); - * }) - * - */ -Hook.Collection.prototype.where = function(objects, _operation, _value, _boolean) { - var field, - operation = (typeof(_value)==="undefined") ? '=' : _operation, - value = (typeof(_value)==="undefined") ? _operation : _value, - boolean = (typeof(_boolean)==="undefined") ? 'and' : _boolean; - - if (typeof(objects)==="object") { - for (field in objects) { - if (objects.hasOwnProperty(field)) { - operation = '='; - if (objects[field] instanceof Array) { - operation = objects[field][0]; - value = objects[field][1]; - } else { - value = objects[field]; - } - this.addWhere(field, operation, value, boolean); - } - } - } else { - this.addWhere(objects, operation, value, boolean); - } - - return this; -}; - -/** - * Add OR query param - * @method orWhere - * @param {Object | String} where params or field name - * @param {String} operation '<', '<=', '>', '>=', '!=', 'in', 'between', 'not_in', 'not_between', 'like', 'not_null' - * @param {String} value value - * @return {Hook.Collection} this - */ -Hook.Collection.prototype.orWhere = function(objects, _operation, _value) { - return this.where(objects, _operation, _value, "or"); -}; - -/** - * Find first item by _id - * @method find - * @param {Number} _id - * @param {Function} callback [optional] - * @return {Promise} - * - * @example Finding first item by _id, with 'success' callback as param. - * - * client.collection('posts').find(50, function(data) { - * console.log("Row:", data); - * }); - * - * @example Catching 'not found' error. - * - * client.collection('posts').find(128371923).then(function(data) { - * console.log("Row:", data); // will never execute this - * }).otherwise(function(e) { - * console.log("Not found."); - * }); - * - */ -Hook.Collection.prototype.find = function(_id) { - var promise = this.client.get(this.segments + '/' + _id, this.buildQuery()); - if (arguments.length > 1) { - return promise.then.apply(promise, Array.prototype.slice.call(arguments,1)); - } - return promise; -}; - -/** - * Set the relationships that should be eager loaded. - * @method join - * @param {String} ... - * @return {Hook.Collection} - * - * @example Simple relationship - * - * client.collection('books').join('author').each(function(book) { - * console.log("Author: ", book.author.name); - * }); - * - * @example Multiple relationships - * - * client.collection('books').join('author', 'publisher').each(function(book) { - * console.log("Author: ", book.author.name); - * console.log("Publisher: ", book.publisher.name); - * }); - * - * @example Nested relationships - * - * client.collection('books').join('author.contacts').each(function(book) { - * console.log("Author: ", book.author.name); - * console.log("Contacts: ", book.author.contacts); - * }); - * - */ -Hook.Collection.prototype.join = function() { - this.options['with'] = arguments; - return this; -}; - - -/** - * The 'distinct' can be used to return only distinct (different) values. - * @method distinct - * @param {String} field - * @param {String} ... more fields - * @return {Hook.Collection} this - */ -Hook.Collection.prototype.distinct = function() { - this.options.distinct = true; - return this; -}; - -/** - * Group results by field - * @method group - * @param {String} field - * @param {String} ... more fields - * @return {Hook.Collection} this - */ -Hook.Collection.prototype.group = function() { - this._group = arguments; - return this; -}; - -/** - * Count the number of items on this collection - * @method count - * @param {Function} callback [optional] - * @return {Promise} - * - * @example Count the elements of the current query - * - * client.collection('posts').where('author','Vicente').count(function(total) { - * console.log("Total:", total); - * }); - */ -Hook.Collection.prototype.count = function(field) { - field = (typeof(field)==="undefined") ? '*' : field; - this.options.aggregation = {method: 'count', field: field}; - var promise = this.get(); - if (arguments.length > 0) { - promise.then.apply(promise, arguments); - } - return promise; -}; - -/** - * Aggregate field with 'max' values - * @method max - * @param {String} field - * @param {Function} callback [optional] - * @return {Promise} - * - * @example Get the max value from highscore collection - * - * client.collection('highscore').max('score', function(data) { - * console.log("max: ", data); - * }); - */ -Hook.Collection.prototype.max = function(field) { - this.options.aggregation = {method: 'max', field: field}; - var promise = this.get(); - if (arguments.length > 1) { - promise.then.apply(promise, Array.prototype.slice.call(arguments,1)); - } - return promise; -}; - -/** - * Aggregate field with 'min' values - * @method min - * @param {String} field - * @param {Function} callback [optional] - * @return {Promise} - * - * @example Get the min value from highscore collection - * - * client.collection('highscore').min('score', function(data) { - * console.log("min: ", data); - * }); - */ -Hook.Collection.prototype.min = function(field) { - this.options.aggregation = {method: 'min', field: field}; - var promise = this.get(); - if (arguments.length > 1) { - promise.then.apply(promise, Array.prototype.slice.call(arguments,1)); - } - return promise; -}; - -/** - * Aggregate field with 'avg' values - * @method avg - * @param {String} field - * @param {Function} callback [optional] - * @return {Promise} - * - * @example Get the average value from highscore collection - * - * client.collection('highscore').avg('score', function(data) { - * console.log("avg: ", data); - * }); - */ -Hook.Collection.prototype.avg = function(field) { - this.options.aggregation = {method: 'avg', field: field}; - var promise = this.get(); - if (arguments.length > 1) { - promise.then.apply(promise, Array.prototype.slice.call(arguments,1)); - } - return promise; -}; - -/** - * Aggregate field with 'sum' values - * @method sum - * @param {String} field - * @param {Function} callback [optional] - * @return {Promise} - * - * @example Get the sum value from highscore collection - * - * client.collection('highscore').sum('score', function(data) { - * console.log("sum: ", data); - * }); - */ -Hook.Collection.prototype.sum = function(field) { - this.options.aggregation = {method: 'sum', field: field}; - var promise = this.get(); - if (arguments.length > 1) { - promise.then.apply(promise, Array.prototype.slice.call(arguments,1)); - } - return promise; -}; - -/** - * Query only the first result - * @method first - * @param {Function} callback [optional] - * @return {Promise} - * - * @example Return just the first element for current query - * - * client.collection('users').sort('created_at', -1).first(function(data) { - * console.log("Last created user:", data); - * }); - */ -Hook.Collection.prototype.first = function() { - this.options.first = 1; - var promise = this.get(); - promise.then.apply(promise, arguments); - return promise; -}; - -/** - * First or create - * - * @method firstOrCreate - * @param {Object} data - * @param {Function} callback - * @return {Promise} - * - * example Return the first match for 'data' param, or create it. - * - * client.collection('uniques').firstOrCreate({type: "something"}).then(function(data) { - * console.log("Unique row: ", data); - * }); - */ -Hook.Collection.prototype.firstOrCreate = function(data) { - this.options.first = 1; - this.options.data = data; - return this.client.post(this.segments, this.buildQuery()); -}; - -/** - * Alias for get & then - * @method then - * @return {Promise} - */ -Hook.Collection.prototype.then = function() { - var promise = this.get(); - promise.then.apply(promise, arguments); - return promise; -}; - -/** - * Alias for then & console.log.bind(console) - * @method debug - * @return {Promise} - */ -Hook.Collection.prototype.debug = function(func) { - func = (typeof(func) == "undefined") ? "log" : func; - return this.then(console[func].bind(console)); -}; - -/** - * Clear collection filtering state - * @method reset - * @return {Hook.Collection} this - */ -Hook.Collection.prototype.reset = function() { - this.options = {}; - this.wheres = []; - this.ordering = []; - this._group = []; - this._limit = null; - this._offset = null; - this._remember = null; - return this; -}; - -/** - * @method sort - * @param {String} field - * @param {Number|String} direction - * @return {Hook.Collection} this - * - * @example Return just the first element for current query - * - * // Ommit the second argument for ascending order: - * client.collection('users').sort('created_at').then(function(data){ }); - * - * // Use 1 or 'asc' to specify ascending order: - * client.collection('users').sort('created_at', 1).then(function(data){ }); - * client.collection('users').sort('created_at', 'asc').then(function(data){ }); - * - * // Use -1 or 'desc' for descending order: - * client.collection('users').sort('created_at', -1).then(function(data) { }); - * client.collection('users').sort('created_at', 'desc').then(function(data) { }); - */ -Hook.Collection.prototype.sort = function(field, direction) { - if (!direction) { - direction = "asc"; - } else if (typeof(direction)==="number") { - direction = (parseInt(direction, 10) === -1) ? 'desc' : 'asc'; - } - this.ordering.push([field, direction]); - return this; -}; - -/** - * @method limit - * @param {Number} int - * @return {Hook.Collection} this - * - * @example Limit the number of rows to retrieve - * - * client.collection('posts').sort('updated_at', -1).limit(5).then(function(data) { - * console.log("Last 5 rows updated: ", data); - * }); - * - * @example Limit and offset - * - * client.collection('posts').sort('updated_at', -1).limit(5).offset(5).then(function(data) { - * console.log("last 5 rows updated, after 5 lastest: ", data); - * }); - */ -Hook.Collection.prototype.limit = function(int) { - this._limit = int; - return this; -}; - -/** - * @method offset - * @see limit - * - * @param {Number} int - * @return {Hook.Collection} this - */ -Hook.Collection.prototype.offset = function(int) { - this._offset = int; - return this; -}; - -/** - * Indicate that the query results should be cached. - * - * @method remember - * @param {Number} minutes - * @return {Hook.Collection} this - * - * @example Caching a query - * - * client.collection('posts').sort('updated_at', -1).limit(5).remember(10).then(function(data) { - * // ... - * }); - * - */ -Hook.Collection.prototype.remember = function(minutes) { - this._remember = minutes; - return this; -}; - -/** - * Get channel for this collection. - * @method channel - * @param {Object} options (optional) - * @return {Hook.Channel} - * - * @example Streaming collection data - * - * client.collection('messages').where('type', 'new-game').channel().subscribe(function(event, data) { - * console.log("Received new-game message: ", data); - * }); - * - * client.collection('messages').create({type: 'sad', text: "i'm sad because streaming won't catch me"}); - * client.collection('messages').create({type: 'new-game', text: "yey, streaming will catch me!"}); - * - */ -Hook.Collection.prototype.channel = function(options) { - throw new Error("Not implemented."); - // return new Hook.Channel(this.client, this, options); -}; - -/** - * Drop entire collection. This operation is irreversible. - * @return {Promise} - */ -Hook.Collection.prototype.drop = function() { - return this.client.remove(this.segments); -}; - -/** - * Remove a single row by id - * @method remove - * @param {String} id [optional] - * @return {Promise} - * - * @example Deleting a row by id - * - * client.collection('posts').remove(1).then(function(data) { - * console.log("Success:", data.success); - * }); - * - * @example Deleting multiple rows - * - * client.collection('ranking').where('score', 0).remove().then(function(data) { - * console.log("Success:", data.success); - * }); - */ -Hook.Collection.prototype.remove = function(_id) { - var path = this.segments; - if (typeof(_id)!=="undefined") { - path += '/' + _id; - } - return this.client.remove(path, this.buildQuery()); -}; - -/** - * Update a single collection entry - * @method update - * @param {Number | String | Object} _id or data - * @param {Object} data or null - * - * @example Updating a single row - * - * client.collection('posts').update(1, { title: "Changing post title" }).then(function(data) { - * console.log("Success:", data.success); - * }); - * - * @example Updating all rows of the collection - * - * client.collection('users').update({category: 'everybody'}).then(function(numRows) { - * console.log(numRows, " users has been updated"); - * }); - * - * @example Updating collection filters - * - * client.collection('users').where('age','<',18).update({category: 'baby'}).then(function(numRows) { - * console.log(numRows, " users has been updated"); - * }); - * - */ -Hook.Collection.prototype.update = function(_id, data) { - if (!data && typeof(_id)==="object") { - this.options.data = _id; - return this.client.put(this.segments, this.buildQuery()); - } else { - console.log(".update(_id, data) method will be deprecated. Please use .update(data) instead."); - return this.client.post(this.segments + '/' + _id, data); - } -}; - -/** - * Increment a value from 'field' from all rows matching current filter. - * @method increment - * @param {String} field - * @param {Number} value - * @return {Promise} - * - * @example Increment user score - * - * client.collection('users').where('_id', user_id).increment('score', 10).then(function(numRows) { - * console.log(numRows, " users has been updated"); - * }); - */ -Hook.Collection.prototype.increment = function(field, value) { - this.options.operation = { method: 'increment', field: field, value: value || 1 }; - var promise = this.client.put(this.segments, this.buildQuery()); - if (arguments.length > 0) { - promise.then.apply(promise, arguments); - } - return promise; -}; - -/** - * Decrement a value from 'field' from all rows matching current filter. - * @method decrement - * @param {String} field - * @param {Number} value - * @return {Promise} - * - * @example Decrement user score - * - * client.collection('users').where('_id', user_id).decrement('score', 10).then(function(numRows) { - * console.log(numRows, " users has been updated"); - * }); - */ -Hook.Collection.prototype.decrement = function(field, value) { - this.options.operation = { method: 'decrement', field: field, value: value || 1 }; - var promise = this.client.put(this.segments, this.buildQuery()); - if (arguments.length > 0) { - promise.then.apply(promise, arguments); - } - return promise; -}; - -/** - * Update all collection's data based on `where` params. - * @method updateAll - * @param {Object} data key-value data to update from matched rows [optional] - * @return {Promise} - * - * @example Updating all rows of the collection - * - * client.collection('users').updateAll({category: 'everybody'}).then(function(numRows) { - * console.log(numRows, " users has been updated"); - * }); - * - * @example Updating collection filters - * - * client.collection('users').where('age','<',18).updateAll({category: 'baby'}).then(function(numRows) { - * console.log(numRows, " users has been updated"); - * }); - */ -Hook.Collection.prototype.updateAll = function(data) { - console.log(".updateAll() method will be deprecated. Please use .update() instead."); - this.options.data = data; - return this.client.put(this.segments, this.buildQuery()); -}; - -Hook.Collection.prototype.addWhere = function(field, operation, value, boolean) { - this.wheres.push([field, operation.toLowerCase(), value, boolean]); - return this; -}; - -Hook.Collection.prototype._validateName = function(name) { - var regexp = /^[a-z_\/0-9]+$/; - - if (!regexp.test(name)) { - throw new Error("Invalid name: " + name); - } - - return name; -}; - -Hook.Collection.prototype.buildQuery = function() { - var query = {}; - - // apply limit / offset and remember - if (this._limit !== null) { query.limit = this._limit; } - if (this._offset !== null) { query.offset = this._offset; } - if (this._remember !== null) { query.remember = this._remember; } - - // apply wheres - if (this.wheres.length > 0) { - query.q = this.wheres; - } - - // apply ordering - if (this.ordering.length > 0) { - query.s = this.ordering; - } - - // apply group - if (this._group.length > 0) { - query.g = this._group; - } - - var f, shortnames = { - paginate: 'p', // pagination (perPage) - first: 'f', // first / firstOrCreate - aggregation: 'aggr', // min / max / count / avg / sum - operation: 'op', // increment / decrement - data: 'data', // updateAll / firstOrCreate - 'with': 'with', // join / relationships - select: 'select', // fields to return - distinct: 'distinct' // use distinct operation - }; - - for (f in shortnames) { - if (this.options[f]) { - query[shortnames[f]] = this.options[f]; - } - } - - // clear wheres/ordering for future calls - this.reset(); - - return query; -}; - -/** - * Return a new copy of the collection. - * @method clone - * @return {Collection} - */ -Hook.Collection.prototype.clone = function() { - var clone = this.client.collection(this.name); - - // copy attributes to the new instance - clone.options = _.clone(this.options); - clone.wheres = _.clone(this.wheres); - clone.ordering = _.clone(this.ordering); - clone._group = _.clone(this._group); - clone._limit = _.clone(this._limit); - clone._offset = _.clone(this._offset); - clone._remember = _.clone(this._remember); - - return clone; -}; diff --git a/src/core/api.js b/src/core/api.js deleted file mode 100644 index c9ae280..0000000 --- a/src/core/api.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @module Hook - */ -var Hook = { - VERSION: "0.3.4", - defaults: { - perPage: 50 - } -}; - -window.Hook = Hook; diff --git a/src/core/client.js b/src/core/client.js deleted file mode 100644 index 4945422..0000000 --- a/src/core/client.js +++ /dev/null @@ -1,391 +0,0 @@ -/** - * Hook.Client is the entry-point for using hook. - * - * You should instantiate a global javascript client for consuming hook. - * - * ```javascript - * var client = new Hook.Client({ - * endpoint: "http://local-or-remote-hook-address.com/public/index.php/", - * app_id: 1, // your application id - * key: 'browser credential' // your hook-ext/credentials/{environment}/browser.json - * }); - * ``` - * - * @module Hook - * @class Hook.Client - * - * @param {Object} options - * @param {String} options.app_id - * @param {String} options.key - * @param {String} options.endpoint default: window.location.origin - * - * @constructor - */ -Hook.Client = function(options) { - if (!options) { options = {}; } - - this.endpoint = options.endpoint || options.url || window.location.origin; - this.app_id = options.app_id || options.appId || ""; - this.key = options.key || ""; - - this.options = (typeof(options.options) !== "undefined") ? options.options : {}; - - // append last slash if doesn't have it - if (this.endpoint.lastIndexOf('/') != this.endpoint.length - 1) { - this.endpoint += "/"; - } - - /** - * @property {Hook.KeyValues} keys - */ - this.keys = new Hook.KeyValues(this); - - /** - * @property {Hook.Auth} auth - */ - this.auth = new Hook.Auth(this); - - /** - * @property {Hook.System} system - */ - this.system = new Hook.System(this); - - // Setup all registered plugins. - Hook.Plugin.Manager.setup(this); -}; - -/** - * Get collection instance. - * @method collection - * @param {String} collectionName - * @return {Hook.Collection} - * - * @example Retrieve a collection reference. Your collection tables are created on demand. - * - * // Users collection - * var users = client.collection('users'); - * - * // Highscores - * var highscores = client.collection('highscores'); - * - */ -Hook.Client.prototype.collection = function(collectionName) { - return new Hook.Collection(this, collectionName); -}; - -/** - * Get channel instance. - * @method channel - * @param {String} name - * @param {Object} options (optional) - * @return {Hook.Channel} - * - * @example Create a channel using Servet-Sent Events transport. - * - * var channel = client.channel('messages'); - * - * @example Create a channel using WebSockets transport. - * - * var channel = client.channel('messages', { transport: "websockets" }); - * - */ -Hook.Client.prototype.channel = function(name, options) { - if (typeof(options)==="undefined") { options = {}; } - - var collection = this.collection(name); - collection.segments = collection.segments.replace('collection/', 'channel/'); - - // Use 'SSE' as default transport layer - if (!options.transport) { options.transport = 'sse'; } - options.transport = options.transport.toUpperCase(); - - return new Hook.Channel[options.transport](this, collection, options); -}; - -/** - * Get remote URL string. - * @method url - * @param {String} route - * @return {String} - * - * @example Downloading data from a hook route - * - * location.href = client.url('download', { something: "hey" }) - * - * @example Using custom hook route for image catpcha - * - * // Implementing custom route for captcha: https://github.com/doubleleft/hook/wiki/Composer-dependencies - * var img = new Image(); - * img.src = client.url('captcha'); - * - */ -Hook.Client.prototype.url = function(route, params) { - var serializedParams = ""; - if (params) { serializedParams = "&" + this.serialize(params); } - return this.endpoint + route + this._getCredentialsParams() + serializedParams; -}; - -/** - * Create resource - * @method post - * @param {String} segments - * @param {Object} data - */ -Hook.Client.prototype.post = function(segments, data) { - if (typeof(data)==="undefined") { - data = {}; - } - return this.request(segments, "POST", data); -}; - -/** - * Retrieve a resource - * @method get - * @param {String} segments - * @param {Object} data - */ -Hook.Client.prototype.get = function(segments, data) { - return this.request(segments, "GET", data); -}; - -/** - * Update existing resource - * @method put - * @param {String} segments - * @param {Object} data - */ -Hook.Client.prototype.put = function(segments, data) { - return this.request(segments, "PUT", data); -}; - -/** - * Delete existing resource. - * @method delete - * @param {String} segments - */ -Hook.Client.prototype.remove = function(segments, data) { - return this.request(segments, "DELETE", data); -}; - -/** - * @method request - * @param {String} segments - * @param {String} method - * @param {Object} data - */ -Hook.Client.prototype.request = function(segments, method, data) { - var payload - , request_headers - , synchronous = false; - - // FIXME: find a better way to write this - if (data && data._sync) { - delete data._sync; - synchronous = true; - } - - // Compute payload - payload = this.getPayload(method, data); - - // Compute request headers - request_headers = this.getHeaders(); - if (!(payload instanceof FormData)){ - request_headers["Content-Type"] = 'application/json'; // exchange data via JSON to keep basic data types - } - - // Use method override? (some web servers doesn't respond to DELETE/PUT requests) - if (method !== "GET" && method !== "POST" && this.options.method_override) { - request_headers['X-HTTP-Method-Override'] = method; - method = "POST"; - } - - if (typeof(XDomainRequest) !== "undefined") { - // XMLHttpRequest#setRequestHeader isn't implemented on Internet Explorer's XDomainRequest - segments += this._getCredentialsParams() + "&r=" + Math.floor(Math.random()*1000); - } - - var promise = new Promise(function(resolve, reject) { - var xhr = uxhr(this.endpoint + segments, payload, { - method: method, - headers: request_headers, - sync: synchronous, - success: function(response) { - var total, - data = null, - // IE<10 doesn't have 'getAllResponseHeaders' method. - responseHeaders = (xhr.getAllResponseHeaders && xhr.getAllResponseHeaders()) || ""; - - try { - data = JSON.parseWithDate(response); - } catch(e) { } - - if (data === false || data === null || data.error) { - // log error on console - if (data && data.error) { console.error(data.error); } - reject(data); - } else { - - // get X-Total-Count for pagination - total = responseHeaders.match(/x-total-count: ([^\n]+)/i); - if (total) { data.total = parseInt(total[1]); } - - resolve(data); - } - }, - error: function(response) { - var data = null; - try { - data = JSON.parseWithDate(response); - } catch(e) { } - console.log("Error: ", data || "Invalid JSON response."); - reject(data); - } - }); - - }.bind(this)); - - return promise; -}; - -/** - * Get XHR headers for app/auth context. - * @method getHeaders - * @return {Object} - */ -Hook.Client.prototype.getHeaders = function() { - // App authentication request headers - var request_headers = { - 'X-App-Id': this.app_id, - 'X-App-Key': this.key - }, auth_token; - - // Forward user authentication token, if it is set - var auth_token = this.auth.getToken(); - if (auth_token) { - request_headers['X-Auth-Token'] = auth_token; - } - return request_headers; -} - -/** - * Get payload of given data - * @method getPayload - * @param {String} requestMethod - * @param {Object} data - * @return {String|FormData} - */ -Hook.Client.prototype.getPayload = function(method, data) { - var payload = null; - if (data) { - - if (data instanceof FormData){ - payload = data; - } else if (method !== "GET") { - var formdata = new FormData(), - worth = false; - - var getFieldName = function(nested) { - var name = nested.shift(); - return (nested.length > 0) ? name + '[' + getFieldName(nested) + ']' : name; - }; - - var appendFormdataRecursively = function(formdata, data, previous) { - var field, value, filename, isFile = false; - - for (field in data) { - value = data[field]; - filename = null; - - if (typeof(value)==='undefined' || value === null) { - continue; - - } else if (typeof(value)==='boolean' || typeof(value)==='number' || typeof(value)==="string") { - value = value.toString(); - - // IE8 can't compare instanceof String with HTMLInputElement. - } else if (value instanceof HTMLInputElement && value.files && value.files.length > 0) { - filename = value.files[0].name; - value = value.files[0]; - worth = true; - isFile = true; - - } else if (value instanceof HTMLInputElement) { - value = value.value; - - } else if (value instanceof HTMLCanvasElement) { - value = dataURLtoBlob(value.toDataURL()); - worth = true; - filename = 'canvas.png'; - - } else if (typeof(Blob) !== "undefined" && value instanceof Blob) { - worth = true; - filename = 'blob.' + value.type.match(/\/(.*)/)[1]; // get extension from blob mime/type - - } else if (typeof(value)==="object") { - appendFormdataRecursively(formdata, value, previous.concat(field)); - continue; - } - - // - // Consider serialization to keep data types here: http://phpjs.org/functions/serialize/ - // - if (!(value instanceof Array)) { // fixme - var fieldname = (isFile) ? field : getFieldName(previous.concat(field)); - - if (typeof(value)==="string") { - formdata.append(fieldname, value); - } else { - try { - formdata.append(fieldname, value, filename || "file"); - } catch (e) { - // TODO: - // Node.js (CLI console) throws exception here - } - } - } - } - }; - - appendFormdataRecursively(formdata, data, []); - - if (worth) { - payload = formdata; - } - } - - payload = payload || JSON.stringify(data, function(key, value) { - if (this[key] instanceof Date) { - return Math.round(this[key].getTime() / 1000); - } else { - return value; - } - }); - - // empty payload, return null. - if (payload == "{}") { return null; } - - if (method==="GET" && typeof(payload)==="string") { - payload = encodeURIComponent(payload); - } - } - return payload; -} - -Hook.Client.prototype._getCredentialsParams = function() { - var params = "?X-App-Id=" + this.app_id + "&X-App-Key=" + this.key; - var auth_token = this.auth.getToken(); - if (auth_token) { params += '&X-Auth-Token=' + auth_token; } - return params; -} - -Hook.Client.prototype.serialize = function(obj, prefix) { - var str = []; - for (var p in obj) { - if (obj.hasOwnProperty(p)) { - var k = prefix ? prefix + "[" + p + "]" : p, - v = obj[p]; - str.push(typeof v == "object" ? this.serialize(v, k) : encodeURIComponent(k) + "=" + encodeURIComponent(v)); - } - } - return str.join("&"); -}; diff --git a/src/core/events.js b/src/core/events.js deleted file mode 100644 index 661bc71..0000000 --- a/src/core/events.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @class Hook.Events - */ -Hook.Events = function() { - this._events = {}; -}; - -Hook.Events.prototype.on = function(event, callback, context) { - if (!this._events[event]) { this._events[event] = []; } - this._events[event].push({callback: callback, context: context || this}); -}; - -Hook.Events.prototype.trigger = function(event, data) { - var c, args = Array.prototype.slice.call(arguments,1); - if (this._events[event]) { - for (var i=0,length=this._events[event].length;i 0 ) { - self._registerDevice(e.regid); - } - }); - - function successHandler(result) { - console.log("successHandler"); - // on iOS devices, result is the token - if (device.platform.match(/ios/i)) { - self._registerDevice(result); - } - } - - function errorHandler(error) { - console.log("errorHandler"); - console.log("Error: " + error); - } - - // Handle notification - function onNotification(e) { - // trigger generic notification - self.trigger('notification', e); - - if (device.platform.match(/ios/i)) { - if (e.alert) { - navigator.notification.alert(e.alert); - } - - if (e.sound) { - var snd = new Media(e.sound); - snd.play(); - } - - if (e.badge) { - notificationPlugin.setApplicationIconBadgeNumber(successHandler, e.badge); - } - - return; - } - - // trigger event - if (e.event) { - self.trigger(event, e); - } - - if (e.event == "message") { - // if this flag is set, this notification happened while we were in the foreground. - // you might want to play a sound to get the user's attention, throw up a dialog, etc. - if (e.foreground) { - // on Android soundname is outside the payload. - // On Amazon FireOS all custom attributes are contained within payload - var soundfile = e.soundname || e.payload.sound; - // if the notification contains a soundname, play it. - var my_media = new Media("/android_asset/www/"+ soundfile); - - my_media.play(); - - } else { - - // otherwise we were launched because the user touched a notification in the notification tray. - if (e.coldstart) { - // COLDSTART NOTIFICATION - } else { - // BACKGROUND NOTIFICATION - } - } - - // e.payload.message - - // (android only) - // e.payload.msgcnt - - // (amazon-fireos only) - // e.payload.timeStamp - } - - } - - // Android options - // {"senderID":"1013943151641","ecb":"onNotification"} - - // iOS options - // {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"} - - console.log("will register for notifications..."); - console.log("options: " + JSON.stringify(registerOptions)); - - // required - notificationPlugin.register(successHandler, errorHandler, registerOptions); - console.log("registered."); - - return this; -}; - -/** - * Unregister device for Push Notifications - * @method unregister - */ -Hook.Plugin.Cordova.PushNotification.prototype.unregister = function(options) { -}; - -/** - * method _registerDevice - */ -Hook.Plugin.Cordova.PushNotification.prototype._registerDevice = function(id) { - console.log("_registerDevice: " + id); - - this.client.post('push/registration', { - device_id: id, - app_name: this.appVersion, - app_version: this.appVersion, - platform: device.platform.toLowerCase() - }); -}; diff --git a/src/system.js b/src/system.js deleted file mode 100644 index 177facc..0000000 --- a/src/system.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @module Hook - * @class Hook.System - * - * @param {Client} client - * @constructor - */ -Hook.System = function(client) { - this.client = client; -}; - -/** - * Return server's system time. - * @method time - * @return {Promise} - */ -Hook.System.prototype.time = function() { - var promise = this.client.get('system/time'); - if (arguments.length > 0) { - promise.then.apply(promise, arguments); - } - return promise; -}; diff --git a/src/wrap/begin.js b/src/wrap/begin.js deleted file mode 100644 index f67bf91..0000000 --- a/src/wrap/begin.js +++ /dev/null @@ -1 +0,0 @@ -(function(window) { diff --git a/src/wrap/end.js b/src/wrap/end.js deleted file mode 100644 index 7773a74..0000000 --- a/src/wrap/end.js +++ /dev/null @@ -1 +0,0 @@ -})(window); diff --git a/tests/api.js b/tests/api.js deleted file mode 100644 index 313d687..0000000 --- a/tests/api.js +++ /dev/null @@ -1,5 +0,0 @@ -test("API", function() { - ok( client.endpoint == "http://hook.dev/index.php/", "endpoint OK"); - ok( client.app_id == appData.keys[1].app_id, "'app_id' OK"); - ok( client.key == appData.keys[1].key, "'secret' OK"); -}); diff --git a/tests/app.json b/tests/app.json deleted file mode 100644 index b08137d..0000000 --- a/tests/app.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"hook-javascript-test","secret":"9be410a9a5f2c7ff545ce537d5c299c3","updated_at":"2015-05-22T17:02:01-03:00","created_at":"2015-05-22T17:02:01-03:00","_id":39,"keys":[{"_id":"153","app_id":"39","key":"a62f11923c2f1adc2b9f85dc4f78c57f","type":"cli","deleted_at":null,"created_at":"2015-05-22T17:02:01-03:00","updated_at":"2015-05-22T17:02:01-03:00"},{"_id":"154","app_id":"39","key":"67b6921d8ceb4eb1d7263e9c7df529ca","type":"browser","deleted_at":null,"created_at":"2015-05-22T17:02:01-03:00","updated_at":"2015-05-22T17:02:01-03:00"},{"_id":"155","app_id":"39","key":"90dc29fe7f49785d816ea4fbf829886b","type":"device","deleted_at":null,"created_at":"2015-05-22T17:02:01-03:00","updated_at":"2015-05-22T17:02:01-03:00"},{"_id":"156","app_id":"39","key":"cfee5fb8b7f8301bb3830d54a008c320","type":"server","deleted_at":null,"created_at":"2015-05-22T17:02:01-03:00","updated_at":"2015-05-22T17:02:01-03:00"}]} \ No newline at end of file diff --git a/tests/auth/email.js b/tests/auth/email.js deleted file mode 100644 index bbb9521..0000000 --- a/tests/auth/email.js +++ /dev/null @@ -1,24 +0,0 @@ -asyncTest("Auth: register by email", function() { - expect(3); - - var email = ascii_rand(8) + "@" + ascii_rand(5) + ".com"; - - client.auth.register({ - email: email, - name: "Endel Dreyer", - password: "teste" - - }).then(function(response) { - ok(client.auth.currentUser.email == email, "currentUser.email"); - ok(client.auth.currentUser.name == "Endel Dreyer", "currentUser.name"); - // ok(client.auth.currentUser.password == "teste", "currentUser.password"); - - client.auth.logout(); - ok(client.auth.currentUser == null, "logout"); - - }).done(function() { - start(); - - }); - -}); diff --git a/tests/auth/email_login.js b/tests/auth/email_login.js deleted file mode 100644 index 85b1056..0000000 --- a/tests/auth/email_login.js +++ /dev/null @@ -1,63 +0,0 @@ -asyncTest("Authentication: Email login (success)", function() { - expect(4); - - // register dummy user first - var email = ascii_rand(8) + "@" + ascii_rand(5) + ".com"; - client.auth.register({ - email: email, - name: "Endel Dreyer", - password: "teste" - }).done(function() { - - client.auth.logout(); - ok(client.auth.currentUser == null, "should have clean session before login"); - - // test for successful login - client.auth.login({ - email: email, - name: "Endel Dreyer", - password: "teste" - }).then(function(response) { - ok(client.auth.currentUser.email == email, "currentUser.email"); - ok(client.auth.currentUser.name == "Endel Dreyer", "currentUser.name"); - - client.auth.logout(); - ok(client.auth.currentUser == null, "logout"); - - }).done(function() { - start(); - }); - - }); -}); - -asyncTest("Authentication: Email login (error)", function() { - expect(1); - - // register dummy user first - var email = ascii_rand(8) + "@" + ascii_rand(5) + ".com"; - client.auth.register({ - email: email, - name: "Endel Dreyer", - password: "teste" - }).done(function() { - - var promise = client.auth.login({ - email: "edreyer@doubleleft.com", - name: "Endel Dreyer", - password: "i'm using the wrong password here" - }).then(function(response) { - ok(false, "shouldn't login with invalid password"); - start(); - - }, function(response) { - ok(typeof(response.error)=="string", "Password invalid"); - - }).done(function() { - start(); - }); - - - }); - -}); diff --git a/tests/auth/facebook.js b/tests/auth/facebook.js deleted file mode 100644 index 490e110..0000000 --- a/tests/auth/facebook.js +++ /dev/null @@ -1,18 +0,0 @@ -// asyncTest("Authentication: Facebook", function() { -// expect(4); -// -// FB.login(function(response) { -// data = response.authResponse; -// data.additional_field = "It's possible to add new fields when registering with facebook."; -// client.auth.register('facebook', data).then(function(userdata) { -// FB.api('/me', function(me) { // match registered data with actual user info -// ok(client.auth.currentUser.email == me.email, "currentUser.email"); -// ok(client.auth.currentUser.name == me.name, "currentUser.name"); -// ok(client.auth.currentUser.additional_field == data.additional_field, "additional_field should be saved"); -// client.auth.logout(); -// ok(client.auth.currentUser == null, "logout"); -// start(); -// }); -// }); -// }, {scope: 'email'}); -// }); diff --git a/tests/auth/forgot_password.js b/tests/auth/forgot_password.js deleted file mode 100644 index 576098f..0000000 --- a/tests/auth/forgot_password.js +++ /dev/null @@ -1,45 +0,0 @@ -asyncTest("Authentication: Forgot password (send)", function() { - expect(1); - - var email = ascii_rand(8) + "@" + ascii_rand(5) + ".com"; - - // register dummy user - client.auth.register({ - email: email, - name: "Endel Dreyer", - password: "teste" - }).then(function(response) { - client.auth.logout(); - - // test forgot password - client.auth.forgotPassword({ - subject: "Project name: Forgot your password?", - email: email, - }).then(function(data) { - ok(true); - }, function(data) { - ok(false, data.error); - }).done(function() { - start(); - }); - - }); - -}); - -asyncTest("Authentication: Forgot password (user not found)", function() { - expect(1); - - // test forgot password - client.auth.forgotPassword({ - subject: "Project name: Forgot your password?", - email: "somebody@inexistent.com", - }).then(function(data) { - ok(false); - }, function(data) { - ok(typeof(data.error)==="string", "Should return 'user not found' error."); - }).done(function() { - start(); - }); - -}); diff --git a/tests/channels/sse.js b/tests/channels/sse.js deleted file mode 100644 index 9e51980..0000000 --- a/tests/channels/sse.js +++ /dev/null @@ -1,14 +0,0 @@ -asyncTest("Channels: Server-Sent Events", function() { - expect(2); - - var messages = client.channel('messages'); - messages.subscribe(function(event, message) { - // console.log("message: ", event, message) - }).then(function() { - messages.publish('event-name', { - data: 'message-data' - }); - }); - - -}); diff --git a/tests/client.js b/tests/client.js deleted file mode 100644 index a7e1ec1..0000000 --- a/tests/client.js +++ /dev/null @@ -1,16 +0,0 @@ -test("Client: getPayload", function() { - var payload, data; - - payload = client.getPayload("GET", {}); - ok(payload == null, "empty payload should return null"); - - payload = client.getPayload("GET", {name: "it's a string"}); - ok(payload == "%7B%22name%22%3A%22it's%20a%20string%22%7D", "string on payloads"); - - payload = client.getPayload("GET", {integer: 100}); - ok(payload == "%7B%22integer%22%3A100%7D", "integer on payloads"); - - var date = new Date(); - payload = client.getPayload("GET", {date: date}); - ok(payload == "%7B%22date%22%3A"+Math.round(date.getTime() / 1000)+"%7D", "dates should be converted to timestamps on payload"); -}); diff --git a/tests/collections/basic.js b/tests/collections/basic.js deleted file mode 100644 index db3547b..0000000 --- a/tests/collections/basic.js +++ /dev/null @@ -1,83 +0,0 @@ -asyncTest("Collections: create", function() { - expect(1); - - // - // Create - // - client.collection('posts').create({title: "My awesome blog post", content: "Lorem ipsum dolor sit amet."}).then(function(response) { - ok(response.title == "My awesome blog post", "CREATE"); - }).otherwise(function(response) { - ok(false, "CREATE first row"); - }).done(function() { - start(); - }); -}); - -asyncTest("Collections: exception", function() { - expect(1); - - // - // Create - // - client.collection('posts').then(function() { - start(); - try { - throw new Error("woops!"); - } catch (e) { - ok(true, "error handled successfully") - return; - } - ok(false, "can't handle error"); - }) -}); - -asyncTest("Collections: create with data types", function() { - expect(4); - - client.collection('posts').create({string: "Another post", int: 5, float: 9.9, bool: true}).then(function(response) { - ok(response.string == "Another post", "CREATE keep string data-type"); - ok(response.int == 5, "CREATE keep integer data-type"); - ok(response.float == 9.9, "CREATE keep float data-type"); - ok(response.bool === true, "CREATE keep boolean data-type"); - }).otherwise(function(response) { - ok(false, "CREATE with more fields"); - }).done(function() { - start(); - }); -}); - -asyncTest("Collections: listing without where", function() { - // - // Get without where - // - client.collection('posts').get().then(function(response) { - ok(response.length > 0, "LIST WITHOUT where"); - }).otherwise(function(response) { - ok(false, "LIST WITHOUT where"); - }).done(function() { - start(); - }); - -}); - -asyncTest("Collections: firstOrCreate", function() { - // - // Get without where - // - client.collection('posts').firstOrCreate({title: "First or create"}).then(function(response) { - ok(response.title === "First or create", "firstOrCreate should create an entry"); - - var previousId = response._id; - - client.collection('posts').firstOrCreate({title: "First or create"}).then(function(response) { - ok(response._id === previousId, "firstOrCreate should find already created item"); - }).otherwise(function(response) { - ok(false, "couldn't find existing item"); - }).done(function() { - start(); - }); - - }).otherwise(function(response) { - ok(false, "couldn't create"); - }); -}); diff --git a/tests/collections/internals.js b/tests/collections/internals.js deleted file mode 100644 index 832f415..0000000 --- a/tests/collections/internals.js +++ /dev/null @@ -1,51 +0,0 @@ -test("Collection: Internal behaviour", function() { - var posts = client.collection('posts'); - - // - // Wheres combinations - // - var past_date = (new Date()).getTime() - 24 * 60 * 60; - posts.where('name', 'My awesome blog post'); - ok(posts.wheres.length==1, "where() field,value"); - - posts.where('created_at', '>', past_date); - ok(posts.wheres.length == 2, "where() field,operation,value"); - ok(posts.wheres[1][1] == ">", "where() field,operation,value"); - - posts.reset(); - ok(posts.wheres.length == 0, "reset()"); - - posts.where({ - name: "My awesome blog post", - created_at: ['>', past_date], - }); - - ok(posts.wheres.length == 2, "where() object, test length"); - ok(posts.wheres[0][0] == "name", "where() object, test first field"); - ok(posts.wheres[0][1] == "=", "where() object, test first operation"); - ok(posts.wheres[0][2] == "My awesome blog post", "where() object, test first value"); - - ok(posts.wheres[1][0] == "created_at", "where() object, test second field"); - ok(posts.wheres[1][1] == ">", "where() object, test second operation"); - ok(posts.wheres[1][2] == past_date, "where() object, test second value"); - - posts.sort('default'); - ok(posts.ordering[0][0] == 'default', "sort(), default field asc"); - ok(posts.ordering[0][1] == 'asc', "sort(), default orientation asc"); - - posts.sort('field', 1); - ok(posts.ordering[1][0] == 'field', "sort(), field asc"); - ok(posts.ordering[1][1] == 'asc', "sort(), orientation asc"); - - posts.sort('field2', -1); - ok(posts.ordering[2][0] == 'field2', "sort(), field desc"); - ok(posts.ordering[2][1] == 'desc', "sort(), orientation desc"); - - posts.sort('field3', 'desc'); - ok(posts.ordering[3][0] == 'field3', "sort(), field desc"); - ok(posts.ordering[3][1] == 'desc', "sort(), orientation desc"); - - posts.sort('field4', 'asc'); - ok(posts.ordering[4][0] == 'field4', "sort(), field asc"); - ok(posts.ordering[4][1] == 'asc', "sort(), orientation asc"); -}); diff --git a/tests/collections/relationship.js b/tests/collections/relationship.js deleted file mode 100644 index 413c9cf..0000000 --- a/tests/collections/relationship.js +++ /dev/null @@ -1,9 +0,0 @@ -// asyncTest("Collection: Querying relationships", function() { -// client.collection('posts').join('author').then(function(posts) { -// for (var i=0; i < posts.length; i++) { -// posts[i].author -// } -// }).done(function() { -// start(); -// }); -// }); diff --git a/tests/collections/upload_base64.js b/tests/collections/upload_base64.js deleted file mode 100644 index 01d9bab..0000000 --- a/tests/collections/upload_base64.js +++ /dev/null @@ -1,17 +0,0 @@ -asyncTest("Files: uploading base64-encoded files with collections", function() { - var attached_files = client.collection('attached_files'); - - $.get('fixtures/base64_jpg.txt').then(function(base64) { - attached_files.create({ - file: "data:image/jpeg;base64," + base64 - }).then(function(data) { - ok(data.file.match(/\.jpeg$/)[0] === ".jpeg"); - ok(data.file_id >= 0, "file_id should be present"); - - }).done(function() { - start(); - - }); - - }) -}); diff --git a/tests/collections/upload_input.js b/tests/collections/upload_input.js deleted file mode 100644 index ff9b68d..0000000 --- a/tests/collections/upload_input.js +++ /dev/null @@ -1,27 +0,0 @@ -asyncTest("Files: uploading with input[type=file]", function() { - var attached_files = client.collection('attached_files'); - - $('body').append($('')); - $('body').append($('')); - - $('body').append($('')); - - $('#letstest').click(function() { - attached_files.create({ - file_1: $('#upload_input_file_1').get(0), - file_2: $('#upload_input_file_2').get(0) - }).then(function(data) { - ok(data.file_1.match(/\.pdf/)[0] === ".pdf"); - ok(data.file_1_id >= 0, "file_1_id should be present"); - - ok(data.file_2.match(/\.pdf/)[0] === ".pdf"); - ok(data.file_2_id >= 0, "file_1_id should be present"); - - }).done(function() { - start(); - - }); - }) - -}); - diff --git a/tests/fixtures/base64_jpg.txt b/tests/fixtures/base64_jpg.txt deleted file mode 100644 index 7f2420a..0000000 --- a/tests/fixtures/base64_jpg.txt +++ /dev/null @@ -1 +0,0 @@ -/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABLAAD/4QNxaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6Rjc3RjExNzQwNzIwNjgxMThEQkJFOTkxOTAxQzNCMDciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTM0MUQxRDU2MjM4MTFFMkI5ODdGQjlCOEQ1RUM5NjciIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTM0MUQxRDQ2MjM4MTFFMkI5ODdGQjlCOEQ1RUM5NjciIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg1RkE0MDc4MEYyMDY4MTFBODZFRjE0MEFBNzQxM0RFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkY3N0YxMTc0MDcyMDY4MTE4REJCRTk5MTkwMUMzQjA3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv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 diff --git a/tests/fixtures/doubleleft.png b/tests/fixtures/doubleleft.png deleted file mode 100644 index 60130d2..0000000 Binary files a/tests/fixtures/doubleleft.png and /dev/null differ diff --git a/tests/fixtures/image.jpg b/tests/fixtures/image.jpg deleted file mode 100644 index d2e6acb..0000000 Binary files a/tests/fixtures/image.jpg and /dev/null differ diff --git a/tests/formdata.html b/tests/formdata.html deleted file mode 100644 index 66b94a4..0000000 --- a/tests/formdata.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - tests - formdata - - - - - -
    - - - - - - - -
    - - - - - - - -
    - - - - diff --git a/tests/index.html b/tests/index.html deleted file mode 100644 index e6a8ba7..0000000 --- a/tests/index.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - hook-javascript tests - - - - - - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/key_value.js b/tests/key_value.js deleted file mode 100644 index 52ea410..0000000 --- a/tests/key_value.js +++ /dev/null @@ -1,23 +0,0 @@ -asyncTest("Key-value: set", function() { - expect(1); - - client.keys.set('something', 'data').then(function(data) { - ok(data == "data", "SET"); - }).done(function() { - start(); - }); - -}); - -asyncTest("Key-value: get", function() { - expect(1); - - client.keys.get('something').then(function(data) { - ok(true, "GET"); - }).done(function() { - start(); - }); - - -}); - diff --git a/tests/pagination.js b/tests/pagination.js deleted file mode 100644 index ca905fd..0000000 --- a/tests/pagination.js +++ /dev/null @@ -1,23 +0,0 @@ -asyncTest("Pagination", function() { - expect(7); - - var posts = client.collection('posts'); - posts.sort('created_at', -1); - - posts.paginate(function(pagination) { - console.log(data); - - ok(pagination.isFetching() == false, "is fetching"); - ok(pagination.per_page === 50, "per_page"); - ok(pagination.current_page === 1, "current_page"); - ok(pagination.last_page >= 1, "last_page"); - ok(pagination.from == 1, "from"); - ok(pagination.to >= 1, "to"); - ok(pagination.data.length > 0, "data"); - - start(); - }, function(error) { - console.log(error); - }); -}); - diff --git a/tests/plugins/backbone.collection.js b/tests/plugins/backbone.collection.js deleted file mode 100644 index 6d6c573..0000000 --- a/tests/plugins/backbone.collection.js +++ /dev/null @@ -1,21 +0,0 @@ -asyncTest("Plugin: Backbone.HookCollection", function() { - expect(1); - - Backbone.hook = client; - - var Post = Backbone.HookModel.extend({name: 'posts'}); - var PostCollection = Backbone.HookCollection.extend({ - model: Post, - getLast: function() { - this.remote.sort('created_at', -1).limit(5); - this.fetchRemote(); - } - }); - - var posts = new PostCollection(); - posts.on('fetch', function(collection, response, options) { - ok(collection); - start(); - }); - posts.getLast(); -}); diff --git a/tests/plugins/backbone.model.js b/tests/plugins/backbone.model.js deleted file mode 100644 index edc2422..0000000 --- a/tests/plugins/backbone.model.js +++ /dev/null @@ -1,18 +0,0 @@ -asyncTest("Plugin: Backbone.HookModel", function() { - expect(1); - - Backbone.hook = client; - - var Post = Backbone.HookModel.extend({name: "posts"}); - var entry = new Post({ - title: "I'm a Backbone model", - content: "Syncing with hook." - }); - - entry.on('created', function(model) { - ok(model.attributes.title == "I'm a Backbone model", "callback on 'created'"); - start(); - }); - - entry.save(); -}); diff --git a/tests/system.js b/tests/system.js deleted file mode 100644 index 17cfe34..0000000 --- a/tests/system.js +++ /dev/null @@ -1,15 +0,0 @@ -asyncTest("System", function() { - expect(1); - - client.system.time(function(response) { - ok(true); - // var localTime = Math.floor((new Date().getTime()) / 1000); - // ok(response === localTime); - - }).done(function() { - start(); - }); - -}); - -