mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-11-08 23:25:51 +01:00
Conflicts: lib/config.js lib/config_def.yaml lib/index.js lib/local-storage.js lib/storage.js package.json
This commit is contained in:
commit
4f913f2468
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,10 +1,12 @@
|
||||
node_modules
|
||||
package.json
|
||||
npm-debug.log
|
||||
sinopia-*.tgz
|
||||
.DS_Store
|
||||
|
||||
###
|
||||
bin/storage*
|
||||
bin/htpasswd
|
||||
bin/*.yaml
|
||||
test-storage*
|
||||
|
||||
example
|
||||
|
39
Gruntfile.js
Normal file
39
Gruntfile.js
Normal file
@ -0,0 +1,39 @@
|
||||
module.exports = function(grunt) {
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
browserify: {
|
||||
dist: {
|
||||
files: {
|
||||
'lib/static/main.js': ['lib/GUI/js/main.js']
|
||||
},
|
||||
options: {
|
||||
debug: true,
|
||||
transform: ['browserify-handlebars']
|
||||
}
|
||||
}
|
||||
},
|
||||
less: {
|
||||
dist: {
|
||||
files: {
|
||||
'lib/static/main.css': ['lib/GUI/css/main.less']
|
||||
},
|
||||
options: {
|
||||
sourceMap: true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: [ "lib/GUI/**/*"],
|
||||
tasks: [ 'default' ]
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-browserify');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-contrib-less');
|
||||
|
||||
grunt.registerTask('default', [
|
||||
'browserify',
|
||||
'less'
|
||||
]);
|
||||
};
|
19
README.md
19
README.md
@ -44,6 +44,8 @@ $ npm set always-auth true
|
||||
$ npm set ca null
|
||||
```
|
||||
|
||||
Now you can navigate to [http://localhost:4873/](http://localhost:4873/) where your local packages will be listed and can be searched.
|
||||
|
||||
### Docker
|
||||
|
||||
A Sinopia docker image [is available](https://index.docker.io/u/keyvanfatehi/docker-sinopia/)
|
||||
@ -58,20 +60,15 @@ A Sinopia puppet module [is available at puppet forge](http://forge.puppetlabs.c
|
||||
|
||||
## Configuration
|
||||
|
||||
When you start a server, it auto-creates a config file that adds one user (password is printed to stdout only once).
|
||||
When you start a server, it auto-creates a config file.
|
||||
|
||||
## Adding a new user
|
||||
|
||||
There is no utility to add a new user but you can at least use node on the command-line to generate a password. You will need to edit the config and add the user manually.
|
||||
|
||||
Start node and enter the following code replacing 'newpass' with the password you want to get the hash for.
|
||||
```bash
|
||||
$ node
|
||||
> crypto.createHash('sha1').update('newpass').digest('hex')
|
||||
'6c55803d6f1d7a177a0db3eb4b343b0d50f9c111'
|
||||
> [CTRL-D]
|
||||
npm adduser --registry http://localhost:4873/
|
||||
```
|
||||
|
||||
This will prompt you for user credentials which will be saved on the Sinopia server.
|
||||
|
||||
## Using private packages
|
||||
|
||||
@ -112,18 +109,18 @@ Basic features:
|
||||
|
||||
Advanced package control:
|
||||
|
||||
- Unpublishing packages (npm unpublish) - not yet supported, should be soon
|
||||
- Unpublishing packages (npm unpublish) - supported
|
||||
- Tagging (npm tag) - not yet supported, should be soon
|
||||
- Deprecation (npm deprecate) - not supported
|
||||
|
||||
User management:
|
||||
|
||||
- Registering new users (npm adduser {newuser}) - not supported, sinopia uses its own acl management system
|
||||
- Registering new users (npm adduser {newuser}) - supported
|
||||
- Transferring ownership (npm owner add {user} {pkg}) - not supported, sinopia uses its own acl management system
|
||||
|
||||
Misc stuff:
|
||||
|
||||
- Searching (npm search) - not supported
|
||||
- Searching (npm search) - supported in the browser client but not command line
|
||||
- Starring (npm star, npm unstar) - not supported, doesn't make sense in private registry
|
||||
|
||||
## Storage
|
||||
|
56
lib/GUI/css/fontello.less
Normal file
56
lib/GUI/css/fontello.less
Normal file
@ -0,0 +1,56 @@
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('../static/fontello.eot?10872183');
|
||||
src: url('../static/fontello.eot?10872183#iefix') format('embedded-opentype'),
|
||||
url('../static/fontello.woff?10872183') format('woff'),
|
||||
url('../static/fontello.ttf?10872183') format('truetype'),
|
||||
url('../static/fontello.svg?10872183#fontello') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||
/*
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('../font/fontello.svg?10872183#fontello') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[class^="icon-"]:before, [class*=" icon-"]:before {
|
||||
font-family: "fontello";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: none;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.icon-search:before { content: '\e801'; } /* '' */
|
||||
.icon-cancel:before { content: '\e803'; } /* '' */
|
||||
.icon-right-open:before { content: '\e802'; } /* '' */
|
||||
.icon-angle-right:before { content: '\e800'; } /* '' */
|
153
lib/GUI/css/highlight.js.less
Normal file
153
lib/GUI/css/highlight.js.less
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
|
||||
Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block; padding: 0.5em;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
.hljs,
|
||||
.hljs-subst,
|
||||
.hljs-tag .hljs-title,
|
||||
.lisp .hljs-title,
|
||||
.clojure .hljs-built_in,
|
||||
.nginx .hljs-title {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-title,
|
||||
.hljs-constant,
|
||||
.hljs-parent,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-rules .hljs-value,
|
||||
.hljs-rules .hljs-value .hljs-number,
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.haml .hljs-symbol,
|
||||
.ruby .hljs-symbol,
|
||||
.ruby .hljs-symbol .hljs-string,
|
||||
.hljs-aggregate,
|
||||
.hljs-template_tag,
|
||||
.django .hljs-variable,
|
||||
.smalltalk .hljs-class,
|
||||
.hljs-addition,
|
||||
.hljs-flow,
|
||||
.hljs-stream,
|
||||
.bash .hljs-variable,
|
||||
.apache .hljs-tag,
|
||||
.apache .hljs-cbracket,
|
||||
.tex .hljs-command,
|
||||
.tex .hljs-special,
|
||||
.erlang_repl .hljs-function_or_atom,
|
||||
.asciidoc .hljs-header,
|
||||
.markdown .hljs-header,
|
||||
.coffeescript .hljs-attribute {
|
||||
color: #800;
|
||||
}
|
||||
|
||||
.smartquote,
|
||||
.hljs-comment,
|
||||
.hljs-annotation,
|
||||
.hljs-template_comment,
|
||||
.diff .hljs-header,
|
||||
.hljs-chunk,
|
||||
.asciidoc .hljs-blockquote,
|
||||
.markdown .hljs-blockquote {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-date,
|
||||
.hljs-regexp,
|
||||
.hljs-literal,
|
||||
.hljs-hexcolor,
|
||||
.smalltalk .hljs-symbol,
|
||||
.smalltalk .hljs-char,
|
||||
.go .hljs-constant,
|
||||
.hljs-change,
|
||||
.lasso .hljs-variable,
|
||||
.makefile .hljs-variable,
|
||||
.asciidoc .hljs-bullet,
|
||||
.markdown .hljs-bullet,
|
||||
.asciidoc .hljs-link_url,
|
||||
.markdown .hljs-link_url {
|
||||
color: #080;
|
||||
}
|
||||
|
||||
.hljs-label,
|
||||
.hljs-javadoc,
|
||||
.ruby .hljs-string,
|
||||
.hljs-decorator,
|
||||
.hljs-filter .hljs-argument,
|
||||
.hljs-localvars,
|
||||
.hljs-array,
|
||||
.hljs-attr_selector,
|
||||
.hljs-important,
|
||||
.hljs-pseudo,
|
||||
.hljs-pi,
|
||||
.haml .hljs-bullet,
|
||||
.hljs-doctype,
|
||||
.hljs-deletion,
|
||||
.hljs-envvar,
|
||||
.hljs-shebang,
|
||||
.apache .hljs-sqbracket,
|
||||
.nginx .hljs-built_in,
|
||||
.tex .hljs-formula,
|
||||
.erlang_repl .hljs-reserved,
|
||||
.hljs-prompt,
|
||||
.asciidoc .hljs-link_label,
|
||||
.markdown .hljs-link_label,
|
||||
.vhdl .hljs-attribute,
|
||||
.clojure .hljs-attribute,
|
||||
.asciidoc .hljs-attribute,
|
||||
.lasso .hljs-attribute,
|
||||
.coffeescript .hljs-property,
|
||||
.hljs-phony {
|
||||
color: #88F
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-id,
|
||||
.hljs-title,
|
||||
.hljs-built_in,
|
||||
.hljs-aggregate,
|
||||
.css .hljs-tag,
|
||||
.hljs-javadoctag,
|
||||
.hljs-phpdoc,
|
||||
.hljs-yardoctag,
|
||||
.smalltalk .hljs-class,
|
||||
.hljs-winutils,
|
||||
.bash .hljs-variable,
|
||||
.apache .hljs-tag,
|
||||
.go .hljs-typename,
|
||||
.tex .hljs-command,
|
||||
.asciidoc .hljs-strong,
|
||||
.markdown .hljs-strong,
|
||||
.hljs-request,
|
||||
.hljs-status {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.asciidoc .hljs-emphasis,
|
||||
.markdown .hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.nginx .hljs-built_in {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.coffeescript .javascript,
|
||||
.javascript .xml,
|
||||
.lasso .markup,
|
||||
.tex .hljs-formula,
|
||||
.xml .javascript,
|
||||
.xml .vbscript,
|
||||
.xml .css,
|
||||
.xml .hljs-cdata {
|
||||
opacity: 0.5;
|
||||
}
|
200
lib/GUI/css/main.less
Normal file
200
lib/GUI/css/main.less
Normal file
@ -0,0 +1,200 @@
|
||||
@import "../../../node_modules/helpers.less/helpers.less";
|
||||
@import "./markdown.less";
|
||||
@import "./highlight.js.less";
|
||||
@import "./fontello.less";
|
||||
|
||||
/*** Main Styles ***/
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Lucida Grande", "Helvetica Neue", Helvetica, Arial, Sans-Serif;
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
text-decoration: none;
|
||||
color: #0D5AFF;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@contentWidth: 880px;
|
||||
@headerPadding: 10px;
|
||||
header {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
background: #FFF;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
|
||||
#header-inner {
|
||||
max-width: @contentWidth + @headerPadding*2;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#content {
|
||||
max-width: @contentWidth;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#logo {
|
||||
margin: 20px auto 0;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
|
||||
a, a:visited {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
/*** Setup ***/
|
||||
#setup {
|
||||
background: #DB4141;
|
||||
padding: 15px 20px;
|
||||
display: inline-block;
|
||||
.border-radius(4px);
|
||||
text-align: left;
|
||||
color: #FFF;
|
||||
margin-top: 20px;
|
||||
|
||||
code {
|
||||
font-family: Consolas, monaco, monospace;
|
||||
}
|
||||
}
|
||||
|
||||
/*** Search Box ***/
|
||||
#search-form {
|
||||
float: right;
|
||||
|
||||
@media (max-width: 540px) {
|
||||
float: none;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
@height: 30px;
|
||||
|
||||
input, button {
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
border: 1px solid #CCC;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
width: 200px;
|
||||
height: @height;
|
||||
.border-box;
|
||||
padding: 0 5px;
|
||||
font-size: 16px;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
height: @height;
|
||||
width: @height;
|
||||
margin: 0;
|
||||
border-left: 0;
|
||||
background: #FFF;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
/*** Heading ***/
|
||||
h2 {
|
||||
border-bottom: 6px solid #424242;
|
||||
margin: 40px 0 0;
|
||||
padding: 0 @headerPadding 10px;
|
||||
}
|
||||
|
||||
/*** Package Entries ***/
|
||||
.entry {
|
||||
background: #F3F3F3;
|
||||
.border-radius(4px);
|
||||
padding: 12px 15px 15px;
|
||||
.transition(height .3s);
|
||||
overflow: hidden;
|
||||
margin-bottom: 12px;
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.name:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.name:before {
|
||||
margin: 0;
|
||||
margin-left: -10px;
|
||||
.transformTransition(.2s);
|
||||
}
|
||||
|
||||
&.open .name:before {
|
||||
.rotate(90deg);
|
||||
}
|
||||
|
||||
.version {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.author {
|
||||
font-size: 16px;
|
||||
float: right;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.readme {
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
background: #FFF;
|
||||
padding: 10px 12px;
|
||||
.border-radius(3px);
|
||||
}
|
||||
}
|
||||
|
||||
/*** Search Results ***/
|
||||
.state-search #all-packages {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-ajax {
|
||||
display: block;
|
||||
margin: 50px auto;
|
||||
}
|
||||
|
||||
.no-results {
|
||||
text-align: center;
|
||||
margin: 50px 0;
|
||||
color: #888;
|
||||
|
||||
big {
|
||||
font-size: 38px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
268
lib/GUI/css/markdown.less
Normal file
268
lib/GUI/css/markdown.less
Normal file
@ -0,0 +1,268 @@
|
||||
/*** Sourced from this Gist: https://gist.github.com/andyferra/2554919 ***/
|
||||
|
||||
.readme {
|
||||
a {
|
||||
color: #4183C4; }
|
||||
a.absent {
|
||||
color: #cc0000; }
|
||||
a.anchor {
|
||||
display: block;
|
||||
padding-left: 30px;
|
||||
margin-left: -30px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0; }
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 20px 0 10px;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
cursor: text;
|
||||
position: relative; }
|
||||
|
||||
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
|
||||
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
|
||||
text-decoration: none; }
|
||||
|
||||
h1 tt, h1 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h2 tt, h2 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h3 tt, h3 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h4 tt, h4 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h5 tt, h5 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h6 tt, h6 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
color: black; }
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
color: black; }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
h4 {
|
||||
font-size: 16px; }
|
||||
|
||||
h5 {
|
||||
font-size: 14px; }
|
||||
|
||||
h6 {
|
||||
color: #777777;
|
||||
font-size: 14px; }
|
||||
|
||||
p, blockquote, ul, ol, dl, li, table, pre {
|
||||
margin: 15px 0; }
|
||||
|
||||
hr {
|
||||
background: transparent url("../../images/modules/pulls/dirty-shade.png") repeat-x 0 0;
|
||||
border: 0 none;
|
||||
color: #cccccc;
|
||||
height: 4px;
|
||||
padding: 0; }
|
||||
|
||||
body > h2:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h1:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h1:first-child + h2 {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
|
||||
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
|
||||
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
|
||||
margin-top: 0; }
|
||||
|
||||
li p.first {
|
||||
display: inline-block; }
|
||||
|
||||
ul, ol {
|
||||
padding-left: 30px; }
|
||||
|
||||
ul :first-child, ol :first-child {
|
||||
margin-top: 0; }
|
||||
|
||||
ul :last-child, ol :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
dl {
|
||||
padding: 0; }
|
||||
dl dt {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
padding: 0;
|
||||
margin: 15px 0 5px; }
|
||||
dl dt:first-child {
|
||||
padding: 0; }
|
||||
dl dt > :first-child {
|
||||
margin-top: 0; }
|
||||
dl dt > :last-child {
|
||||
margin-bottom: 0; }
|
||||
dl dd {
|
||||
margin: 0 0 15px;
|
||||
padding: 0 15px; }
|
||||
dl dd > :first-child {
|
||||
margin-top: 0; }
|
||||
dl dd > :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
blockquote {
|
||||
border-left: 4px solid #dddddd;
|
||||
padding: 0 15px;
|
||||
color: #777777; }
|
||||
blockquote > :first-child {
|
||||
margin-top: 0; }
|
||||
blockquote > :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
table {
|
||||
padding: 0; }
|
||||
table tr {
|
||||
border-top: 1px solid #cccccc;
|
||||
background-color: white;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8; }
|
||||
table tr th {
|
||||
font-weight: bold;
|
||||
border: 1px solid #cccccc;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px; }
|
||||
table tr td {
|
||||
border: 1px solid #cccccc;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px; }
|
||||
table tr th :first-child, table tr td :first-child {
|
||||
margin-top: 0; }
|
||||
table tr th :last-child, table tr td :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
img {
|
||||
margin: 10px 0;
|
||||
max-width: 100%; }
|
||||
|
||||
span.frame {
|
||||
display: block;
|
||||
overflow: hidden; }
|
||||
span.frame > span {
|
||||
border: 1px solid #dddddd;
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
padding: 7px;
|
||||
width: auto; }
|
||||
span.frame span img {
|
||||
display: block;
|
||||
float: left; }
|
||||
span.frame span span {
|
||||
clear: both;
|
||||
color: #333333;
|
||||
display: block;
|
||||
padding: 5px 0 0; }
|
||||
span.align-center {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both; }
|
||||
span.align-center > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: center; }
|
||||
span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center; }
|
||||
span.align-right {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both; }
|
||||
span.align-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
text-align: right; }
|
||||
span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right; }
|
||||
span.float-left {
|
||||
display: block;
|
||||
margin-right: 13px;
|
||||
overflow: hidden;
|
||||
float: left; }
|
||||
span.float-left span {
|
||||
margin: 13px 0 0; }
|
||||
span.float-right {
|
||||
display: block;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
float: right; }
|
||||
span.float-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: right; }
|
||||
|
||||
code, tt {
|
||||
margin: 0 2px;
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
border: 1px solid #eaeaea;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 3px; }
|
||||
|
||||
pre code {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
border: none;
|
||||
background: transparent; }
|
||||
|
||||
.highlight pre {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #cccccc;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px; }
|
||||
|
||||
pre {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #cccccc;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px; }
|
||||
pre code, pre tt {
|
||||
background-color: transparent;
|
||||
border: none; }
|
||||
}
|
8
lib/GUI/entry.hbs
Normal file
8
lib/GUI/entry.hbs
Normal file
@ -0,0 +1,8 @@
|
||||
<article class='entry' data-name='{{ name }}' data-version='{{ version }}'>
|
||||
<h3>
|
||||
<a class='name icon-angle-right' href='javascript:void(0)'>{{ name }}</a>
|
||||
<small class='version'>v{{ version }}</small>
|
||||
<div class='author'>By: {{ _npmUser.name }}</div>
|
||||
</h3>
|
||||
<p>{{ description }}</p>
|
||||
</article>
|
52
lib/GUI/index.hbs
Normal file
52
lib/GUI/index.hbs
Normal file
@ -0,0 +1,52 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ name }}</title>
|
||||
|
||||
<link rel="icon" type="image/ico" href="/-/static/favicon.ico"/>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/-/static/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div id='header-inner'>
|
||||
<a href='/'><img id='logo' alt='{{ name }}' title='{{ name }}' src='/-/logo' /></a>
|
||||
|
||||
<div class='center'>
|
||||
<article id='setup'>
|
||||
<code>npm set registry {{ baseUrl }}</code><br>
|
||||
<code>npm adduser --registry {{ baseUrl }}</code>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<h2>
|
||||
Available Packages:
|
||||
<form id='search-form'>
|
||||
<input type='text' placeholder='Search' /><button class='clear icon-search'></button>
|
||||
</form>
|
||||
</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id='content'>
|
||||
<div id='search-results'></div>
|
||||
|
||||
<div id='all-packages'>
|
||||
{{#each packages}}
|
||||
{{> entry}}
|
||||
{{/each}}
|
||||
|
||||
{{#unless packages.length}}
|
||||
<div class='no-results'>
|
||||
<big>No Packages</big><br>
|
||||
Use <code>npm publish</code>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
|
||||
<script type='text/javascript' src='/-/static/main.js'></script>
|
||||
</body>
|
||||
</html>
|
71
lib/GUI/js/entry.js
Normal file
71
lib/GUI/js/entry.js
Normal file
@ -0,0 +1,71 @@
|
||||
var $ = require('unopinionate').selector,
|
||||
onClick = require('onclick'),
|
||||
transitionComplete = require('transition-complete');
|
||||
|
||||
$(function() {
|
||||
onClick('.entry .name', function() {
|
||||
var $this = $(this),
|
||||
$entry = $this.closest('.entry');
|
||||
|
||||
//Close entry
|
||||
if($entry.hasClass('open')) {
|
||||
$entry
|
||||
.height($entry.height())
|
||||
.removeClass('open');
|
||||
|
||||
setTimeout(function() {
|
||||
$entry.css('height', $entry.attr('data-height') + 'px');
|
||||
}, 0);
|
||||
|
||||
transitionComplete(function() {
|
||||
$entry.find('.readme').remove();
|
||||
$entry.css('height', 'auto');
|
||||
});
|
||||
}
|
||||
//Open entry
|
||||
else {
|
||||
//Close open entries
|
||||
$('.entry.open').each(function() {
|
||||
var $entry = $(this);
|
||||
$entry
|
||||
.height($entry.height())
|
||||
.removeClass('open');
|
||||
|
||||
setTimeout(function() {
|
||||
$entry.css('height', $entry.attr('data-height') + 'px');
|
||||
}, 0);
|
||||
|
||||
transitionComplete(function() {
|
||||
$entry.find('.readme').remove();
|
||||
$entry.css('height', 'auto');
|
||||
});
|
||||
});
|
||||
|
||||
//Add the open class
|
||||
$entry.addClass('open');
|
||||
|
||||
//Explicitly set heights for transitions
|
||||
var height = $entry.height();
|
||||
$entry
|
||||
.attr('data-height', height)
|
||||
.css('height', height);
|
||||
|
||||
//Get the data
|
||||
$.ajax({
|
||||
url: '/-/readme/'+$entry.attr('data-name')+'/'+$entry.attr('data-version'),
|
||||
dataType: 'text',
|
||||
success: function(html) {
|
||||
var $readme = $("<div class='readme'>")
|
||||
.html(html)
|
||||
.appendTo($entry);
|
||||
|
||||
$entry.height(height + $readme.outerHeight());
|
||||
|
||||
transitionComplete(function() {
|
||||
$entry.css('height', 'auto');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
29
lib/GUI/js/header.js
Normal file
29
lib/GUI/js/header.js
Normal file
@ -0,0 +1,29 @@
|
||||
var $ = require('unopinionate').selector,
|
||||
onScroll = require('onscroll');
|
||||
|
||||
$(function() {
|
||||
var $header = $('header'),
|
||||
$content = $('#content'),
|
||||
bottomOffset = 52;
|
||||
|
||||
var scrollFunc = function(top) {
|
||||
var limit = $header.outerHeight() - bottomOffset;
|
||||
|
||||
if(top < 0) {
|
||||
$header.css('top', 0);
|
||||
}
|
||||
else if(top > limit) {
|
||||
$header.css('top', -limit + 'px');
|
||||
}
|
||||
else {
|
||||
$header.css('top', -top + 'px');
|
||||
}
|
||||
};
|
||||
|
||||
onScroll(scrollFunc);
|
||||
scrollFunc();
|
||||
|
||||
$(window).resize(function() {
|
||||
$content.css('margin-top', $header.outerHeight());
|
||||
}).resize();
|
||||
});
|
3
lib/GUI/js/main.js
Normal file
3
lib/GUI/js/main.js
Normal file
@ -0,0 +1,3 @@
|
||||
require('./search');
|
||||
require('./entry');
|
||||
require('./header');
|
70
lib/GUI/js/search.js
Normal file
70
lib/GUI/js/search.js
Normal file
@ -0,0 +1,70 @@
|
||||
var $ = require('unopinionate').selector,
|
||||
template = require('../entry.hbs'),
|
||||
onScroll = require('onscroll');
|
||||
|
||||
$(function() {
|
||||
'use strict';
|
||||
|
||||
var $form = $('#search-form'),
|
||||
$input = $form.find('input'),
|
||||
$searchResults = $("#search-results"),
|
||||
$body = $('body'),
|
||||
$clear = $form.find('.clear'),
|
||||
request,
|
||||
currentResults;
|
||||
|
||||
$form.bind('submit keyup', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var q = $input.val();
|
||||
|
||||
$body.addClass('state-search');
|
||||
|
||||
//Switch the icons
|
||||
$clear
|
||||
[q ? 'addClass' : 'removeClass']('icon-cancel')
|
||||
[!q ? 'addClass' : 'removeClass']('icon-search');
|
||||
|
||||
if(q) {
|
||||
if(request) {
|
||||
request.abort();
|
||||
}
|
||||
|
||||
if(!currentResults) {
|
||||
$searchResults.html("<img class='search-ajax' src='/-/static/ajax.gif' alt='Spinner'/>");
|
||||
}
|
||||
|
||||
request = $.getJSON('/-/search/' + q, function(results) {
|
||||
currentResults = results;
|
||||
|
||||
if(results.length) {
|
||||
var html = '';
|
||||
|
||||
$.each(results, function(i, entry) {
|
||||
html += template(entry);
|
||||
});
|
||||
|
||||
$searchResults.html(html);
|
||||
}
|
||||
else {
|
||||
$searchResults.html("<div class='no-results'><big>No Results</big></div>");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
request.abort();
|
||||
currentResults = null;
|
||||
$searchResults.html('');
|
||||
$body.removeClass('state-search');
|
||||
}
|
||||
});
|
||||
|
||||
$clear.click(function(e) {
|
||||
e.preventDefault();
|
||||
$input.val('');
|
||||
$form.keyup();
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
@ -4,6 +4,7 @@ var assert = require('assert')
|
||||
, minimatch = require('minimatch')
|
||||
, UError = require('./error').UserError
|
||||
, utils = require('./utils')
|
||||
, users = require('./users')
|
||||
|
||||
// [[a, [b, c]], d] -> [a, b, c, d]
|
||||
function flatten(array) {
|
||||
|
@ -9,6 +9,9 @@ users:
|
||||
# crypto.createHash('sha1').update(pass).digest('hex')
|
||||
password: __PASSWORD__
|
||||
|
||||
title: Sinopia
|
||||
# logo: logo.png
|
||||
|
||||
users_file: ./htpasswd
|
||||
|
||||
# Maximum amount of users allowed to register, defaults to "+inf".
|
||||
|
95
lib/index.js
95
lib/index.js
@ -11,6 +11,13 @@ var express = require('express')
|
||||
, validate_name = Middleware.validate_name
|
||||
, media = Middleware.media
|
||||
, expect_json = Middleware.expect_json
|
||||
, Handlebars = require('handlebars')
|
||||
, fs = require('fs')
|
||||
, localList = require('./local-list')
|
||||
, search = require('./search')
|
||||
, _ = require('underscore')
|
||||
, users = require('./users')
|
||||
, marked = require('marked');
|
||||
|
||||
function match(regexp) {
|
||||
return function(req, res, next, value, name) {
|
||||
@ -24,7 +31,9 @@ function match(regexp) {
|
||||
|
||||
module.exports = function(config_hash) {
|
||||
var config = new Config(config_hash)
|
||||
, storage = new Storage(config)
|
||||
, storage = new Storage(config);
|
||||
|
||||
search.configureStorage(storage);
|
||||
|
||||
var can = function(action) {
|
||||
return function(req, res, next) {
|
||||
@ -109,13 +118,7 @@ module.exports = function(config_hash) {
|
||||
app.param('org_couchdb_user', match(/^org\.couchdb\.user:/))
|
||||
app.param('anything', match(/.*/))
|
||||
|
||||
/* app.get('/', function(req, res) {
|
||||
res.send({
|
||||
error: 'unimplemented'
|
||||
})
|
||||
})*/
|
||||
|
||||
/* app.get('/-/all', function(req, res) {
|
||||
/* app.get('/-/all', function(req, res) {
|
||||
var https = require('https')
|
||||
var JSONStream = require('JSONStream')
|
||||
var request = require('request')({
|
||||
@ -126,6 +129,21 @@ module.exports = function(config_hash) {
|
||||
console.log(d)
|
||||
})
|
||||
})*/
|
||||
|
||||
Handlebars.registerPartial('entry', fs.readFileSync(require.resolve('./GUI/entry.hbs'), 'utf8'));
|
||||
var template = Handlebars.compile(fs.readFileSync(require.resolve('./GUI/index.hbs'), 'utf8'));
|
||||
|
||||
app.get('/', can('access'), function(req, res, next) {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
|
||||
storage.get_local(function(err, packages) {
|
||||
res.send(template({
|
||||
name: config.title || "Sinopia",
|
||||
packages: packages,
|
||||
baseUrl: config.url_prefix || req.protocol + '://' + req.get('host') + '/'
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: anonymous user?
|
||||
app.get('/:package/:version?', can('access'), function(req, res, next) {
|
||||
@ -185,7 +203,7 @@ module.exports = function(config_hash) {
|
||||
})
|
||||
|
||||
//app.get('/*', function(req, res) {
|
||||
// proxy.request(req, res)
|
||||
// proxy.request(req, res)
|
||||
//})
|
||||
|
||||
// placeholder 'cause npm require to be authenticated to publish
|
||||
@ -239,6 +257,65 @@ module.exports = function(config_hash) {
|
||||
}
|
||||
})
|
||||
|
||||
// Static
|
||||
app.get('/-/static/:file', function(req, res, next) {
|
||||
var file = __dirname + '/static/' + req.params.file;
|
||||
fs.exists(file, function(exists) {
|
||||
if(exists) {
|
||||
res.sendfile(file);
|
||||
}
|
||||
else {
|
||||
res.status(404);
|
||||
res.send("File Not Found");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/-/logo', function(req, res, next) {
|
||||
res.sendfile(config.logo ? config.logo : __dirname + "/static/logo.png");
|
||||
});
|
||||
|
||||
// Search
|
||||
app.get('/-/search/:query', function(req, res, next) {
|
||||
var results = search.query(req.params.query),
|
||||
packages = [];
|
||||
|
||||
var getData = function(i) {
|
||||
storage.get_package(results[i].ref, function(err, entry) {
|
||||
if(entry) {
|
||||
packages.push(entry.versions[entry['dist-tags'].latest]);
|
||||
}
|
||||
|
||||
if(i >= results.length - 1) {
|
||||
res.send(packages);
|
||||
}
|
||||
else {
|
||||
getData(i + 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if(results.length) {
|
||||
getData(0);
|
||||
}
|
||||
else {
|
||||
res.send([]);
|
||||
}
|
||||
});
|
||||
|
||||
// Readme
|
||||
marked.setOptions({
|
||||
highlight: function (code) {
|
||||
return require('highlight.js').highlightAuto(code).value;
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/-/readme/:name/:version', function(req, res, next) {
|
||||
storage.get_readme(req.params.name, req.params.version, function(readme) {
|
||||
res.send(marked(readme));
|
||||
});
|
||||
});
|
||||
|
||||
// tagging a package
|
||||
app.put('/:package/:tag', can('publish'), media('application/json'), function(req, res, next) {
|
||||
if (typeof(req.body) !== 'string') return next('route')
|
||||
|
36
lib/local-list.js
Normal file
36
lib/local-list.js
Normal file
@ -0,0 +1,36 @@
|
||||
var fs = require('fs')
|
||||
, listFilePath = './local-list.json';
|
||||
|
||||
var LocalList = function() {
|
||||
if(fs.existsSync(listFilePath)) {
|
||||
this.list = JSON.parse(fs.readFileSync(listFilePath, 'utf8'));
|
||||
}
|
||||
else {
|
||||
this.list = [];
|
||||
}
|
||||
};
|
||||
|
||||
LocalList.prototype = {
|
||||
add: function(name) {
|
||||
if(this.list.indexOf(name) == -1) {
|
||||
this.list.push(name);
|
||||
this.sync();
|
||||
}
|
||||
},
|
||||
remove: function(name) {
|
||||
var i = this.list.indexOf(name);
|
||||
if(i != -1) {
|
||||
this.list.splice(i, 1);
|
||||
}
|
||||
|
||||
this.sync();
|
||||
},
|
||||
get: function() {
|
||||
return this.list;
|
||||
},
|
||||
sync: function() {
|
||||
fs.writeFileSync(listFilePath, JSON.stringify(this.list)); //Uses sync to prevent ugly race condition
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = new LocalList();
|
@ -8,6 +8,9 @@ var fs = require('fs')
|
||||
, mystreams = require('./streams')
|
||||
, Logger = require('./logger')
|
||||
, info_file = 'package.json'
|
||||
, localList = require('./local-list')
|
||||
, targz = require('tar.gz')
|
||||
, search = require('./search');
|
||||
|
||||
//
|
||||
// Implements Storage interface
|
||||
@ -45,7 +48,7 @@ Storage.prototype._internal_error = function(err, file, message) {
|
||||
})
|
||||
}
|
||||
|
||||
Storage.prototype.add_package = function(name, metadata, callback) {
|
||||
Storage.prototype.add_package = function(name, info, callback) {
|
||||
this.storage(name).create_json(info_file, get_boilerplate(name), function(err) {
|
||||
if (err && err.code === 'EEXISTS') {
|
||||
return callback(new UError({
|
||||
@ -53,6 +56,10 @@ Storage.prototype.add_package = function(name, metadata, callback) {
|
||||
message: 'this package is already present'
|
||||
}))
|
||||
}
|
||||
|
||||
search.add(info.versions[info['dist-tags'].latest]);
|
||||
localList.add(name);
|
||||
|
||||
callback()
|
||||
})
|
||||
}
|
||||
@ -91,10 +98,13 @@ Storage.prototype.remove_package = function(name, callback) {
|
||||
// try to unlink the directory, but ignore errors because it can fail
|
||||
self.storage(name).rmdir('.', function(err) {
|
||||
callback(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
search.remove(name);
|
||||
localList.remove(name);
|
||||
}
|
||||
|
||||
Storage.prototype._read_create_package = function(name, callback) {
|
||||
@ -378,6 +388,41 @@ Storage.prototype.add_tarball = function(name, filename) {
|
||||
return stream
|
||||
}
|
||||
|
||||
Storage.prototype.unpack_tarball = function(file, callback) {
|
||||
new targz().extract(file + '.tgz', file, callback);
|
||||
};
|
||||
|
||||
Storage.prototype.get_readme = function(name, version, callback) {
|
||||
var self = this,
|
||||
fileName = this.storage(name).path + '/' + name + '-' + version;
|
||||
|
||||
fs.exists(fileName, function(exists) {
|
||||
if(exists) {
|
||||
returnReadme();
|
||||
}
|
||||
else {
|
||||
self.unpack_tarball(fileName, function(err) {
|
||||
returnReadme();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function returnReadme() {
|
||||
var readmeFileName = fileName + '/package/README.md';
|
||||
|
||||
fs.exists(readmeFileName, function(exists) {
|
||||
if(exists) {
|
||||
fs.readFile(readmeFileName, {encoding: "UTF-8"}, function(err, file) {
|
||||
callback(file);
|
||||
});
|
||||
}
|
||||
else {
|
||||
callback('');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Storage.prototype.get_tarball = function(name, filename, callback) {
|
||||
assert(utils.validate_name(filename))
|
||||
|
||||
|
@ -136,7 +136,9 @@ module.exports.log_and_etagify = function(req, res, next) {
|
||||
res.send = function(body) {
|
||||
try {
|
||||
if (typeof(body) === 'string' || typeof(body) === 'object') {
|
||||
res.header('Content-type', 'application/json')
|
||||
if (!res.getHeader('Content-type')) {
|
||||
res.header('Content-type', 'application/json')
|
||||
}
|
||||
|
||||
if (typeof(body) === 'object' && body != null) {
|
||||
if (typeof(body.error) === 'string') {
|
||||
|
46
lib/search.js
Normal file
46
lib/search.js
Normal file
@ -0,0 +1,46 @@
|
||||
var lunr = require('lunr')
|
||||
, localList = require('./local-list');
|
||||
|
||||
var Search = function() {
|
||||
this.index = lunr(function () {
|
||||
this.field('name', {boost: 10});
|
||||
this.field('description', {boost: 4});
|
||||
this.field('author', {boost: 6});
|
||||
this.field('readme');
|
||||
});
|
||||
};
|
||||
|
||||
Search.prototype = {
|
||||
query: function(q) {
|
||||
return this.index.search(q);
|
||||
},
|
||||
add: function(package) {
|
||||
this.index.add({
|
||||
id: package.name,
|
||||
name: package.name,
|
||||
description: package.description,
|
||||
author: package._npmUser.name
|
||||
});
|
||||
},
|
||||
remove: function(name) {
|
||||
this.index.remove({
|
||||
id: name
|
||||
});
|
||||
},
|
||||
reindex: function() {
|
||||
var self = this;
|
||||
this.storage.get_local(function(err, packages) {
|
||||
var i = packages.length;
|
||||
|
||||
while(i--) {
|
||||
self.add(packages[i]);
|
||||
}
|
||||
});
|
||||
},
|
||||
configureStorage: function(storage) {
|
||||
this.storage = storage;
|
||||
this.reindex();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = new Search();
|
BIN
lib/static/ajax.gif
Normal file
BIN
lib/static/ajax.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
lib/static/favicon.ico
Normal file
BIN
lib/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
BIN
lib/static/fontello.eot
Normal file
BIN
lib/static/fontello.eot
Normal file
Binary file not shown.
15
lib/static/fontello.svg
Normal file
15
lib/static/fontello.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
|
||||
<defs>
|
||||
<font id="fontello" horiz-adv-x="1000" >
|
||||
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||
<missing-glyph horiz-adv-x="1000" />
|
||||
<glyph glyph-name="search" unicode="" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
|
||||
<glyph glyph-name="cancel" unicode="" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
|
||||
<glyph glyph-name="right-open" unicode="" d="m613 386q0-29-20-51l-364-363q-21-21-50-21t-51 21l-42 42q-21 21-21 50 0 30 21 51l271 271-271 270q-21 22-21 51 0 30 21 50l42 42q20 21 51 21t50-21l364-363q20-21 20-50z" horiz-adv-x="642.9" />
|
||||
<glyph glyph-name="angle-right" unicode="" d="m332 314q0-7-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13t6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13z" horiz-adv-x="357.1" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
BIN
lib/static/fontello.ttf
Normal file
BIN
lib/static/fontello.ttf
Normal file
Binary file not shown.
BIN
lib/static/fontello.woff
Normal file
BIN
lib/static/fontello.woff
Normal file
Binary file not shown.
BIN
lib/static/logo.png
Normal file
BIN
lib/static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
731
lib/static/main.css
Normal file
731
lib/static/main.css
Normal file
File diff suppressed because one or more lines are too long
965
lib/static/main.js
Normal file
965
lib/static/main.js
Normal file
@ -0,0 +1,965 @@
|
||||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
var templater = require("handlebars/runtime").default.template;module.exports = templater(function (Handlebars,depth0,helpers,partials,data) {
|
||||
this.compilerInfo = [4,'>= 1.0.0'];
|
||||
helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
|
||||
var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression;
|
||||
|
||||
|
||||
buffer += "<article class='entry' data-name='";
|
||||
if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
||||
else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
||||
buffer += escapeExpression(stack1)
|
||||
+ "' data-version='";
|
||||
if (helper = helpers.version) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
||||
else { helper = (depth0 && depth0.version); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
||||
buffer += escapeExpression(stack1)
|
||||
+ "'>\n <h3>\n <a class='name icon-angle-right' href='javascript:void(0)'>";
|
||||
if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
||||
else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
||||
buffer += escapeExpression(stack1)
|
||||
+ "</a>\n <small class='version'>v";
|
||||
if (helper = helpers.version) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
||||
else { helper = (depth0 && depth0.version); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
||||
buffer += escapeExpression(stack1)
|
||||
+ "</small>\n <div class='author'>By: "
|
||||
+ escapeExpression(((stack1 = ((stack1 = (depth0 && depth0._npmUser)),stack1 == null || stack1 === false ? stack1 : stack1.name)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
|
||||
+ "</div>\n </h3>\n <p>";
|
||||
if (helper = helpers.description) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
||||
else { helper = (depth0 && depth0.description); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
||||
buffer += escapeExpression(stack1)
|
||||
+ "</p>\n</article>";
|
||||
return buffer;
|
||||
});
|
||||
},{"handlebars/runtime":12}],2:[function(require,module,exports){
|
||||
var $ = require('unopinionate').selector,
|
||||
onClick = require('onclick'),
|
||||
transitionComplete = require('transition-complete');
|
||||
|
||||
$(function() {
|
||||
onClick('.entry .name', function() {
|
||||
var $this = $(this),
|
||||
$entry = $this.closest('.entry');
|
||||
|
||||
//Close entry
|
||||
if($entry.hasClass('open')) {
|
||||
$entry
|
||||
.height($entry.height())
|
||||
.removeClass('open');
|
||||
|
||||
setTimeout(function() {
|
||||
$entry.css('height', $entry.attr('data-height') + 'px');
|
||||
}, 0);
|
||||
|
||||
transitionComplete(function() {
|
||||
$entry.find('.readme').remove();
|
||||
$entry.css('height', 'auto');
|
||||
});
|
||||
}
|
||||
//Open entry
|
||||
else {
|
||||
//Close open entries
|
||||
$('.entry.open').each(function() {
|
||||
var $entry = $(this);
|
||||
$entry
|
||||
.height($entry.height())
|
||||
.removeClass('open');
|
||||
|
||||
setTimeout(function() {
|
||||
$entry.css('height', $entry.attr('data-height') + 'px');
|
||||
}, 0);
|
||||
|
||||
transitionComplete(function() {
|
||||
$entry.find('.readme').remove();
|
||||
$entry.css('height', 'auto');
|
||||
});
|
||||
});
|
||||
|
||||
//Add the open class
|
||||
$entry.addClass('open');
|
||||
|
||||
//Explicitly set heights for transitions
|
||||
var height = $entry.height();
|
||||
$entry
|
||||
.attr('data-height', height)
|
||||
.css('height', height);
|
||||
|
||||
//Get the data
|
||||
$.ajax({
|
||||
url: '/-/readme/'+$entry.attr('data-name')+'/'+$entry.attr('data-version'),
|
||||
dataType: 'text',
|
||||
success: function(html) {
|
||||
var $readme = $("<div class='readme'>")
|
||||
.html(html)
|
||||
.appendTo($entry);
|
||||
|
||||
$entry.height(height + $readme.outerHeight());
|
||||
|
||||
transitionComplete(function() {
|
||||
$entry.css('height', 'auto');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},{"onclick":13,"transition-complete":15,"unopinionate":16}],3:[function(require,module,exports){
|
||||
var $ = require('unopinionate').selector,
|
||||
onScroll = require('onscroll');
|
||||
|
||||
$(function() {
|
||||
var $header = $('header'),
|
||||
$content = $('#content'),
|
||||
bottomOffset = 52;
|
||||
|
||||
var scrollFunc = function(top) {
|
||||
var limit = $header.outerHeight() - bottomOffset;
|
||||
|
||||
if(top < 0) {
|
||||
$header.css('top', 0);
|
||||
}
|
||||
else if(top > limit) {
|
||||
$header.css('top', -limit + 'px');
|
||||
}
|
||||
else {
|
||||
$header.css('top', -top + 'px');
|
||||
}
|
||||
};
|
||||
|
||||
onScroll(scrollFunc);
|
||||
scrollFunc();
|
||||
|
||||
$(window).resize(function() {
|
||||
$content.css('margin-top', $header.outerHeight());
|
||||
}).resize();
|
||||
});
|
||||
},{"onscroll":14,"unopinionate":16}],4:[function(require,module,exports){
|
||||
require('./search');
|
||||
require('./entry');
|
||||
require('./header');
|
||||
},{"./entry":2,"./header":3,"./search":5}],5:[function(require,module,exports){
|
||||
var $ = require('unopinionate').selector,
|
||||
template = require('../entry.hbs'),
|
||||
onScroll = require('onscroll');
|
||||
|
||||
$(function() {
|
||||
'use strict';
|
||||
|
||||
var $form = $('#search-form'),
|
||||
$input = $form.find('input'),
|
||||
$searchResults = $("#search-results"),
|
||||
$body = $('body'),
|
||||
$clear = $form.find('.clear'),
|
||||
request,
|
||||
currentResults;
|
||||
|
||||
$form.bind('submit keyup', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var q = $input.val();
|
||||
|
||||
$body.addClass('state-search');
|
||||
|
||||
//Switch the icons
|
||||
$clear
|
||||
[q ? 'addClass' : 'removeClass']('icon-cancel')
|
||||
[!q ? 'addClass' : 'removeClass']('icon-search');
|
||||
|
||||
if(q) {
|
||||
if(request) {
|
||||
request.abort();
|
||||
}
|
||||
|
||||
if(!currentResults) {
|
||||
$searchResults.html("<img class='search-ajax' src='/-/static/ajax.gif' alt='Spinner'/>");
|
||||
}
|
||||
|
||||
request = $.getJSON('/-/search/' + q, function(results) {
|
||||
currentResults = results;
|
||||
|
||||
if(results.length) {
|
||||
var html = '';
|
||||
|
||||
$.each(results, function(i, entry) {
|
||||
html += template(entry);
|
||||
});
|
||||
|
||||
$searchResults.html(html);
|
||||
}
|
||||
else {
|
||||
$searchResults.html("<div class='no-results'><big>No Results</big></div>");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
request.abort();
|
||||
currentResults = null;
|
||||
$searchResults.html('');
|
||||
$body.removeClass('state-search');
|
||||
}
|
||||
});
|
||||
|
||||
$clear.click(function(e) {
|
||||
e.preventDefault();
|
||||
$input.val('');
|
||||
$form.keyup();
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
},{"../entry.hbs":1,"onscroll":14,"unopinionate":16}],6:[function(require,module,exports){
|
||||
"use strict";
|
||||
/*globals Handlebars: true */
|
||||
var base = require("./handlebars/base");
|
||||
|
||||
// Each of these augment the Handlebars object. No need to setup here.
|
||||
// (This is done to easily share code between commonjs and browse envs)
|
||||
var SafeString = require("./handlebars/safe-string")["default"];
|
||||
var Exception = require("./handlebars/exception")["default"];
|
||||
var Utils = require("./handlebars/utils");
|
||||
var runtime = require("./handlebars/runtime");
|
||||
|
||||
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
|
||||
var create = function() {
|
||||
var hb = new base.HandlebarsEnvironment();
|
||||
|
||||
Utils.extend(hb, base);
|
||||
hb.SafeString = SafeString;
|
||||
hb.Exception = Exception;
|
||||
hb.Utils = Utils;
|
||||
|
||||
hb.VM = runtime;
|
||||
hb.template = function(spec) {
|
||||
return runtime.template(spec, hb);
|
||||
};
|
||||
|
||||
return hb;
|
||||
};
|
||||
|
||||
var Handlebars = create();
|
||||
Handlebars.create = create;
|
||||
|
||||
exports["default"] = Handlebars;
|
||||
},{"./handlebars/base":7,"./handlebars/exception":8,"./handlebars/runtime":9,"./handlebars/safe-string":10,"./handlebars/utils":11}],7:[function(require,module,exports){
|
||||
"use strict";
|
||||
var Utils = require("./utils");
|
||||
var Exception = require("./exception")["default"];
|
||||
|
||||
var VERSION = "1.3.0";
|
||||
exports.VERSION = VERSION;var COMPILER_REVISION = 4;
|
||||
exports.COMPILER_REVISION = COMPILER_REVISION;
|
||||
var REVISION_CHANGES = {
|
||||
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
|
||||
2: '== 1.0.0-rc.3',
|
||||
3: '== 1.0.0-rc.4',
|
||||
4: '>= 1.0.0'
|
||||
};
|
||||
exports.REVISION_CHANGES = REVISION_CHANGES;
|
||||
var isArray = Utils.isArray,
|
||||
isFunction = Utils.isFunction,
|
||||
toString = Utils.toString,
|
||||
objectType = '[object Object]';
|
||||
|
||||
function HandlebarsEnvironment(helpers, partials) {
|
||||
this.helpers = helpers || {};
|
||||
this.partials = partials || {};
|
||||
|
||||
registerDefaultHelpers(this);
|
||||
}
|
||||
|
||||
exports.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = {
|
||||
constructor: HandlebarsEnvironment,
|
||||
|
||||
logger: logger,
|
||||
log: log,
|
||||
|
||||
registerHelper: function(name, fn, inverse) {
|
||||
if (toString.call(name) === objectType) {
|
||||
if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); }
|
||||
Utils.extend(this.helpers, name);
|
||||
} else {
|
||||
if (inverse) { fn.not = inverse; }
|
||||
this.helpers[name] = fn;
|
||||
}
|
||||
},
|
||||
|
||||
registerPartial: function(name, str) {
|
||||
if (toString.call(name) === objectType) {
|
||||
Utils.extend(this.partials, name);
|
||||
} else {
|
||||
this.partials[name] = str;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function registerDefaultHelpers(instance) {
|
||||
instance.registerHelper('helperMissing', function(arg) {
|
||||
if(arguments.length === 2) {
|
||||
return undefined;
|
||||
} else {
|
||||
throw new Exception("Missing helper: '" + arg + "'");
|
||||
}
|
||||
});
|
||||
|
||||
instance.registerHelper('blockHelperMissing', function(context, options) {
|
||||
var inverse = options.inverse || function() {}, fn = options.fn;
|
||||
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if(context === true) {
|
||||
return fn(this);
|
||||
} else if(context === false || context == null) {
|
||||
return inverse(this);
|
||||
} else if (isArray(context)) {
|
||||
if(context.length > 0) {
|
||||
return instance.helpers.each(context, options);
|
||||
} else {
|
||||
return inverse(this);
|
||||
}
|
||||
} else {
|
||||
return fn(context);
|
||||
}
|
||||
});
|
||||
|
||||
instance.registerHelper('each', function(context, options) {
|
||||
var fn = options.fn, inverse = options.inverse;
|
||||
var i = 0, ret = "", data;
|
||||
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if (options.data) {
|
||||
data = createFrame(options.data);
|
||||
}
|
||||
|
||||
if(context && typeof context === 'object') {
|
||||
if (isArray(context)) {
|
||||
for(var j = context.length; i<j; i++) {
|
||||
if (data) {
|
||||
data.index = i;
|
||||
data.first = (i === 0);
|
||||
data.last = (i === (context.length-1));
|
||||
}
|
||||
ret = ret + fn(context[i], { data: data });
|
||||
}
|
||||
} else {
|
||||
for(var key in context) {
|
||||
if(context.hasOwnProperty(key)) {
|
||||
if(data) {
|
||||
data.key = key;
|
||||
data.index = i;
|
||||
data.first = (i === 0);
|
||||
}
|
||||
ret = ret + fn(context[key], {data: data});
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(i === 0){
|
||||
ret = inverse(this);
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
||||
instance.registerHelper('if', function(conditional, options) {
|
||||
if (isFunction(conditional)) { conditional = conditional.call(this); }
|
||||
|
||||
// Default behavior is to render the positive path if the value is truthy and not empty.
|
||||
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
|
||||
// behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
|
||||
if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) {
|
||||
return options.inverse(this);
|
||||
} else {
|
||||
return options.fn(this);
|
||||
}
|
||||
});
|
||||
|
||||
instance.registerHelper('unless', function(conditional, options) {
|
||||
return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
|
||||
});
|
||||
|
||||
instance.registerHelper('with', function(context, options) {
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if (!Utils.isEmpty(context)) return options.fn(context);
|
||||
});
|
||||
|
||||
instance.registerHelper('log', function(context, options) {
|
||||
var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
|
||||
instance.log(level, context);
|
||||
});
|
||||
}
|
||||
|
||||
var logger = {
|
||||
methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
|
||||
|
||||
// State enum
|
||||
DEBUG: 0,
|
||||
INFO: 1,
|
||||
WARN: 2,
|
||||
ERROR: 3,
|
||||
level: 3,
|
||||
|
||||
// can be overridden in the host environment
|
||||
log: function(level, obj) {
|
||||
if (logger.level <= level) {
|
||||
var method = logger.methodMap[level];
|
||||
if (typeof console !== 'undefined' && console[method]) {
|
||||
console[method].call(console, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.logger = logger;
|
||||
function log(level, obj) { logger.log(level, obj); }
|
||||
|
||||
exports.log = log;var createFrame = function(object) {
|
||||
var obj = {};
|
||||
Utils.extend(obj, object);
|
||||
return obj;
|
||||
};
|
||||
exports.createFrame = createFrame;
|
||||
},{"./exception":8,"./utils":11}],8:[function(require,module,exports){
|
||||
"use strict";
|
||||
|
||||
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
|
||||
|
||||
function Exception(message, node) {
|
||||
var line;
|
||||
if (node && node.firstLine) {
|
||||
line = node.firstLine;
|
||||
|
||||
message += ' - ' + line + ':' + node.firstColumn;
|
||||
}
|
||||
|
||||
var tmp = Error.prototype.constructor.call(this, message);
|
||||
|
||||
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
|
||||
for (var idx = 0; idx < errorProps.length; idx++) {
|
||||
this[errorProps[idx]] = tmp[errorProps[idx]];
|
||||
}
|
||||
|
||||
if (line) {
|
||||
this.lineNumber = line;
|
||||
this.column = node.firstColumn;
|
||||
}
|
||||
}
|
||||
|
||||
Exception.prototype = new Error();
|
||||
|
||||
exports["default"] = Exception;
|
||||
},{}],9:[function(require,module,exports){
|
||||
"use strict";
|
||||
var Utils = require("./utils");
|
||||
var Exception = require("./exception")["default"];
|
||||
var COMPILER_REVISION = require("./base").COMPILER_REVISION;
|
||||
var REVISION_CHANGES = require("./base").REVISION_CHANGES;
|
||||
|
||||
function checkRevision(compilerInfo) {
|
||||
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
|
||||
currentRevision = COMPILER_REVISION;
|
||||
|
||||
if (compilerRevision !== currentRevision) {
|
||||
if (compilerRevision < currentRevision) {
|
||||
var runtimeVersions = REVISION_CHANGES[currentRevision],
|
||||
compilerVersions = REVISION_CHANGES[compilerRevision];
|
||||
throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+
|
||||
"Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
|
||||
} else {
|
||||
// Use the embedded version info since the runtime doesn't know about this revision yet
|
||||
throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+
|
||||
"Please update your runtime to a newer version ("+compilerInfo[1]+").");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial
|
||||
|
||||
function template(templateSpec, env) {
|
||||
if (!env) {
|
||||
throw new Exception("No environment passed to template");
|
||||
}
|
||||
|
||||
// Note: Using env.VM references rather than local var references throughout this section to allow
|
||||
// for external users to override these as psuedo-supported APIs.
|
||||
var invokePartialWrapper = function(partial, name, context, helpers, partials, data) {
|
||||
var result = env.VM.invokePartial.apply(this, arguments);
|
||||
if (result != null) { return result; }
|
||||
|
||||
if (env.compile) {
|
||||
var options = { helpers: helpers, partials: partials, data: data };
|
||||
partials[name] = env.compile(partial, { data: data !== undefined }, env);
|
||||
return partials[name](context, options);
|
||||
} else {
|
||||
throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
|
||||
}
|
||||
};
|
||||
|
||||
// Just add water
|
||||
var container = {
|
||||
escapeExpression: Utils.escapeExpression,
|
||||
invokePartial: invokePartialWrapper,
|
||||
programs: [],
|
||||
program: function(i, fn, data) {
|
||||
var programWrapper = this.programs[i];
|
||||
if(data) {
|
||||
programWrapper = program(i, fn, data);
|
||||
} else if (!programWrapper) {
|
||||
programWrapper = this.programs[i] = program(i, fn);
|
||||
}
|
||||
return programWrapper;
|
||||
},
|
||||
merge: function(param, common) {
|
||||
var ret = param || common;
|
||||
|
||||
if (param && common && (param !== common)) {
|
||||
ret = {};
|
||||
Utils.extend(ret, common);
|
||||
Utils.extend(ret, param);
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
programWithDepth: env.VM.programWithDepth,
|
||||
noop: env.VM.noop,
|
||||
compilerInfo: null
|
||||
};
|
||||
|
||||
return function(context, options) {
|
||||
options = options || {};
|
||||
var namespace = options.partial ? options : env,
|
||||
helpers,
|
||||
partials;
|
||||
|
||||
if (!options.partial) {
|
||||
helpers = options.helpers;
|
||||
partials = options.partials;
|
||||
}
|
||||
var result = templateSpec.call(
|
||||
container,
|
||||
namespace, context,
|
||||
helpers,
|
||||
partials,
|
||||
options.data);
|
||||
|
||||
if (!options.partial) {
|
||||
env.VM.checkRevision(container.compilerInfo);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
exports.template = template;function programWithDepth(i, fn, data /*, $depth */) {
|
||||
var args = Array.prototype.slice.call(arguments, 3);
|
||||
|
||||
var prog = function(context, options) {
|
||||
options = options || {};
|
||||
|
||||
return fn.apply(this, [context, options.data || data].concat(args));
|
||||
};
|
||||
prog.program = i;
|
||||
prog.depth = args.length;
|
||||
return prog;
|
||||
}
|
||||
|
||||
exports.programWithDepth = programWithDepth;function program(i, fn, data) {
|
||||
var prog = function(context, options) {
|
||||
options = options || {};
|
||||
|
||||
return fn(context, options.data || data);
|
||||
};
|
||||
prog.program = i;
|
||||
prog.depth = 0;
|
||||
return prog;
|
||||
}
|
||||
|
||||
exports.program = program;function invokePartial(partial, name, context, helpers, partials, data) {
|
||||
var options = { partial: true, helpers: helpers, partials: partials, data: data };
|
||||
|
||||
if(partial === undefined) {
|
||||
throw new Exception("The partial " + name + " could not be found");
|
||||
} else if(partial instanceof Function) {
|
||||
return partial(context, options);
|
||||
}
|
||||
}
|
||||
|
||||
exports.invokePartial = invokePartial;function noop() { return ""; }
|
||||
|
||||
exports.noop = noop;
|
||||
},{"./base":7,"./exception":8,"./utils":11}],10:[function(require,module,exports){
|
||||
"use strict";
|
||||
// Build out our basic SafeString type
|
||||
function SafeString(string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
SafeString.prototype.toString = function() {
|
||||
return "" + this.string;
|
||||
};
|
||||
|
||||
exports["default"] = SafeString;
|
||||
},{}],11:[function(require,module,exports){
|
||||
"use strict";
|
||||
/*jshint -W004 */
|
||||
var SafeString = require("./safe-string")["default"];
|
||||
|
||||
var escape = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
"`": "`"
|
||||
};
|
||||
|
||||
var badChars = /[&<>"'`]/g;
|
||||
var possible = /[&<>"'`]/;
|
||||
|
||||
function escapeChar(chr) {
|
||||
return escape[chr] || "&";
|
||||
}
|
||||
|
||||
function extend(obj, value) {
|
||||
for(var key in value) {
|
||||
if(Object.prototype.hasOwnProperty.call(value, key)) {
|
||||
obj[key] = value[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.extend = extend;var toString = Object.prototype.toString;
|
||||
exports.toString = toString;
|
||||
// Sourced from lodash
|
||||
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
|
||||
var isFunction = function(value) {
|
||||
return typeof value === 'function';
|
||||
};
|
||||
// fallback for older versions of Chrome and Safari
|
||||
if (isFunction(/x/)) {
|
||||
isFunction = function(value) {
|
||||
return typeof value === 'function' && toString.call(value) === '[object Function]';
|
||||
};
|
||||
}
|
||||
var isFunction;
|
||||
exports.isFunction = isFunction;
|
||||
var isArray = Array.isArray || function(value) {
|
||||
return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
|
||||
};
|
||||
exports.isArray = isArray;
|
||||
|
||||
function escapeExpression(string) {
|
||||
// don't escape SafeStrings, since they're already safe
|
||||
if (string instanceof SafeString) {
|
||||
return string.toString();
|
||||
} else if (!string && string !== 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Force a string conversion as this will be done by the append regardless and
|
||||
// the regex test will do this transparently behind the scenes, causing issues if
|
||||
// an object's to string has escaped characters in it.
|
||||
string = "" + string;
|
||||
|
||||
if(!possible.test(string)) { return string; }
|
||||
return string.replace(badChars, escapeChar);
|
||||
}
|
||||
|
||||
exports.escapeExpression = escapeExpression;function isEmpty(value) {
|
||||
if (!value && value !== 0) {
|
||||
return true;
|
||||
} else if (isArray(value) && value.length === 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
exports.isEmpty = isEmpty;
|
||||
},{"./safe-string":10}],12:[function(require,module,exports){
|
||||
// Create a simple path alias to allow browserify to resolve
|
||||
// the runtime on a supported path.
|
||||
module.exports = require('./dist/cjs/handlebars.runtime');
|
||||
|
||||
},{"./dist/cjs/handlebars.runtime":6}],13:[function(require,module,exports){
|
||||
var $ = require('unopinionate').selector;
|
||||
|
||||
var $document = $(document),
|
||||
bindings = {};
|
||||
|
||||
var click = function(events) {
|
||||
click.bind.apply(click, arguments);
|
||||
return click;
|
||||
};
|
||||
|
||||
/*** Configuration Options ***/
|
||||
click.distanceLimit = 10;
|
||||
click.timeLimit = 140;
|
||||
|
||||
/*** Useful Properties ***/
|
||||
click.isTouch = ('ontouchstart' in window) ||
|
||||
window.DocumentTouch &&
|
||||
document instanceof DocumentTouch;
|
||||
|
||||
/*** Cached Functions ***/
|
||||
var onTouchstart = function(e) {
|
||||
e.stopPropagation(); //Prevents multiple click events from happening
|
||||
|
||||
click._doAnywheres(e);
|
||||
|
||||
var $this = $(this),
|
||||
startTime = new Date().getTime(),
|
||||
startPos = click._getPos(e);
|
||||
|
||||
$this.one('touchend', function(e) {
|
||||
e.preventDefault(); //Prevents click event from firing
|
||||
|
||||
var time = new Date().getTime() - startTime,
|
||||
endPos = click._getPos(e),
|
||||
distance = Math.sqrt(
|
||||
Math.pow(endPos.x - startPos.x, 2) +
|
||||
Math.pow(endPos.y - startPos.y, 2)
|
||||
);
|
||||
|
||||
if(time < click.timeLimit && distance < click.distanceLimit) {
|
||||
//Find the correct callback
|
||||
$.each(bindings, function(selector, callback) {
|
||||
if($this.is(selector)) {
|
||||
callback.apply(e.target, [e]);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*** API ***/
|
||||
click.bind = function(events) {
|
||||
|
||||
//Argument Surgery
|
||||
if(!$.isPlainObject(events)) {
|
||||
newEvents = {};
|
||||
newEvents[arguments[0]] = arguments[1];
|
||||
events = newEvents;
|
||||
}
|
||||
|
||||
$.each(events, function(selector, callback) {
|
||||
|
||||
/*** Register Binding ***/
|
||||
if(typeof bindings[selector] != 'undefined') {
|
||||
click.unbind(selector); //Ensure no duplicates
|
||||
}
|
||||
|
||||
bindings[selector] = callback;
|
||||
|
||||
/*** Touch Support ***/
|
||||
if(click.isTouch) {
|
||||
$document.delegate(selector, 'touchstart', onTouchstart);
|
||||
}
|
||||
|
||||
/*** Mouse Support ***/
|
||||
$document.delegate(selector, 'click', function(e) {
|
||||
e.stopPropagation(); //Prevents multiple click events from happening
|
||||
//click._doAnywheres(e); //Do anywheres first to be consistent with touch order
|
||||
callback.apply(this, [e]);
|
||||
});
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
click.unbind = function(selector) {
|
||||
$document
|
||||
.undelegate(selector, 'touchstart')
|
||||
.undelegate(selector, 'click');
|
||||
|
||||
delete bindings[selector];
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
click.unbindAll = function() {
|
||||
$.each(bindings, function(selector, callback) {
|
||||
$document
|
||||
.undelegate(selector, 'touchstart')
|
||||
.undelegate(selector, 'click');
|
||||
});
|
||||
|
||||
bindings = {};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
click.trigger = function(selector, e) {
|
||||
e = e || $.Event('click');
|
||||
|
||||
if(typeof bindings[selector] != 'undefined') {
|
||||
bindings[selector](e);
|
||||
}
|
||||
else {
|
||||
console.error("No click events bound for selector '"+selector+"'.");
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
click.anywhere = function(callback) {
|
||||
click._anywheres.push(callback);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*** Internal (but useful) Methods ***/
|
||||
click._getPos = function(e) {
|
||||
e = e.originalEvent;
|
||||
|
||||
if(e.pageX || e.pageY) {
|
||||
return {
|
||||
x: e.pageX,
|
||||
y: e.pageY
|
||||
};
|
||||
}
|
||||
else if(e.changedTouches) {
|
||||
return {
|
||||
x: e.changedTouches[0].clientX,
|
||||
y: e.changedTouches[0].clientY
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
x: e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
|
||||
y: e.clientY + document.body.scrollTop + document.documentElement.scrollTop
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
click._anywheres = [];
|
||||
|
||||
click._doAnywheres = function(e) {
|
||||
var i = click._anywheres.length;
|
||||
while(i--) {
|
||||
click._anywheres[i](e);
|
||||
}
|
||||
};
|
||||
|
||||
$(document).bind('mousedown', click._doAnywheres);
|
||||
|
||||
module.exports = click;
|
||||
|
||||
|
||||
},{"unopinionate":16}],14:[function(require,module,exports){
|
||||
var $ = require('unopinionate').selector;
|
||||
|
||||
var bodyScrollers = [];
|
||||
|
||||
$(function() {
|
||||
var $html = $('html'),
|
||||
$body = $('body');
|
||||
|
||||
$(window, document, 'body').bind('scroll touchmove', function() {
|
||||
var top = $html[0].scrollTop || $body[0].scrollTop;
|
||||
|
||||
for(var i=0; i<bodyScrollers.length; i++) {
|
||||
bodyScrollers[i](top);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var onScroll = function(callback) {
|
||||
bodyScrollers.push(callback);
|
||||
};
|
||||
|
||||
module.exports = onScroll;
|
||||
},{"unopinionate":16}],15:[function(require,module,exports){
|
||||
(function(root) {
|
||||
var callbacks = [];
|
||||
|
||||
var transitionComplete = function(callback) {
|
||||
if(callbacks.length === 0) {
|
||||
setEvent();
|
||||
}
|
||||
|
||||
callbacks.push(callback);
|
||||
};
|
||||
|
||||
function setEvent() {
|
||||
document.addEventListener(eventName(), function() {
|
||||
var i = callbacks.length;
|
||||
while(i--) {
|
||||
callbacks[i]();
|
||||
}
|
||||
|
||||
callbacks = [];
|
||||
});
|
||||
}
|
||||
|
||||
var _eventName;
|
||||
|
||||
function eventName() {
|
||||
if(!_eventName) {
|
||||
// Sourced from: http://stackoverflow.com/questions/5023514/how-do-i-normalize-css3-transition-functions-across-browsers
|
||||
var el = document.createElement('fakeelement');
|
||||
transitions = {
|
||||
transition: 'transitionend',
|
||||
OTransition: 'oTransitionEnd',
|
||||
MozTransition: 'transitionend',
|
||||
WebkitTransition: 'webkitTransitionEnd'
|
||||
};
|
||||
|
||||
for(var t in transitions) {
|
||||
if(el.style[t] !== undefined) {
|
||||
_eventName = transitions[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _eventName;
|
||||
}
|
||||
|
||||
/*** Export ***/
|
||||
|
||||
// AMD
|
||||
if(typeof define === 'function' && define.amd) {
|
||||
define([], function() {
|
||||
return transitionComplete;
|
||||
});
|
||||
}
|
||||
// CommonJS
|
||||
else if(typeof exports !== 'undefined') {
|
||||
module.exports = transitionComplete;
|
||||
}
|
||||
// Browser Global
|
||||
else {
|
||||
root.transitionComplete = transitionComplete;
|
||||
}
|
||||
})(this);
|
||||
|
||||
},{}],16:[function(require,module,exports){
|
||||
(function (global){
|
||||
(function(root) {
|
||||
var unopinionate = {
|
||||
selector: root.jQuery || root.Zepto || root.ender || root.$,
|
||||
template: root.Handlebars || root.Mustache
|
||||
};
|
||||
|
||||
/*** Export ***/
|
||||
|
||||
//AMD
|
||||
if(typeof define === 'function' && define.amd) {
|
||||
define([], function() {
|
||||
return unopinionate;
|
||||
});
|
||||
}
|
||||
//CommonJS
|
||||
else if(typeof module.exports !== 'undefined') {
|
||||
module.exports = unopinionate;
|
||||
}
|
||||
//Global
|
||||
else {
|
||||
root.unopinionate = unopinionate;
|
||||
}
|
||||
})(typeof window != 'undefined' ? window : global);
|
||||
|
||||
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{}]},{},[4])
|
@ -6,6 +6,7 @@ var async = require('async')
|
||||
, mystreams = require('./streams')
|
||||
, utils = require('./utils')
|
||||
, Logger = require('./logger')
|
||||
, localList = require('./local-list');
|
||||
|
||||
//
|
||||
// Implements Storage interface
|
||||
@ -173,6 +174,10 @@ Storage.prototype.add_tarball = function(name, filename) {
|
||||
return this.local.add_tarball(name, filename)
|
||||
}
|
||||
|
||||
Storage.prototype.get_readme = function(name, version, callback) {
|
||||
return this.local.get_readme(name, version, callback);
|
||||
};
|
||||
|
||||
//
|
||||
// Get a tarball from a storage for {name} package
|
||||
//
|
||||
@ -406,6 +411,34 @@ Storage.prototype.search = function(startkey, options, callback) {
|
||||
remote_search()
|
||||
}
|
||||
|
||||
Storage.prototype.get_local = function(callback) {
|
||||
var self = this
|
||||
, locals = localList.get()
|
||||
, packages = [];
|
||||
|
||||
var getPackage = function(i) {
|
||||
self.get_package(locals[i], function(err, info) {
|
||||
var latest = info['dist-tags'].latest;
|
||||
|
||||
packages.push(info.versions[latest]);
|
||||
|
||||
if(err || i >= locals.length - 1) {
|
||||
callback(err, packages);
|
||||
}
|
||||
else {
|
||||
getPackage(i + 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if(locals.length) {
|
||||
getPackage(0);
|
||||
}
|
||||
else {
|
||||
callback(null, []);
|
||||
}
|
||||
};
|
||||
|
||||
// function fetches package information from uplinks and synchronizes it with local data
|
||||
// if package is available locally, it MUST be provided in pkginfo
|
||||
// returns callback(err, result, uplink_errors)
|
||||
|
37
lib/users.js
Normal file
37
lib/users.js
Normal file
@ -0,0 +1,37 @@
|
||||
var fs = require('fs')
|
||||
, crypto = require('crypto')
|
||||
, usersPath = './users.json';
|
||||
|
||||
var Users = function() {
|
||||
if(fs.existsSync(usersPath)) {
|
||||
this.users = JSON.parse(fs.readFileSync(usersPath, 'utf8'));
|
||||
}
|
||||
else {
|
||||
this.users = {};
|
||||
}
|
||||
};
|
||||
|
||||
Users.prototype = {
|
||||
add: function(params, callback) {
|
||||
//Hash the Password
|
||||
if(params.password) {
|
||||
params.password = crypto.createHash('sha1').update(params.password).digest('hex');
|
||||
}
|
||||
else if(params.password_sha) {
|
||||
params.password = params.password_sha;
|
||||
}
|
||||
|
||||
//Save
|
||||
this.users[params.name] = params;
|
||||
this.sync(callback);
|
||||
},
|
||||
remove: function(name, callback) {
|
||||
delete this.users[name];
|
||||
this.sync(callback);
|
||||
},
|
||||
sync: function(callback) {
|
||||
fs.writeFile(usersPath, JSON.stringify(this.users), callback);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = new Users();
|
19
package.yaml
19
package.yaml
@ -28,6 +28,17 @@ dependencies:
|
||||
minimatch: '>= 0.2.14'
|
||||
bunyan: '>= 0.22.1'
|
||||
mkdirp: '>= 0.3.5'
|
||||
handlebars: '1.x.x'
|
||||
helpers.less: 'git://github.com/bpeacock/helpers.less.git'
|
||||
highlight.js: '^8.0.0'
|
||||
lunr: '^0.5.2'
|
||||
marked: '^0.3.2'
|
||||
onclick: '^0.1.0'
|
||||
onscroll: '0.0.3'
|
||||
tar.gz: '^0.1.1'
|
||||
transition-complete: '0.0.2'
|
||||
underscore: '^1.6.0'
|
||||
unopinionate: '0.0.4'
|
||||
|
||||
optionalDependencies:
|
||||
fs-ext: '>= 0.3.2'
|
||||
@ -44,6 +55,13 @@ devDependencies:
|
||||
# installed, but I don't want it to be installed everytime
|
||||
#heapdump: '*'
|
||||
|
||||
browserify: '^3.46.0'
|
||||
browserify-handlebars: '~0.2.0'
|
||||
grunt: '^0.4.4'
|
||||
grunt-browserify: '^2.0.8'
|
||||
grunt-contrib-less: '^0.11.0'
|
||||
grunt-contrib-watch: '^0.6.1'
|
||||
|
||||
keywords:
|
||||
- private
|
||||
- package
|
||||
@ -71,4 +89,3 @@ publishConfig:
|
||||
license:
|
||||
type: WTFPL
|
||||
url: http://www.wtfpl.net/txt/copying/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user