├── misc ├── Press_Release.txt ├── .dockerignore ├── server-old.zip ├── docker-compose.yml ├── Dockerfile └── addRemotes ├── client ├── assets │ ├── n.png │ ├── n_s.png │ ├── gh_mk.png │ ├── gh_oc.jpg │ ├── subl.png │ ├── N_square.png │ ├── avatar.png │ ├── gh_eh.jpeg │ ├── gh_gy.jpeg │ ├── n_white.png │ ├── nfavicon.png │ ├── photo.jpeg │ ├── subl_bw.png │ ├── n_blue_lg.png │ ├── n_white_lg.png │ ├── n_square_big.png │ ├── octocat_white.png │ ├── material-icons-font.woff2 │ ├── material-icons.css │ └── codemirror-themes │ │ ├── eclipse.css │ │ ├── cobalt.css │ │ ├── rubyblue.css │ │ ├── yeti.css │ │ ├── zenburn.css │ │ ├── 3024-day.css │ │ ├── paraiso-light.css │ │ ├── twilight.css │ │ ├── material.css │ │ └── mdn-like.css ├── font │ ├── roboto │ │ ├── Roboto-Bold.eot │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Bold.woff │ │ ├── Roboto-Bold.woff2 │ │ ├── Roboto-Light.eot │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-Light.woff │ │ ├── Roboto-Medium.eot │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-Thin.eot │ │ ├── Roboto-Thin.ttf │ │ ├── Roboto-Thin.woff │ │ ├── Roboto-Thin.woff2 │ │ ├── Roboto-Light.woff2 │ │ ├── Roboto-Medium.woff │ │ ├── Roboto-Medium.woff2 │ │ ├── Roboto-Regular.eot │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Regular.woff │ │ └── Roboto-Regular.woff2 │ └── material-design-icons │ │ ├── Material-Design-Icons.eot │ │ ├── Material-Design-Icons.ttf │ │ ├── Material-Design-Icons.woff │ │ └── Material-Design-Icons.woff2 ├── nevercode-sublime-setup.zip ├── js │ └── tinymce │ │ ├── plugins │ │ ├── media │ │ │ └── moxieplayer.swf │ │ ├── emoticons │ │ │ ├── img │ │ │ │ ├── smiley-cool.gif │ │ │ │ ├── smiley-cry.gif │ │ │ │ ├── smiley-frown.gif │ │ │ │ ├── smiley-kiss.gif │ │ │ │ ├── smiley-smile.gif │ │ │ │ ├── smiley-wink.gif │ │ │ │ ├── smiley-yell.gif │ │ │ │ ├── smiley-sealed.gif │ │ │ │ ├── smiley-embarassed.gif │ │ │ │ ├── smiley-innocent.gif │ │ │ │ ├── smiley-laughing.gif │ │ │ │ ├── smiley-surprised.gif │ │ │ │ ├── smiley-tongue-out.gif │ │ │ │ ├── smiley-undecided.gif │ │ │ │ ├── smiley-money-mouth.gif │ │ │ │ └── smiley-foot-in-mouth.gif │ │ │ └── plugin.min.js │ │ ├── print │ │ │ └── plugin.min.js │ │ ├── hr │ │ │ └── plugin.min.js │ │ ├── nonbreaking │ │ │ └── plugin.min.js │ │ ├── code │ │ │ └── plugin.min.js │ │ ├── directionality │ │ │ └── plugin.min.js │ │ ├── contextmenu │ │ │ └── plugin.min.js │ │ ├── wordcount │ │ │ └── plugin.min.js │ │ ├── noneditable │ │ │ └── plugin.min.js │ │ ├── save │ │ │ └── plugin.min.js │ │ ├── visualblocks │ │ │ ├── plugin.min.js │ │ │ └── css │ │ │ │ └── visualblocks.css │ │ ├── colorpicker │ │ │ └── plugin.min.js │ │ ├── pagebreak │ │ │ └── plugin.min.js │ │ ├── visualchars │ │ │ └── plugin.min.js │ │ ├── tabfocus │ │ │ └── plugin.min.js │ │ ├── preview │ │ │ └── plugin.min.js │ │ ├── autoresize │ │ │ └── plugin.min.js │ │ ├── autolink │ │ │ └── plugin.min.js │ │ ├── insertdatetime │ │ │ └── plugin.min.js │ │ ├── autosave │ │ │ └── plugin.min.js │ │ ├── importcss │ │ │ └── plugin.min.js │ │ ├── textpattern │ │ │ └── plugin.min.js │ │ ├── layer │ │ │ └── plugin.min.js │ │ ├── codesample │ │ │ └── css │ │ │ │ └── prism.css │ │ ├── bbcode │ │ │ └── plugin.min.js │ │ ├── legacyoutput │ │ │ └── plugin.min.js │ │ ├── textcolor │ │ │ └── plugin.min.js │ │ ├── template │ │ │ └── plugin.min.js │ │ └── link │ │ │ └── plugin.min.js │ │ └── skins │ │ └── lightgray │ │ ├── img │ │ ├── anchor.gif │ │ ├── loader.gif │ │ ├── object.gif │ │ └── trans.gif │ │ ├── fonts │ │ ├── tinymce.eot │ │ ├── tinymce.ttf │ │ ├── tinymce.woff │ │ ├── tinymce-small.eot │ │ ├── tinymce-small.ttf │ │ └── tinymce-small.woff │ │ ├── content.inline.min.css │ │ └── content.min.css ├── app │ ├── services │ │ ├── index.js │ │ ├── Public.js │ │ ├── UrlEncoding.js │ │ ├── Auth.js │ │ ├── Folders.js │ │ └── Snippets.js │ ├── modals │ │ ├── index.js │ │ ├── foldermodal │ │ │ ├── foldermodal.html │ │ │ └── foldermodal.js │ │ ├── editormodal │ │ │ ├── editormodal.js │ │ │ └── editorModal.html │ │ ├── movemodal │ │ │ ├── moveModal.html │ │ │ └── moveModal.js │ │ └── authmodals │ │ │ ├── authmodal.js │ │ │ ├── signin.html │ │ │ └── signup.html │ ├── controllers │ │ ├── main │ │ │ ├── about │ │ │ │ ├── about.js │ │ │ │ └── about.html │ │ │ ├── editor │ │ │ │ ├── snippets │ │ │ │ │ ├── favorites.html │ │ │ │ │ └── snippets.js │ │ │ │ ├── search │ │ │ │ │ ├── search.js │ │ │ │ │ └── search.html │ │ │ │ └── profile │ │ │ │ │ ├── profile.js │ │ │ │ │ └── profile.html │ │ │ ├── download │ │ │ │ ├── download.js │ │ │ │ └── download.html │ │ │ ├── public │ │ │ │ ├── public.js │ │ │ │ └── public.html │ │ │ └── main.js │ │ └── index.js │ ├── redux │ │ ├── actions.js │ │ ├── reducers.js │ │ └── fileTree.js │ └── app.js ├── index.html └── styles │ └── materialize.scss ├── user-server ├── noncluster.js ├── server.js ├── config │ ├── middleware.js │ ├── routes.js │ └── utils.js ├── cluster.js └── models │ └── users.js ├── files-server ├── noncluster.js ├── server.js ├── config │ ├── middleware.js │ ├── utils.js │ └── routes.js ├── cluster.js └── models │ └── snippets.js ├── .jshintignore ├── README.md ├── .jshintrc ├── .gitignore ├── setup.example.js ├── webpack.config.js ├── test └── TestingOutline.txt ├── nginx-server └── nevercode.com ├── Gruntfile.js └── package.json /misc/Press_Release.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /misc/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | .editorconfig 4 | node_modules 5 | *.log 6 | -------------------------------------------------------------------------------- /client/assets/n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/n.png -------------------------------------------------------------------------------- /client/assets/n_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/n_s.png -------------------------------------------------------------------------------- /misc/server-old.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/misc/server-old.zip -------------------------------------------------------------------------------- /client/assets/gh_mk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/gh_mk.png -------------------------------------------------------------------------------- /client/assets/gh_oc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/gh_oc.jpg -------------------------------------------------------------------------------- /client/assets/subl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/subl.png -------------------------------------------------------------------------------- /user-server/noncluster.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let startServer = require('./server.js'); 3 | 4 | startServer(); 5 | -------------------------------------------------------------------------------- /client/assets/N_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/N_square.png -------------------------------------------------------------------------------- /client/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/avatar.png -------------------------------------------------------------------------------- /client/assets/gh_eh.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/gh_eh.jpeg -------------------------------------------------------------------------------- /client/assets/gh_gy.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/gh_gy.jpeg -------------------------------------------------------------------------------- /client/assets/n_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/n_white.png -------------------------------------------------------------------------------- /client/assets/nfavicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/nfavicon.png -------------------------------------------------------------------------------- /client/assets/photo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/photo.jpeg -------------------------------------------------------------------------------- /client/assets/subl_bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/subl_bw.png -------------------------------------------------------------------------------- /files-server/noncluster.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let startServer = require('./server.js'); 3 | 4 | startServer(); 5 | -------------------------------------------------------------------------------- /client/assets/n_blue_lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/n_blue_lg.png -------------------------------------------------------------------------------- /client/assets/n_white_lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/n_white_lg.png -------------------------------------------------------------------------------- /client/assets/n_square_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/n_square_big.png -------------------------------------------------------------------------------- /client/assets/octocat_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/octocat_white.png -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Bold.eot -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Light.eot -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Medium.eot -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Thin.eot -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /client/nevercode-sublime-setup.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/nevercode-sublime-setup.zip -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Regular.eot -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /client/assets/material-icons-font.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/assets/material-icons-font.woff2 -------------------------------------------------------------------------------- /client/font/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /client/js/tinymce/plugins/media/moxieplayer.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/media/moxieplayer.swf -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/img/anchor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/img/anchor.gif -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/img/loader.gif -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/img/object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/img/object.gif -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/img/trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/img/trans.gif -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/fonts/tinymce.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/fonts/tinymce.eot -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/fonts/tinymce.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/fonts/tinymce.ttf -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/fonts/tinymce.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/fonts/tinymce.woff -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | client/js 3 | /client/assets 4 | /client/dist 5 | /client/font 6 | test/ 7 | setup.example.js 8 | setup.js 9 | /client/app/tinymce 10 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-cool.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-cool.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-cry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-cry.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-frown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-frown.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-kiss.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-kiss.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-smile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-smile.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-wink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-wink.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-yell.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-yell.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-sealed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-sealed.gif -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/fonts/tinymce-small.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/fonts/tinymce-small.eot -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/fonts/tinymce-small.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/fonts/tinymce-small.ttf -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/fonts/tinymce-small.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/skins/lightgray/fonts/tinymce-small.woff -------------------------------------------------------------------------------- /client/font/material-design-icons/Material-Design-Icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/material-design-icons/Material-Design-Icons.eot -------------------------------------------------------------------------------- /client/font/material-design-icons/Material-Design-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/material-design-icons/Material-Design-Icons.ttf -------------------------------------------------------------------------------- /client/font/material-design-icons/Material-Design-Icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/material-design-icons/Material-Design-Icons.woff -------------------------------------------------------------------------------- /client/font/material-design-icons/Material-Design-Icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/font/material-design-icons/Material-Design-Icons.woff2 -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-embarassed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-embarassed.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-innocent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-innocent.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-laughing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-laughing.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-surprised.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-surprised.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-tongue-out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-tongue-out.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-undecided.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-undecided.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-money-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-money-mouth.gif -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precocious-tangerine/nevercode/HEAD/client/js/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Stories in Ready](https://badge.waffle.io/precocious-tangerine/evercode.png?label=ready&title=Ready)](https://waffle.io/precocious-tangerine/evercode) 2 | #nevercode 3 | Helping engineers build their personal code library. 4 | -------------------------------------------------------------------------------- /client/app/services/index.js: -------------------------------------------------------------------------------- 1 | import Snippets from './Snippets.js'; 2 | import Public from './Public.js'; 3 | import Folders from './Folders.js'; 4 | import Auth from './Auth.js'; 5 | import UrlEncoding from './UrlEncoding.js'; 6 | 7 | 8 | export {Snippets, Public, Folders, Auth, UrlEncoding}; -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | 4 | "curly": true, 5 | "latedef": true, 6 | "quotmark": true, 7 | "unused": true, 8 | "trailing": true, 9 | "esversion": 6, 10 | "browser": true, 11 | "undef": true, 12 | "predef": ["angular", "-Promise", "Materialize", "$"], 13 | "-W138": false 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/print/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("print",function(a){a.addCommand("mcePrint",function(){a.getWin().print()}),a.addButton("print",{title:"Print",cmd:"mcePrint"}),a.addShortcut("Meta+P","","mcePrint"),a.addMenuItem("print",{text:"Print",cmd:"mcePrint",icon:"print",shortcut:"Meta+P",context:"file"})}); -------------------------------------------------------------------------------- /misc/docker-compose.yml: -------------------------------------------------------------------------------- 1 | evercode: 2 | image: orlandoc1618/pt-evercode:v3 3 | links: 4 | - redis 5 | - mongodb 6 | ports: 7 | - "3000:3000" 8 | 9 | mongodb: 10 | image: mongo 11 | ports: 12 | - "27017" 13 | 14 | redis: 15 | image: redis 16 | ports: 17 | - "6379" 18 | command: redis-server -------------------------------------------------------------------------------- /client/app/modals/index.js: -------------------------------------------------------------------------------- 1 | import createEditorModal from './editormodal/editormodal.js'; 2 | import createFolderModal from './foldermodal/foldermodal.js'; 3 | import createAuthModal from './authmodals/authmodal.js'; 4 | import createMoveModal from './movemodal/moveModal.js'; 5 | 6 | export {createAuthModal, createFolderModal, createEditorModal, createMoveModal}; -------------------------------------------------------------------------------- /client/js/tinymce/plugins/hr/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("hr",function(a){a.addCommand("InsertHorizontalRule",function(){a.execCommand("mceInsertContent",!1,"
")}),a.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),a.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})}); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #server 2 | /files-server/setup.js 3 | /files-server/gmail-credentials.json 4 | /files-server/client_secret.json 5 | /user-server/setup.js 6 | /user-server/setup.js 7 | /user-server/gmail-credentials.json 8 | 9 | setup.js 10 | 11 | #client 12 | client/lib/* 13 | client/dist/* 14 | client/styles/materialize.css 15 | 16 | #npm_files 17 | /node_modules/* 18 | *.rdb 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /client/app/controllers/main/about/about.js: -------------------------------------------------------------------------------- 1 | class AboutCtrl { 2 | constructor() { 3 | } 4 | } 5 | 6 | const aboutPage = () => { 7 | return { 8 | url: '/about', 9 | controllerAs: 'aboutCtrl', 10 | controller: AboutCtrl, 11 | template: require('./about.html'), 12 | scope: {}, 13 | access: {restricted: false} 14 | }; 15 | }; 16 | 17 | export default aboutPage; 18 | 19 | -------------------------------------------------------------------------------- /setup.example.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | githubClientId: '', 3 | githubSecret: '', 4 | githubCallback: 'user/auth/github/callback', 5 | mongodbHost: 'mongodb://127.0.0.1', 6 | mongodbUsersName: '/neverCodeUsers', 7 | mongodbFilesName: '/neverCodeFiles', 8 | mongodbPort: ':27017', 9 | secretToken: '', 10 | verificationEmailRoute: 'user/email-verification', 11 | email: '', 12 | emailPassword: '' 13 | }; 14 | -------------------------------------------------------------------------------- /misc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:argon 2 | RUN npm install -g lodash 3 | RUN npm install -g bluebird 4 | RUN npm install -g webpack 5 | 6 | 7 | # Create app directory 8 | RUN mkdir -p /usr/src/app 9 | WORKDIR /usr/src/app 10 | 11 | # Install app dependencies 12 | COPY package.json /usr/src/app/ 13 | RUN npm install 14 | RUN npm install --save lodash 15 | 16 | # Bundle app source 17 | COPY . /usr/src/app 18 | 19 | EXPOSE 6379 20 | EXPOSE 3000 21 | 22 | RUN webpack 23 | CMD [ "npm", "start" ] 24 | 25 | -------------------------------------------------------------------------------- /files-server/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let express = require('express'); 3 | let app = express(); 4 | 5 | require(__dirname + '/config/middleware.js')(app, express); 6 | require(__dirname + '/config/routes.js')(app, express); 7 | const port = process.env.PORT || 3002; 8 | 9 | 10 | const startServer = () => { 11 | console.log(`server running on port ${port} in ${process.env.NODE_ENV} mode`); 12 | app.listen(port); 13 | }; 14 | // export our app for testing and flexibility, required by index.js 15 | module.exports = startServer; -------------------------------------------------------------------------------- /user-server/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let express = require('express'); 3 | let app = express(); 4 | 5 | require(__dirname + '/config/middleware.js')(app, express); 6 | require(__dirname + '/config/routes.js')(app, express); 7 | const port = process.env.PORT || 3003; 8 | 9 | 10 | const startServer = () => { 11 | console.log(`server running on port ${port} in ${process.env.NODE_ENV} mode`); 12 | app.listen(port); 13 | }; 14 | // export our app for testing and flexibility, required by index.js 15 | module.exports = startServer; -------------------------------------------------------------------------------- /client/app/controllers/index.js: -------------------------------------------------------------------------------- 1 | import mainPage from './main/main.js'; 2 | import publicPage from './main/public/public.js'; 3 | import {editor} from './main/editor/editor.js'; 4 | import snippets from './main/editor/snippets/snippets.js'; 5 | import search from './main/editor/search/search.js'; 6 | import profile from './main/editor/profile/profile.js'; 7 | import downloadPage from './main/download/download.js'; 8 | import aboutPage from './main/about/about.js'; 9 | 10 | export {mainPage, publicPage, editor, snippets, profile, downloadPage, aboutPage, search}; -------------------------------------------------------------------------------- /files-server/config/middleware.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let morgan = require('morgan'); 3 | let bodyParser = require('body-parser'); 4 | let utils = require('./utils.js'); 5 | 6 | module.exports = (app) => { 7 | app.use(morgan('dev')); 8 | app.use(bodyParser.urlencoded({ extended: true })); 9 | app.use(bodyParser.json()); 10 | app.use((req, res, next) => { 11 | res.header('Access-Control-Allow-Origin', '*'); 12 | res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); 13 | next(); 14 | }); 15 | app.use('/files/api', utils.decode); 16 | }; 17 | -------------------------------------------------------------------------------- /user-server/config/middleware.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let morgan = require('morgan'); 3 | let bodyParser = require('body-parser'); 4 | let utils = require('./utils.js'); 5 | 6 | module.exports = (app) => { 7 | app.use(morgan('dev')); 8 | app.use(bodyParser.urlencoded({ extended: true })); 9 | app.use(bodyParser.json()); 10 | app.use((req, res, next) => { 11 | res.header('Access-Control-Allow-Origin', '*'); 12 | res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); 13 | next(); 14 | }); 15 | app.use('/user/api', utils.decode); 16 | }; 17 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | devtool: 'source-map', 5 | entry: [ 6 | path.join(__dirname, 'client/app/app.js') 7 | ], 8 | output: { 9 | path: path.join(__dirname, 'client/dist'), 10 | filename: 'bundle.js' 11 | }, 12 | module: { 13 | preLoaders: [{ 14 | text: /(\.js|\.html)$/, 15 | loader: 'source-map-loader' 16 | }], 17 | loaders: [{ 18 | test: /\.js$/, 19 | loader: 'babel', 20 | exclude: /node_modules/, 21 | query: { 22 | presets: ['es2015'] 23 | } 24 | }, { 25 | test: /\.html$/, 26 | loader: 'raw' 27 | }] 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/nonbreaking/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("nonbreaking",function(a){var b=a.getParam("nonbreaking_force_tab");if(a.addCommand("mceNonBreaking",function(){a.insertContent(a.plugins.visualchars&&a.plugins.visualchars.state?' ':" "),a.dom.setAttrib(a.dom.select("span.mce-nbsp"),"data-mce-bogus","1")}),a.addButton("nonbreaking",{title:"Nonbreaking space",cmd:"mceNonBreaking"}),a.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),b){var c=+b>1?+b:3;a.on("keydown",function(b){if(9==b.keyCode){if(b.shiftKey)return;b.preventDefault();for(var d=0;c>d;d++)a.execCommand("mceNonBreaking")}})}}); -------------------------------------------------------------------------------- /files-server/config/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let setup = require('../../setup.js'); 3 | let jwt = require('jsonwebtoken'); 4 | let secret = setup.secretToken; 5 | 6 | 7 | module.exports.createJWT = (user) => { 8 | let payload = { 9 | username: user.username, 10 | email: user.email 11 | }; 12 | return jwt.sign(payload, secret); 13 | }; 14 | 15 | module.exports.decode = (req, res, next) => { 16 | let token = req.headers.authorization; 17 | if (!token) { 18 | return res.status(403).send('Please login'); 19 | } 20 | try { 21 | req.user = jwt.decode(token, secret); 22 | next(); 23 | } catch (error) { 24 | return next(error); 25 | } 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /client/assets/material-icons.css: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: local('Material Icons'), local('MaterialIcons-Regular'), url('./material-icons-font.woff2') format('woff2'); 7 | } 8 | 9 | .material-icons { 10 | font-family: 'Material Icons'; 11 | font-weight: normal; 12 | font-style: normal; 13 | font-size: 24px; 14 | line-height: 1; 15 | letter-spacing: normal; 16 | text-transform: none; 17 | display: inline-block; 18 | white-space: nowrap; 19 | word-wrap: normal; 20 | direction: ltr; 21 | -webkit-font-feature-settings: 'liga'; 22 | -webkit-font-smoothing: antialiased; 23 | } 24 | -------------------------------------------------------------------------------- /files-server/cluster.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let cluster = require('cluster'); 3 | const numOfCPUs = require('os').cpus().length; 4 | 5 | if (cluster.isMaster) { 6 | 7 | console.log(`Master cluster setting up ${numOfCPUs} workers`); 8 | for (let i = 0; i < numOfCPUs; i++) { 9 | cluster.fork(); 10 | } 11 | 12 | cluster.on('online', (worker) => { 13 | console.log(`Worker ${worker.process.pid} is online`); 14 | }); 15 | 16 | cluster.on('exit', (worker) => { 17 | console.log(`worker ${worker.process.pid} died`); 18 | console.log('Starting a new worker'); 19 | cluster.fork(); 20 | }); 21 | } else { 22 | let startServer = require('./server.js'); 23 | startServer(); 24 | } 25 | -------------------------------------------------------------------------------- /user-server/cluster.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let cluster = require('cluster'); 3 | const numOfCPUs = require('os').cpus().length; 4 | 5 | if (cluster.isMaster) { 6 | 7 | console.log(`Master cluster setting up ${numOfCPUs} workers`); 8 | for (let i = 0; i < numOfCPUs; i++) { 9 | cluster.fork(); 10 | } 11 | 12 | cluster.on('online', (worker) => { 13 | console.log(`Worker ${worker.process.pid} is online`); 14 | }); 15 | 16 | cluster.on('exit', (worker) => { 17 | console.log(`worker ${worker.process.pid} died`); 18 | console.log('Starting a new worker'); 19 | cluster.fork(); 20 | }); 21 | } else { 22 | let startServer = require('./server.js'); 23 | startServer(); 24 | } 25 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/code/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("code",function(a){function b(){var b=a.windowManager.open({title:"Source code",body:{type:"textbox",name:"code",multiline:!0,minWidth:a.getParam("code_dialog_width",600),minHeight:a.getParam("code_dialog_height",Math.min(tinymce.DOM.getViewPort().h-200,500)),spellcheck:!1,style:"direction: ltr; text-align: left"},onSubmit:function(b){a.focus(),a.undoManager.transact(function(){a.setContent(b.data.code)}),a.selection.setCursorLocation(),a.nodeChanged()}});b.find("#code").value(a.getContent({source_view:!0}))}a.addCommand("mceCodeEditor",b),a.addButton("code",{icon:"code",tooltip:"Source code",onclick:b}),a.addMenuItem("code",{icon:"code",text:"Source code",context:"tools",onclick:b})}); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/directionality/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("directionality",function(a){function b(b){var c,d=a.dom,e=a.selection.getSelectedBlocks();e.length&&(c=d.getAttrib(e[0],"dir"),tinymce.each(e,function(a){d.getParent(a.parentNode,"*[dir='"+b+"']",d.getRoot())||(c!=b?d.setAttrib(a,"dir",b):d.setAttrib(a,"dir",null))}),a.nodeChanged())}function c(a){var b=[];return tinymce.each("h1 h2 h3 h4 h5 h6 div p".split(" "),function(c){b.push(c+"[dir="+a+"]")}),b.join(",")}a.addCommand("mceDirectionLTR",function(){b("ltr")}),a.addCommand("mceDirectionRTL",function(){b("rtl")}),a.addButton("ltr",{title:"Left to right",cmd:"mceDirectionLTR",stateSelector:c("ltr")}),a.addButton("rtl",{title:"Right to left",cmd:"mceDirectionRTL",stateSelector:c("rtl")})}); -------------------------------------------------------------------------------- /client/app/modals/foldermodal/foldermodal.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | X 7 |
8 |
9 | Change folder name: 10 |
11 |
12 |
13 |
14 | 15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /client/js/tinymce/plugins/contextmenu/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("contextmenu",function(a){var b,c=a.settings.contextmenu_never_use_native;a.on("contextmenu",function(d){var e,f=a.getDoc();if(!d.ctrlKey||c){if(d.preventDefault(),tinymce.Env.mac&&tinymce.Env.webkit&&2==d.button&&f.caretRangeFromPoint&&a.selection.setRng(f.caretRangeFromPoint(d.x,d.y)),e=a.settings.contextmenu||"link image inserttable | cell row column deletetable",b)b.show();else{var g=[];tinymce.each(e.split(/[ ,]/),function(b){var c=a.menuItems[b];"|"==b&&(c={text:b}),c&&(c.shortcut="",g.push(c))});for(var h=0;h { 4 | return { 5 | restrict: 'E', 6 | scope: { 7 | show: '=' 8 | }, 9 | link(scope, element, attrs) { 10 | scope.dialogStyle = {}; 11 | if (scope.editorModal.publicList && attrs.snippetPath) { 12 | scope.editorModal.snippetObj = scope.editorModal.publicList[attrs.snippetPath] || {}; 13 | } 14 | if (attrs.width) { 15 | scope.dialogStyle.width = attrs.width; 16 | } 17 | if (attrs.height) { 18 | scope.dialogStyle.height = attrs.height; 19 | } 20 | }, 21 | controllerAs: 'editorModal', 22 | controller: EditorCtrl, 23 | bindToController: true, 24 | template: require(`./editorModal.html`), 25 | url: '/editor' 26 | }; 27 | }; 28 | 29 | export default createEditorModal; 30 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/emoticons/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("emoticons",function(a,b){function c(){var a;return a='',tinymce.each(d,function(c){a+="",tinymce.each(c,function(c){var d=b+"/img/smiley-"+c+".gif";a+=''}),a+=""}),a+="
"}var d=[["cool","cry","embarassed","foot-in-mouth"],["frown","innocent","kiss","laughing"],["money-mouth","sealed","smile","surprised"],["tongue-out","undecided","wink","yell"]];a.addButton("emoticons",{type:"panelbutton",panel:{role:"application",autohide:!0,html:c,onclick:function(b){var c=a.dom.getParent(b.target,"a");c&&(a.insertContent(''+c.getAttribute('),this.hide())}},tooltip:"Emoticons"})}); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/wordcount/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("wordcount",function(a){function b(){a.theme.panel.find("#wordcount").text(["Words: {0}",e.getCount()])}var c,d,e=this;c=a.getParam("wordcount_countregex",/[\w\u2019\x27\-\u00C0-\u1FFF]+/g),d=a.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$?\x27\x22_+=\\\/\-]*/g),a.on("init",function(){var c=a.theme.panel&&a.theme.panel.find("#statusbar")[0];c&&tinymce.util.Delay.setEditorTimeout(a,function(){c.insert({type:"label",name:"wordcount",text:["Words: {0}",e.getCount()],classes:"wordcount",disabled:a.settings.readonly},0),a.on("setcontent beforeaddundo",b),a.on("keyup",function(a){32==a.keyCode&&b()})},0)}),e.getCount=function(){var b=a.getContent({format:"raw"}),e=0;if(b){b=b.replace(/\.\.\./g," "),b=b.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," "),b=b.replace(/(\w+)(&#?[a-z0-9]+;)+(\w+)/i,"$1$3").replace(/&.+?;/g," "),b=b.replace(d,"");var f=b.match(c);f&&(e=f.length)}return e}}); -------------------------------------------------------------------------------- /client/app/modals/foldermodal/foldermodal.js: -------------------------------------------------------------------------------- 1 | class FolderModalCtrl { 2 | constructor(Folders) { 3 | this.Folders = Folders; 4 | } 5 | 6 | renameFolder() { 7 | this.Folders.renameFolder(this.selectedfolder, this.name); 8 | this.hideModal(); 9 | } 10 | 11 | hideModal() { 12 | this.show = false; 13 | } 14 | } 15 | 16 | let createFolderModal = () => { 17 | return { 18 | restrict: 'E', 19 | scope: { 20 | show: '=', 21 | selectedfolder: '=', 22 | name: '=' 23 | }, 24 | link(scope, element, attrs) { 25 | scope.dialogStyle = {}; 26 | if(attrs.width) { 27 | scope.dialogStyle.width = attrs.width; 28 | } 29 | if(attrs.height) { 30 | scope.dialogStyle.height = attrs.height; 31 | } 32 | }, 33 | controllerAs: 'folderModalCtrl', 34 | controller: FolderModalCtrl, 35 | bindToController: true, 36 | template: require(`./foldermodal.html`) 37 | }; 38 | }; 39 | 40 | export default createFolderModal; -------------------------------------------------------------------------------- /user-server/config/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let userController = require('../controllers/userController'); 3 | 4 | module.exports = (app) => { 5 | 6 | // Post signup and email verification 7 | app.post('/user/signup', userController.postSignup); 8 | app.get('/user/email-verification/:URL', userController.getVerification); 9 | 10 | // Sign in and sign up locally and using github 11 | app.post('/user/signin', userController.signin); 12 | app.post('/user/auth/github', userController.githubLogin); 13 | 14 | // Get or update profile information 15 | app.put('/user/api/updatePassword', userController.updatePassword); 16 | app.route('/user/api/userInfo') 17 | .get(userController.userInfo) 18 | .put(userController.updateUserInfo); 19 | 20 | app.route('/user/api/sublime-secret') 21 | .get(userController.generateSublimeSecret); 22 | 23 | app.route('/user/sublime-secret') 24 | .get(userController.verifySublimeSecret) 25 | .post(userController.verifySublimeSecret); 26 | }; 27 | -------------------------------------------------------------------------------- /client/app/modals/movemodal/moveModal.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | X 7 |
8 |
9 | Select destination folder for {{moveSnippetModalCtrl.name}}: 10 |
11 |
12 |
13 |

14 | 15 | 16 |

17 | 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /test/TestingOutline.txt: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // Auth // 3 | ////////////////////////////////////////////////// 4 | 5 | Post to signin -- incorrect credentials 6 | Post to signup -- correct credentials 7 | copy email, password 8 | copy access token 9 | Post to signin -- correct pw and email 10 | Post to signin -- signup token 11 | copy access token 12 | 13 | 14 | ////////////////////////////////////////////////// 15 | // Snippets - basic // 16 | ////////////////////////////////////////////////// 17 | 18 | Post to api/snippets 19 | no token 20 | Get to api/snippets 21 | no token 22 | Put to api/snippets 23 | no token 24 | Delete to api/snippets 25 | no token 26 | Post to signin correct pw and email 27 | 28 | on body - 29 | filePath 30 | data 31 | name 32 | 33 | Post to api/snippets 34 | Get to api/snippets 35 | Put to api/snippets 36 | Delete to api/snippets 37 | 38 | get to api/user/snippets 39 | 40 | post to api/folders 41 | delete to api/folders -------------------------------------------------------------------------------- /client/js/tinymce/plugins/noneditable/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("noneditable",function(a){function b(a){return function(b){return-1!==(" "+b.attr("class")+" ").indexOf(a)}}function c(b){function c(b){var c=arguments,d=c[c.length-2];return d>0&&'"'==g.charAt(d-1)?b:''+a.dom.encode("string"==typeof c[1]?c[1]:c[0])+""}var d=f.length,g=b.content,h=tinymce.trim(e);if("raw"!=b.format){for(;d--;)g=g.replace(f[d],c);b.content=g}}var d,e,f,g="contenteditable";d=" "+tinymce.trim(a.getParam("noneditable_editable_class","mceEditable"))+" ",e=" "+tinymce.trim(a.getParam("noneditable_noneditable_class","mceNonEditable"))+" ";var h=b(d),i=b(e);f=a.getParam("noneditable_regexp"),f&&!f.length&&(f=[f]),a.on("PreInit",function(){f&&a.on("BeforeSetContent",c),a.parser.addAttributeFilter("class",function(a){for(var b,c=a.length;c--;)b=a[c],h(b)?b.attr(g,"true"):i(b)&&b.attr(g,"false")}),a.serializer.addAttributeFilter(g,function(a){for(var b,c=a.length;c--;)b=a[c],(h(b)||i(b))&&(f&&b.attr("data-mce-content")?(b.name="#text",b.type=3,b.raw=!0,b.value=b.attr("data-mce-content")):b.attr(g,null))})})}); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/save/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("save",function(a){function b(){var b;return b=tinymce.DOM.getParent(a.id,"form"),!a.getParam("save_enablewhendirty",!0)||a.isDirty()?(tinymce.triggerSave(),a.getParam("save_onsavecallback")?(a.execCallback("save_onsavecallback",a),void a.nodeChanged()):void(b?(a.setDirty(!1),b.onsubmit&&!b.onsubmit()||("function"==typeof b.submit?b.submit():c(a.translate("Error: Form submit field collision."))),a.nodeChanged()):c(a.translate("Error: No form element found.")))):void 0}function c(b){a.notificationManager.open({text:b,type:"error"})}function d(){var b=tinymce.trim(a.startContent);return a.getParam("save_oncancelcallback")?void a.execCallback("save_oncancelcallback",a):(a.setContent(b),a.undoManager.clear(),void a.nodeChanged())}function e(){var b=this;a.on("nodeChange dirty",function(){b.disabled(a.getParam("save_enablewhendirty",!0)&&!a.isDirty())})}a.addCommand("mceSave",b),a.addCommand("mceCancel",d),a.addButton("save",{icon:"save",text:"Save",cmd:"mceSave",disabled:!0,onPostRender:e}),a.addButton("cancel",{text:"Cancel",icon:!1,cmd:"mceCancel",disabled:!0,onPostRender:e}),a.addShortcut("Meta+S","","mceSave")}); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/visualblocks/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("visualblocks",function(a,b){function c(){var b=this;b.active(f),a.on("VisualBlocks",function(){b.active(a.dom.hasClass(a.getBody(),"mce-visualblocks"))})}var d,e,f;window.NodeList&&(a.addCommand("mceVisualBlocks",function(){var c,g=a.dom;d||(d=g.uniqueId(),c=g.create("link",{id:d,rel:"stylesheet",href:b+"/css/visualblocks.css"}),a.getDoc().getElementsByTagName("head")[0].appendChild(c)),a.on("PreviewFormats AfterPreviewFormats",function(b){f&&g.toggleClass(a.getBody(),"mce-visualblocks","afterpreviewformats"==b.type)}),g.toggleClass(a.getBody(),"mce-visualblocks"),f=a.dom.hasClass(a.getBody(),"mce-visualblocks"),e&&e.active(g.hasClass(a.getBody(),"mce-visualblocks")),a.fire("VisualBlocks")}),a.addButton("visualblocks",{title:"Show blocks",cmd:"mceVisualBlocks",onPostRender:c}),a.addMenuItem("visualblocks",{text:"Show blocks",cmd:"mceVisualBlocks",onPostRender:c,selectable:!0,context:"view",prependToContext:!0}),a.on("init",function(){a.settings.visualblocks_default_state&&a.execCommand("mceVisualBlocks",!1,null,{skip_focus:!0})}),a.on("remove",function(){a.dom.removeClass(a.getBody(),"mce-visualblocks")}))}); -------------------------------------------------------------------------------- /client/app/controllers/main/editor/snippets/favorites.html: -------------------------------------------------------------------------------- 1 |
28 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | never:code 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /nginx-server/nevercode.com: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server ipv6only=on; 4 | 5 | 6 | server_name nevercode.com; 7 | 8 | #access_log /var/log/nginx/log/host.access.log main; 9 | 10 | location / { 11 | root /Users/BigHeart/Desktop/nevercode/client; 12 | } 13 | 14 | location /files { 15 | proxy_pass http://127.0.0.1:3002; 16 | proxy_http_version 1.1; 17 | proxy_set_header Upgrade $http_upgrade; 18 | proxy_set_header Connection 'upgrade'; 19 | proxy_set_header Host $host; 20 | proxy_cache_bypass $http_upgrade; 21 | } 22 | 23 | location /user { 24 | proxy_pass http://127.0.0.1:3003; 25 | proxy_http_version 1.1; 26 | proxy_set_header Upgrade $http_upgrade; 27 | proxy_set_header Connection 'upgrade'; 28 | proxy_set_header Host $host; 29 | proxy_cache_bypass $http_upgrade; 30 | } 31 | 32 | #error_page 404 /404.html; 33 | 34 | # redirect server error pages to the static page /50x.html 35 | error_page 500 502 503 504 /50x.html; 36 | location = /50x.html { 37 | root /usr/share/nginx/html; 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /files-server/config/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let snippetsController = require('../controllers/snippetsController'); 3 | 4 | module.exports = (app) => { 5 | // Access, add, remove or update user snippets 6 | app.route('/files/api/snippets') 7 | .get(snippetsController.getSnippet) 8 | .post(snippetsController.addSnippet) 9 | .delete(snippetsController.removeSnippet) 10 | .put(snippetsController.updateSnippet); 11 | 12 | // Get all public snippets available 13 | app.get('/files/public/snippets', snippetsController.getPublicSnippets); 14 | 15 | // Get all user snippets available 16 | app.route('/files/api/user/snippets') 17 | .get(snippetsController.getUserSnippets) 18 | .put(snippetsController.renameUserSnippets); 19 | 20 | // Add or remove user folder 21 | app.route('/files/api/folders') 22 | .post(snippetsController.addFolder) 23 | .delete(snippetsController.removeFolder); 24 | 25 | app.route('/files/n') 26 | .get(snippetsController.rerouteSharedSnippet); 27 | 28 | app.route('/files/share') 29 | .get(snippetsController.getSharedSnippet); 30 | 31 | app.route('/files/api/sublime-snippet') 32 | .post(snippetsController.addSublimeSnippet); 33 | }; 34 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/colorpicker/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("colorpicker",function(a){function b(b,c){function d(a){var b=new tinymce.util.Color(a),c=b.toRgb();f.fromJSON({r:c.r,g:c.g,b:c.b,hex:b.toHex().substr(1)}),e(b.toHex())}function e(a){f.find("#preview")[0].getEl().style.background=a}var f=a.windowManager.open({title:"Color",items:{type:"container",layout:"flex",direction:"row",align:"stretch",padding:5,spacing:10,items:[{type:"colorpicker",value:c,onchange:function(){var a=this.rgb();f&&(f.find("#r").value(a.r),f.find("#g").value(a.g),f.find("#b").value(a.b),f.find("#hex").value(this.value().substr(1)),e(this.value()))}},{type:"form",padding:0,labelGap:5,defaults:{type:"textbox",size:7,value:"0",flex:1,spellcheck:!1,onchange:function(){var a,b,c=f.find("colorpicker")[0];return a=this.name(),b=this.value(),"hex"==a?(b="#"+b,d(b),void c.value(b)):(b={r:f.find("#r").value(),g:f.find("#g").value(),b:f.find("#b").value()},c.value(b),void d(b))}},items:[{name:"r",label:"R",autofocus:1},{name:"g",label:"G"},{name:"b",label:"B"},{name:"hex",label:"#",value:"000000"},{name:"preview",type:"container",border:1}]}]},onSubmit:function(){b("#"+this.toJSON().hex)}});d(c)}a.settings.color_picker_callback||(a.settings.color_picker_callback=b)}); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/pagebreak/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("pagebreak",function(a){var b="mce-pagebreak",c=a.getParam("pagebreak_separator",""),d=new RegExp(c.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(a){return"\\"+a}),"gi"),e='';a.addCommand("mcePageBreak",function(){a.settings.pagebreak_split_block?a.insertContent("

"+e+"

"):a.insertContent(e)}),a.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),a.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"}),a.on("ResolveName",function(c){"IMG"==c.target.nodeName&&a.dom.hasClass(c.target,b)&&(c.name="pagebreak")}),a.on("click",function(c){c=c.target,"IMG"===c.nodeName&&a.dom.hasClass(c,b)&&a.selection.select(c)}),a.on("BeforeSetContent",function(a){a.content=a.content.replace(d,e)}),a.on("PreInit",function(){a.serializer.addNodeFilter("img",function(b){for(var d,e,f=b.length;f--;)if(d=b[f],e=d.attr("class"),e&&-1!==e.indexOf("mce-pagebreak")){var g=d.parent;if(a.schema.getBlockElements()[g.name]&&a.settings.pagebreak_split_block){g.type=3,g.value=c,g.raw=!0,d.remove();continue}d.type=3,d.value=c,d.raw=!0}})})}); -------------------------------------------------------------------------------- /client/app/controllers/main/download/download.js: -------------------------------------------------------------------------------- 1 | import * as Actions from '../../../redux/actions.js'; 2 | 3 | class DownloadCtrl { 4 | constructor($ngRedux, $http) { 5 | this.$http = $http; 6 | this.activeUser = {}; 7 | $ngRedux.connect(this.mapStateToThis, this.mapDispatchToThis)(this); 8 | } 9 | 10 | confirmCopyAction() { 11 | Materialize.toast('Client secret added to your clipboard!', 3000, 'rounded'); 12 | } 13 | 14 | mapDispatchToThis(dispatch) { 15 | return { 16 | generateNewSecret() { 17 | this.$http.get('/user/api/sublime-secret') 18 | .then(res => { 19 | let sublimeSecret = res.data; 20 | let newUser = Object.assign({}, this.activeUser, {sublimeSecret}); 21 | dispatch(Actions.setActiveUser(newUser)); 22 | }) 23 | .catch(console.log); 24 | } 25 | }; 26 | } 27 | mapStateToThis(state) { 28 | return { 29 | activeUser: state.activeUser ? state.activeUser: {} 30 | }; 31 | } 32 | } 33 | 34 | const downloadPage = () => { 35 | return { 36 | url: '/download', 37 | controllerAs: 'downloadCtrl', 38 | controller: DownloadCtrl, 39 | template: require('./download.html'), 40 | scope: {}, 41 | access: {restricted: true} 42 | }; 43 | }; 44 | 45 | export default downloadPage; 46 | 47 | -------------------------------------------------------------------------------- /client/app/modals/movemodal/moveModal.js: -------------------------------------------------------------------------------- 1 | class MoveSnippetModalCtrl { 2 | constructor(Snippets) { 3 | this.Snippets = Snippets; 4 | } 5 | 6 | moveSnippet(newPath){ 7 | let oldPath = this.selectedsnippet.value.filePath; 8 | let snippetToMove = Object.assign({}, 9 | this.selectedsnippet.value, { 10 | filePath: newPath + '/' + this.selectedsnippet.value.name 11 | }); 12 | this.Snippets.updateSnippet(snippetToMove, oldPath); 13 | this.hideModal(); 14 | } 15 | 16 | hideModal() { 17 | this.show = false; 18 | } 19 | 20 | } 21 | 22 | let createMoveModal = () => { 23 | return { 24 | restrict: 'E', 25 | scope: { 26 | show: '=', 27 | selectedsnippet: '=', 28 | name: '=', 29 | paths: '=' 30 | }, 31 | link(scope, element, attrs) { 32 | scope.dialogStyle = {}; 33 | if(attrs.width) { 34 | scope.dialogStyle.width = attrs.width; 35 | } 36 | if(attrs.height) { 37 | scope.dialogStyle.height = attrs.height; 38 | } 39 | }, 40 | controllerAs: 'moveSnippetModalCtrl', 41 | controller: MoveSnippetModalCtrl, 42 | bindToController: true, 43 | template: require(`./moveModal.html`) 44 | }; 45 | }; 46 | 47 | export default createMoveModal; -------------------------------------------------------------------------------- /client/js/tinymce/plugins/visualchars/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("visualchars",function(a){function b(b){function c(a){return''+a+""}function f(){var a,b="";for(a in n)b+=a;return new RegExp("["+b+"]","g")}function g(){var a,b="";for(a in n)b&&(b+=","),b+="span.mce-"+n[a];return b}var h,i,j,k,l,m,n,o,p=a.getBody(),q=a.selection;if(n={"\xa0":"nbsp","\xad":"shy"},d=!d,e.state=d,a.fire("VisualChars",{state:d}),o=f(),b&&(m=q.getBookmark()),d)for(i=[],tinymce.walk(p,function(a){3==a.nodeType&&a.nodeValue&&o.test(a.nodeValue)&&i.push(a)},"childNodes"),j=0;j=0;j--)a.dom.remove(i[j],1);q.moveToBookmark(m)}function c(){var b=this;a.on("VisualChars",function(a){b.active(a.state)})}var d,e=this;a.addCommand("mceVisualChars",b),a.addButton("visualchars",{title:"Show invisible characters",cmd:"mceVisualChars",onPostRender:c}),a.addMenuItem("visualchars",{text:"Show invisible characters",cmd:"mceVisualChars",onPostRender:c,selectable:!0,context:"view",prependToContext:!0}),a.on("beforegetcontent",function(a){d&&"raw"!=a.format&&!a.draft&&(d=!0,b(!1))})}); -------------------------------------------------------------------------------- /client/assets/codemirror-themes/eclipse.css: -------------------------------------------------------------------------------- 1 | .cm-s-eclipse span.cm-meta { color: #FF1717; } 2 | .cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } 3 | .cm-s-eclipse span.cm-atom { color: #219; } 4 | .cm-s-eclipse span.cm-number { color: #164; } 5 | .cm-s-eclipse span.cm-def { color: #00f; } 6 | .cm-s-eclipse span.cm-variable { color: black; } 7 | .cm-s-eclipse span.cm-variable-2 { color: #0000C0; } 8 | .cm-s-eclipse span.cm-variable-3 { color: #0000C0; } 9 | .cm-s-eclipse span.cm-property { color: black; } 10 | .cm-s-eclipse span.cm-operator { color: black; } 11 | .cm-s-eclipse span.cm-comment { color: #3F7F5F; } 12 | .cm-s-eclipse span.cm-string { color: #2A00FF; } 13 | .cm-s-eclipse span.cm-string-2 { color: #f50; } 14 | .cm-s-eclipse span.cm-qualifier { color: #555; } 15 | .cm-s-eclipse span.cm-builtin { color: #30a; } 16 | .cm-s-eclipse span.cm-bracket { color: #cc7; } 17 | .cm-s-eclipse span.cm-tag { color: #170; } 18 | .cm-s-eclipse span.cm-attribute { color: #00c; } 19 | .cm-s-eclipse span.cm-link { color: #219; } 20 | .cm-s-eclipse span.cm-error { color: #f00; } 21 | 22 | .cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; } 23 | .cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } 24 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/tabfocus/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("tabfocus",function(a){function b(a){9!==a.keyCode||a.ctrlKey||a.altKey||a.metaKey||a.preventDefault()}function c(b){function c(c){function f(a){return"BODY"===a.nodeName||"hidden"!=a.type&&"none"!=a.style.display&&"hidden"!=a.style.visibility&&f(a.parentNode)}function i(a){return/INPUT|TEXTAREA|BUTTON/.test(a.tagName)&&tinymce.get(b.id)&&-1!=a.tabIndex&&f(a)}if(h=d.select(":input:enabled,*[tabindex]:not(iframe)"),e(h,function(b,c){return b.id==a.id?(g=c,!1):void 0}),c>0){for(j=g+1;j=0;j--)if(i(h[j]))return h[j];return null}var g,h,i,j;if(!(9!==b.keyCode||b.ctrlKey||b.altKey||b.metaKey||b.isDefaultPrevented())&&(i=f(a.getParam("tab_focus",a.getParam("tabfocus_elements",":prev,:next"))),1==i.length&&(i[1]=i[0],i[0]=":prev"),h=b.shiftKey?":prev"==i[0]?c(-1):d.get(i[0]):":next"==i[1]?c(1):d.get(i[1]))){var k=tinymce.get(h.id||h.name);h.id&&k?k.focus():tinymce.util.Delay.setTimeout(function(){tinymce.Env.webkit||window.focus(),h.focus()},10),b.preventDefault()}}var d=tinymce.DOM,e=tinymce.each,f=tinymce.explode;a.on("init",function(){a.inline&&tinymce.DOM.setAttrib(a.getBody(),"tabIndex",null),a.on("keyup",b),tinymce.Env.gecko?a.on("keypress keydown",c):a.on("keydown",c)})}); -------------------------------------------------------------------------------- /misc/addRemotes: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #Point to the upstream 3 | git remote add upstream https://github.com/precocious-tangerine/evercode 4 | #Add everyone's remotes 5 | git remote add edison https://github.com/bamboostgg/evercode 6 | git remote add orlando https://github.com/orlandoc01/evercode 7 | git remote add gerrit https://github.com/yntema/evercode 8 | git remote add max https://github.com/maxkroshka/evercode 9 | #Add shortcuts to everyone's remotes 10 | git remote add u https://github.com/precocious-tangerine/evercode 11 | git remote add e https://github.com/bamboostgg/evercode 12 | git remote add o https://github.com/orlandoc01/evercode 13 | git remote add g https://github.com/yntema/evercode 14 | git remote add m https://github.com/maxkroshka/evercode 15 | 16 | #Overwrite if existing 17 | git remote set-url upstream https://github.com/precocious-tangerine/evercode 18 | git remote set-url edison https://github.com/bamboostgg/evercode 19 | git remote set-url orlando https://github.com/orlandoc01/evercode 20 | git remote set-url gerrit https://github.com/yntema/evercode 21 | git remote set-url max https://github.com/maxkroshka/evercode 22 | git remote set-url u https://github.com/precocious-tangerine/evercode 23 | git remote set-url e https://github.com/bamboostgg/evercode 24 | git remote set-url o https://github.com/orlandoc01/evercode 25 | git remote set-url g https://github.com/yntema/evercode 26 | git remote set-url m https://github.com/maxkroshka/evercode -------------------------------------------------------------------------------- /user-server/config/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let Promise = require('bluebird'); 3 | let request = require('request'); 4 | let setup = require('../../setup.js'); 5 | let jwt = require('jsonwebtoken'); 6 | let secret = setup.secretToken; 7 | 8 | let createJWT = (user) => { 9 | let payload = { 10 | username: user.username, 11 | email: user.email 12 | }; 13 | return jwt.sign(payload, secret); 14 | }; 15 | module.exports.createJWT = createJWT; 16 | 17 | module.exports.decode = (req, res, next) => { 18 | let token = req.headers.authorization; 19 | if (!token) { 20 | return res.status(403).send('Please login'); 21 | } 22 | try { 23 | req.user = jwt.decode(token, secret); 24 | next(); 25 | } catch (error) { 26 | return next(error); 27 | } 28 | }; 29 | 30 | //Declare here first for use locally 31 | module.exports.createRootFolderAsync = (userObj) => { 32 | let token = createJWT(userObj); 33 | return new Promise((resolve, reject) => { 34 | let fullUrl = setup.server + '/files/api/folders'; 35 | request({ 36 | url: fullUrl, 37 | method: 'POST', 38 | headers: { 39 | 'authorization': token 40 | }, 41 | json: { 42 | path: userObj.email 43 | } 44 | }, function(error, resp) { 45 | if (error) { 46 | console.log(error); 47 | reject(error); 48 | } else { 49 | resolve(resp); 50 | } 51 | }); 52 | }); 53 | }; 54 | 55 | 56 | -------------------------------------------------------------------------------- /client/app/controllers/main/editor/search/search.js: -------------------------------------------------------------------------------- 1 | class SearchCtrl { 2 | constructor($ngRedux, Snippets, focus) { 3 | $ngRedux.connect(this.mapStateToThis)(this); 4 | this.Snippets = Snippets; 5 | focus('search-input'); 6 | } 7 | 8 | changeSelectedSnippet(snippetPath) { 9 | this.Snippets.changeSelectedSnippet(snippetPath); 10 | } 11 | 12 | hasTag(snippetTag, searchTag) { 13 | return !!snippetTag.includes(searchTag); 14 | } 15 | 16 | mapStateToThis(state) { 17 | let { snippetMap } = state; 18 | let snippetArr = []; 19 | let tags = {}; 20 | Object.keys(snippetMap).forEach(key => { 21 | let snippetVal = snippetMap[key].value; 22 | if (typeof snippetVal === 'object') { 23 | if (snippetVal.name !== '.config' && snippetVal.name !== '/.config') { 24 | snippetArr.push(snippetVal); 25 | snippetVal.tags.forEach(tag => { 26 | tags[tag] = tags[tag] || []; 27 | tags[tag].push(snippetVal); 28 | }); 29 | } 30 | } 31 | }); 32 | return { 33 | snippetMap, 34 | snippetArr, 35 | tags 36 | }; 37 | } 38 | 39 | } 40 | 41 | const search = () => { 42 | return { 43 | url: '/search', 44 | restrict: 'E', 45 | controllerAs: 'search', 46 | controller: SearchCtrl, 47 | template: require('./search.html'), 48 | scope: {}, 49 | access: { restricted: true } 50 | }; 51 | }; 52 | 53 | export default search; 54 | 55 | -------------------------------------------------------------------------------- /client/app/modals/authmodals/authmodal.js: -------------------------------------------------------------------------------- 1 | class AuthCtrl { 2 | constructor(Auth) { 3 | this.user = {}; 4 | this.failed = false; 5 | this.Auth = Auth; 6 | } 7 | githubAuth() { 8 | this.failed = false; 9 | this.Auth.githubSignin(); 10 | this.hideModal(); 11 | } 12 | hideModal() { 13 | this.show = false; 14 | } 15 | switch() { 16 | this.show = false; 17 | this.other = true; 18 | } 19 | signin(boolean) { 20 | this.failed = false; 21 | if (boolean) { 22 | this.Auth.signin(this.user); 23 | this.hideModal(); 24 | } 25 | } 26 | signup(boolean) { 27 | this.failed = false; 28 | if (boolean && this.user.passwordConfirm === this.user.password) { 29 | this.Auth.signup(this.user); 30 | this.hideModal(); 31 | } else { 32 | this.failed = true; 33 | } 34 | } 35 | } 36 | 37 | let createAuthModal = (url) => { 38 | return () => { 39 | return { 40 | restrict: 'E', 41 | scope: { 42 | show: '=', 43 | other: '=' 44 | }, 45 | replace: true, 46 | link(scope, element, attrs) { 47 | scope.dialogStyle = {}; 48 | if(attrs.width) { 49 | scope.dialogStyle.width = attrs.width; 50 | } 51 | if(attrs.height) { 52 | scope.dialogStyle.height = attrs.height; 53 | } 54 | }, 55 | controllerAs: 'authCtrl', 56 | controller: AuthCtrl, 57 | bindToController: true, 58 | template: require(`.${url}.html`), 59 | url: url 60 | }; 61 | }; 62 | }; 63 | 64 | export default createAuthModal; 65 | 66 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/preview/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("preview",function(a){var b=a.settings,c=!tinymce.Env.ie;a.addCommand("mcePreview",function(){a.windowManager.open({title:"Preview",width:parseInt(a.getParam("plugin_preview_width","650"),10),height:parseInt(a.getParam("plugin_preview_height","500"),10),html:'",buttons:{text:"Close",onclick:function(){this.parent().parent().close()}},onPostRender:function(){var d,e="";e+='',tinymce.each(a.contentCSS,function(b){e+=''});var f=b.body_id||"tinymce";-1!=f.indexOf("=")&&(f=a.getParam("body_id","","hash"),f=f[a.id]||f);var g=b.body_class||"";-1!=g.indexOf("=")&&(g=a.getParam("body_class","","hash"),g=g[a.id]||"");var h=' ',i=a.settings.directionality?' dir="'+a.settings.directionality+'"':"";if(d=""+e+'"+a.getContent()+h+"",c)this.getEl("body").firstChild.src="data:text/html;charset=utf-8,"+encodeURIComponent(d);else{var j=this.getEl("body").firstChild.contentWindow.document;j.open(),j.write(d),j.close()}}})}),a.addButton("preview",{title:"Preview",cmd:"mcePreview"}),a.addMenuItem("preview",{text:"Preview",cmd:"mcePreview",context:"view"})}); -------------------------------------------------------------------------------- /client/app/services/Public.js: -------------------------------------------------------------------------------- 1 | import * as Actions from '../redux/actions.js'; 2 | 3 | export default class Public { 4 | constructor($http, $ngRedux) { 5 | $ngRedux.connect(this.mapStateToThis, this.mapDispatchToThis)(this); 6 | this.$http = $http; 7 | } 8 | mapDispatchToThis(dispatch) { 9 | return { 10 | getPublicSnippets() { 11 | return this.$http({ 12 | method: 'GET', 13 | url: 'files/public/snippets' 14 | }).then(res => { 15 | dispatch(Actions.setPublicList(res.data)); 16 | }) 17 | .catch(error => { 18 | console.error(error); 19 | }); 20 | }, 21 | 22 | getSharedSnippet(id) { 23 | this.$http({ 24 | method: 'GET', 25 | url: '/files/share?s=' + id, 26 | }) 27 | .then(response => { 28 | this.setPublicList(response.data); 29 | this.setSelectedPublicSnippet('share'); 30 | }); 31 | }, 32 | 33 | setPublicList(data) { 34 | dispatch(Actions.setPublicList(data)); 35 | }, 36 | 37 | setSelectedPublicSnippet(filePath) { 38 | dispatch(Actions.removeSelectedSnippet()); 39 | dispatch(Actions.setSelectedPublicSnippet(filePath)); 40 | }, 41 | 42 | removeSelectedPublicSnippet() { 43 | dispatch(Actions.removeSelectedPublicSnippet()); 44 | } 45 | }; 46 | } 47 | mapStateToThis(state) { 48 | return { 49 | publicList: state.publicList, 50 | selectedPublicSnippet: state.selectedPublicSnippet 51 | }; 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | concat: { 5 | options: { 6 | separator: ';' 7 | }, 8 | dist: { 9 | dest: 'client-server/client/dist/bundle-all.min.js', 10 | src: [ 11 | 'client-server/client/js/jquery-2.1.1.min.js', 12 | 'client-server/client/dist/bundle.min.js', 13 | 'client-server/client/js/materialize.min.js', 14 | 'client-server/client/js/code-mirror-scripts/all-cm-scripts.min.js' 15 | ] 16 | } 17 | }, 18 | ngAnnotate: { 19 | options: { 20 | singleQuotes: true 21 | }, 22 | app: { 23 | files: { 24 | 'client-server/client/dist/bundle.min-safe.js': 'client-server/client/dist/bundle.js' 25 | } 26 | } 27 | }, 28 | uglify: { 29 | options: { 30 | mangle: false 31 | }, 32 | my_target: { 33 | files: { 34 | 'client-server/client/dist/bundle.min.js': 'client-server/client/dist/bundle.min-safe.js' 35 | } 36 | } 37 | }, 38 | cssmin: { 39 | options: { 40 | shorthandCompacting: false, 41 | roundingPrecision: -1 42 | }, 43 | target: { 44 | files: { 45 | 'client-server/client/dist/style.min.css': ['client-server/client/styles/style.css', 'client-server/client/styles/materialize.css'] 46 | } 47 | } 48 | } 49 | }); 50 | 51 | require('load-grunt-tasks')(grunt); 52 | 53 | grunt.registerTask('default', ['ngAnnotate', 'uglify', 'cssmin', 'concat']); 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /client/app/controllers/main/public/public.js: -------------------------------------------------------------------------------- 1 | class PublicCtrl { 2 | constructor($ngRedux, $state, $location, Public) { 3 | $ngRedux.connect(this.mapStateToThis)(this); 4 | this.$state = $state; 5 | this.$location = $location; 6 | this.Public = Public; 7 | this.snippetList = []; 8 | this.loading = true; 9 | this.editorModalShow = false; 10 | 11 | this.Public.getPublicSnippets() 12 | .then(() => { 13 | this.loading = false; 14 | }); 15 | 16 | this.checkIfUserHasVerified(); 17 | } 18 | checkIfUserHasVerified() { 19 | if (this.$location.absUrl().indexOf('?') != -1) { 20 | let auth = this.$location.absUrl().slice(-13); 21 | if(auth === 'verified=true') { 22 | Materialize.toast('Your account has been verified! Please sign in', 3000, 'rounded'); 23 | } 24 | } 25 | } 26 | toggleEditorModal(filepath) { 27 | this.Public.setSelectedPublicSnippet(filepath); 28 | this.editorModalShow = !this.editorModalShow; 29 | } 30 | mapStateToThis(state) { 31 | let { publicList, selectedPublicSnippet} = state; 32 | let snippetArr = Object.keys(publicList).map(key => { 33 | return publicList[key]; 34 | }); 35 | return { 36 | publicList, 37 | snippetArr, 38 | selectedPublicSnippet, 39 | }; 40 | } 41 | } 42 | const publicPage = () => { 43 | return { 44 | url: '/public', 45 | restrict: 'E', 46 | controllerAs: 'public', 47 | controller: PublicCtrl, 48 | template: require('./public.html'), 49 | scope: {}, 50 | access: { restricted: false } 51 | }; 52 | }; 53 | 54 | export default publicPage; 55 | 56 | -------------------------------------------------------------------------------- /client/assets/codemirror-themes/cobalt.css: -------------------------------------------------------------------------------- 1 | .cm-s-cobalt.CodeMirror { background: #002240; color: white; } 2 | .cm-s-cobalt div.CodeMirror-selected { background: #b36539; } 3 | .cm-s-cobalt .CodeMirror-line::selection, .cm-s-cobalt .CodeMirror-line > span::selection, .cm-s-cobalt .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); } 4 | .cm-s-cobalt .CodeMirror-line::-moz-selection, .cm-s-cobalt .CodeMirror-line > span::-moz-selection, .cm-s-cobalt .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); } 5 | .cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } 6 | .cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; } 7 | .cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; } 8 | .cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; } 9 | .cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white; } 10 | 11 | .cm-s-cobalt span.cm-comment { color: #08f; } 12 | .cm-s-cobalt span.cm-atom { color: #845dc4; } 13 | .cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; } 14 | .cm-s-cobalt span.cm-keyword { color: #ffee80; } 15 | .cm-s-cobalt span.cm-string { color: #3ad900; } 16 | .cm-s-cobalt span.cm-meta { color: #ff9d00; } 17 | .cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; } 18 | .cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; } 19 | .cm-s-cobalt span.cm-bracket { color: #d8d8d8; } 20 | .cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; } 21 | .cm-s-cobalt span.cm-link { color: #845dc4; } 22 | .cm-s-cobalt span.cm-error { color: #9d1e15; } 23 | 24 | .cm-s-cobalt .CodeMirror-activeline-background { background: #002D57; } 25 | .cm-s-cobalt .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; } 26 | -------------------------------------------------------------------------------- /client/app/controllers/main/editor/profile/profile.js: -------------------------------------------------------------------------------- 1 | class ProfileCtrl { 2 | constructor($ngRedux, $state, Auth, Snippets) { 3 | $ngRedux.connect(this.mapStateToThis)(this); 4 | this.$state = $state; 5 | this.Auth = Auth; 6 | this.Snippets = Snippets; 7 | this.cmThemes = ['eclipse', 'twilight', '3024-day', 'ambiance', 'cobalt', 'material', 'mdn-like', 'paraiso-light', 'rubyblue', 'yeti', 'zenburn']; 8 | this.cmLanguages = ['javascript', 'python', 'clike', 'ruby', 'php', 'sql', 'css', 'htmlmixed']; 9 | } 10 | 11 | changeUsername(email, username) { 12 | this.Snippets.updateUsername({ email, username }); 13 | } 14 | 15 | changeTheme(theme) { 16 | this.Auth.updateUser({ theme }); 17 | } 18 | 19 | changeLanguage(language) { 20 | this.Auth.updateUser({ language }); 21 | } 22 | 23 | changePassword() { 24 | if(this.user.newPass === this.user.confirmPass){ 25 | this.Auth.updatePassword({ email: this.activeUser.email, password: this.user.currentPass, newPassword: this.user.newPass }); 26 | } else { 27 | Materialize.toast('New passwords don\'t match!', 3000, 'rounded'); 28 | } 29 | } 30 | 31 | mapStateToThis(state) { 32 | let { activeUser } = state; 33 | let username = activeUser.username; 34 | let userTheme = activeUser.theme ? activeUser.theme : 'eclipse'; 35 | let userLanguage = activeUser.language ? activeUser.language : 'javascript'; 36 | return { 37 | activeUser, 38 | userTheme, 39 | userLanguage, 40 | username 41 | }; 42 | } 43 | } 44 | 45 | const profile = () => { 46 | return { 47 | url: '/profile', 48 | restrict: 'E', 49 | controllerAs: 'profile', 50 | controller: ProfileCtrl, 51 | template: require('./profile.html'), 52 | scope: {}, 53 | access: { restricted: true } 54 | }; 55 | }; 56 | 57 | export default profile; 58 | 59 | -------------------------------------------------------------------------------- /client/assets/codemirror-themes/rubyblue.css: -------------------------------------------------------------------------------- 1 | .cm-s-rubyblue.CodeMirror { background: #112435; color: white; } 2 | .cm-s-rubyblue div.CodeMirror-selected { background: #38566F; } 3 | .cm-s-rubyblue .CodeMirror-line::selection, .cm-s-rubyblue .CodeMirror-line > span::selection, .cm-s-rubyblue .CodeMirror-line > span > span::selection { background: rgba(56, 86, 111, 0.99); } 4 | .cm-s-rubyblue .CodeMirror-line::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 86, 111, 0.99); } 5 | .cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; } 6 | .cm-s-rubyblue .CodeMirror-guttermarker { color: white; } 7 | .cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; } 8 | .cm-s-rubyblue .CodeMirror-linenumber { color: white; } 9 | .cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white; } 10 | 11 | .cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; } 12 | .cm-s-rubyblue span.cm-atom { color: #F4C20B; } 13 | .cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; } 14 | .cm-s-rubyblue span.cm-keyword { color: #F0F; } 15 | .cm-s-rubyblue span.cm-string { color: #F08047; } 16 | .cm-s-rubyblue span.cm-meta { color: #F0F; } 17 | .cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; } 18 | .cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; } 19 | .cm-s-rubyblue span.cm-bracket { color: #F0F; } 20 | .cm-s-rubyblue span.cm-link { color: #F4C20B; } 21 | .cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; } 22 | .cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; } 23 | .cm-s-rubyblue span.cm-error { color: #AF2018; } 24 | 25 | .cm-s-rubyblue .CodeMirror-activeline-background { background: #173047; } 26 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/autoresize/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("autoresize",function(a){function b(){return a.plugins.fullscreen&&a.plugins.fullscreen.isFullscreen()}function c(d){var g,h,i,j,k,l,m,n,o,p,q,r,s=tinymce.DOM;if(h=a.getDoc()){if(i=h.body,j=h.documentElement,k=e.autoresize_min_height,!i||d&&"setcontent"===d.type&&d.initial||b())return void(i&&j&&(i.style.overflowY="auto",j.style.overflowY="auto"));m=a.dom.getStyle(i,"margin-top",!0),n=a.dom.getStyle(i,"margin-bottom",!0),o=a.dom.getStyle(i,"padding-top",!0),p=a.dom.getStyle(i,"padding-bottom",!0),q=a.dom.getStyle(i,"border-top-width",!0),r=a.dom.getStyle(i,"border-bottom-width",!0),l=i.offsetHeight+parseInt(m,10)+parseInt(n,10)+parseInt(o,10)+parseInt(p,10)+parseInt(q,10)+parseInt(r,10),(isNaN(l)||0>=l)&&(l=tinymce.Env.ie?i.scrollHeight:tinymce.Env.webkit&&0===i.clientHeight?0:i.offsetHeight),l>e.autoresize_min_height&&(k=l),e.autoresize_max_height&&l>e.autoresize_max_height?(k=e.autoresize_max_height,i.style.overflowY="auto",j.style.overflowY="auto"):(i.style.overflowY="hidden",j.style.overflowY="hidden",i.scrollTop=0),k!==f&&(g=k-f,s.setStyle(a.iframeElement,"height",k+"px"),f=k,tinymce.isWebKit&&0>g&&c(d))}}function d(b,e,f){tinymce.util.Delay.setEditorTimeout(a,function(){c({}),b--?d(b,e,f):f&&f()},e)}var e=a.settings,f=0;a.settings.inline||(e.autoresize_min_height=parseInt(a.getParam("autoresize_min_height",a.getElement().offsetHeight),10),e.autoresize_max_height=parseInt(a.getParam("autoresize_max_height",0),10),a.on("init",function(){var b,c;b=a.getParam("autoresize_overflow_padding",1),c=a.getParam("autoresize_bottom_margin",50),b!==!1&&a.dom.setStyles(a.getBody(),{paddingLeft:b,paddingRight:b}),c!==!1&&a.dom.setStyles(a.getBody(),{paddingBottom:c})}),a.on("nodechange setcontent keyup FullscreenStateChanged",c),a.getParam("autoresize_on_init",!0)&&a.on("init",function(){d(20,100,function(){d(5,1e3)})}),a.addCommand("mceAutoResize",c))}); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/autolink/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("autolink",function(a){function b(a){e(a,-1,"(",!0)}function c(a){e(a,0,"",!0)}function d(a){e(a,-1,"",!1)}function e(a,b,c){function d(a,b){if(0>b&&(b=0),3==a.nodeType){var c=a.data.length;b>c&&(b=c)}return b}function e(a,b){1!=a.nodeType||a.hasChildNodes()?h.setStart(a,d(a,b)):h.setStartBefore(a)}function f(a,b){1!=a.nodeType||a.hasChildNodes()?h.setEnd(a,d(a,b)):h.setEndAfter(a)}var h,i,j,k,l,m,n,o,p,q;if("A"!=a.selection.getNode().tagName){if(h=a.selection.getRng(!0).cloneRange(),h.startOffset<5){if(o=h.endContainer.previousSibling,!o){if(!h.endContainer.firstChild||!h.endContainer.firstChild.nextSibling)return;o=h.endContainer.firstChild.nextSibling}if(p=o.length,e(o,p),f(o,p),h.endOffset<5)return;i=h.endOffset,k=o}else{if(k=h.endContainer,3!=k.nodeType&&k.firstChild){for(;3!=k.nodeType&&k.firstChild;)k=k.firstChild;3==k.nodeType&&(e(k,0),f(k,k.nodeValue.length))}i=1==h.endOffset?2:h.endOffset-1-b}j=i;do e(k,i>=2?i-2:0),f(k,i>=1?i-1:0),i-=1,q=h.toString();while(" "!=q&&""!==q&&160!=q.charCodeAt(0)&&i-2>=0&&q!=c);h.toString()==c||160==h.toString().charCodeAt(0)?(e(k,i),f(k,j),i+=1):0===h.startOffset?(e(k,0),f(k,j)):(e(k,i),f(k,j)),m=h.toString(),"."==m.charAt(m.length-1)&&f(k,j-1),m=h.toString(),n=m.match(g),n&&("www."==n[1]?n[1]="http://www.":/@$/.test(n[1])&&!/^mailto:/.test(n[1])&&(n[1]="mailto:"+n[1]),l=a.selection.getBookmark(),a.selection.setRng(h),a.execCommand("createlink",!1,n[1]+n[2]),a.selection.moveToBookmark(l),a.nodeChanged())}}var f,g=/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i;return a.settings.autolink_pattern&&(g=a.settings.autolink_pattern),a.on("keydown",function(b){return 13==b.keyCode?d(a):void 0}),tinymce.Env.ie?void a.on("focus",function(){if(!f){f=!0;try{a.execCommand("AutoUrlDetect",!1,!0)}catch(b){}}}):(a.on("keypress",function(c){return 41==c.keyCode?b(a):void 0}),void a.on("keyup",function(b){return 32==b.keyCode?c(a):void 0}))}); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/insertdatetime/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("insertdatetime",function(a){function b(b,c){function d(a,b){if(a=""+a,a.length'+d+"";var f=a.dom.getParent(a.selection.getStart(),"time");if(f)return void a.dom.setOuterHTML(f,d)}a.insertContent(d)}var d,e,f="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),g="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),h="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),i="January February March April May June July August September October November December".split(" "),j=[];a.addCommand("mceInsertDate",function(){c(a.getParam("insertdatetime_dateformat",a.translate("%Y-%m-%d")))}),a.addCommand("mceInsertTime",function(){c(a.getParam("insertdatetime_timeformat",a.translate("%H:%M:%S")))}),a.addButton("insertdatetime",{type:"splitbutton",title:"Insert date/time",onclick:function(){c(d||e)},menu:j}),tinymce.each(a.settings.insertdatetime_formats||["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"],function(a){e||(e=a),j.push({text:b(a),onclick:function(){d=a,c(a)}})}),a.addMenuItem("insertdatetime",{icon:"date",text:"Insert date/time",menu:j,context:"insert"})}); -------------------------------------------------------------------------------- /client/app/controllers/main/about/about.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

About never:code

4 |
5 | 35 |
36 |
37 | 38 | Nevercode is driven by the question, "How do you become a world class programmer?" 39 | We aim to help take great programmers and make them wizards by allowing them to easily 40 | store, edit, and retrieve code throughout their careers. Instead of rifiling through old 41 | project files for your interesting or useful algorithms, test arrays, and boilerplates 42 | try pulling them straight into your text editor with <N>ever:code 43 | 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /client/assets/codemirror-themes/yeti.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Name: yeti 4 | Author: Michael Kaminsky (http://github.com/mkaminsky11) 5 | 6 | Original yeti color scheme by Jesse Weed (https://github.com/jesseweed/yeti-syntax) 7 | 8 | */ 9 | 10 | 11 | .cm-s-yeti.CodeMirror { 12 | background-color: #ECEAE8 !important; 13 | color: #d1c9c0 !important; 14 | border: none; 15 | } 16 | 17 | .cm-s-yeti .CodeMirror-gutters { 18 | color: #adaba6; 19 | background-color: #E5E1DB; 20 | border: none; 21 | } 22 | .cm-s-yeti .CodeMirror-cursor { border-left: solid thin #d1c9c0; } 23 | .cm-s-yeti .CodeMirror-linenumber { color: #adaba6; } 24 | .cm-s-yeti.CodeMirror-focused div.CodeMirror-selected { background: #DCD8D2; } 25 | .cm-s-yeti .CodeMirror-line::selection, .cm-s-yeti .CodeMirror-line > span::selection, .cm-s-yeti .CodeMirror-line > span > span::selection { background: #DCD8D2; } 26 | .cm-s-yeti .CodeMirror-line::-moz-selection, .cm-s-yeti .CodeMirror-line > span::-moz-selection, .cm-s-yeti .CodeMirror-line > span > span::-moz-selection { background: #DCD8D2; } 27 | .cm-s-yeti span.cm-comment { color: #d4c8be; } 28 | .cm-s-yeti span.cm-string, .cm-s-yeti span.cm-string-2 { color: #96c0d8; } 29 | .cm-s-yeti span.cm-number { color: #a074c4; } 30 | .cm-s-yeti span.cm-variable { color: #55b5db; } 31 | .cm-s-yeti span.cm-variable-2 { color: #a074c4; } 32 | .cm-s-yeti span.cm-def { color: #55b5db; } 33 | .cm-s-yeti span.cm-operator { color: #9fb96e; } 34 | .cm-s-yeti span.cm-keyword { color: #9fb96e; } 35 | .cm-s-yeti span.cm-atom { color: #a074c4; } 36 | .cm-s-yeti span.cm-meta { color: #96c0d8; } 37 | .cm-s-yeti span.cm-tag { color: #96c0d8; } 38 | .cm-s-yeti span.cm-attribute { color: #9fb96e; } 39 | .cm-s-yeti span.cm-qualifier { color: #96c0d8; } 40 | .cm-s-yeti span.cm-property { color: #a074c4; } 41 | .cm-s-yeti span.cm-builtin { color: #a074c4; } 42 | .cm-s-yeti span.cm-variable-3 { color: #96c0d8; } 43 | .cm-s-yeti .CodeMirror-activeline-background { background: #E7E4E0; } 44 | .cm-s-yeti .CodeMirror-matchingbracket { text-decoration: underline; } 45 | -------------------------------------------------------------------------------- /client/app/services/UrlEncoding.js: -------------------------------------------------------------------------------- 1 | export default class UrlEncoding { 2 | decodeId(base62String) { 3 | let charMap = {'e':0,'d':1,'i':2,'s':3,'o':4,'n':5,'g':6,'h':7,'c':8,'j':9, 'k':10,'l':11,'m':12,'f':13,'a':14,'p':15,'q':16,'r':17,'b':18,'t':19,'u':20,'v':21,'w':22,'x':23,'y':24,'z':25,'E':26,'D':27,'I':28,'S':29,'O':30,'N':31,'A':32,'B':33,'C':34,'F':35,'G':36,'H':37,'J':38,'K':39,'L':40,'M':41,'P':42,'Q':43,'R':44,'T':45,'U':46,'V':47,'W':48,'X':49,'Y':50,'Z':51,'0':52,'1':53,'2':54,'3':55,'4':56,'5':57,'6':58,'7':59,'8':60,'9':61,}; 4 | let base62Chunks = []; 5 | let id = ''; 6 | for (let i = 0; i < base62String.length; i += 8){ 7 | if(base62String[i + 8]){ 8 | base62Chunks.push(base62String.slice(i, i + 8)); 9 | } else { 10 | base62Chunks.push(base62String.slice(i)); 11 | } 12 | } 13 | for (let i = 0; i < base62Chunks.length; i++){ 14 | let n = 0; 15 | for (let j = 0; j < base62Chunks[i].length ; j++) { 16 | let val = charMap[base62Chunks[i][base62Chunks[i].length - (1+j)]]; 17 | n += (val) * Math.pow(62, j); 18 | } 19 | id = n.toString(16) + id; 20 | } 21 | return id; 22 | 23 | } 24 | shorten(hexString) { 25 | let charSet = ['e','d','i','s','o','n','g','h','c','j','k','l','m','f','a','p','q','r','b','t','u','v','w','x','y','z','E','D','I','S','O','N','A','B','C','F','G','H','J','K','L','M','P','Q','R','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9','#','$']; 26 | let hexChunks = []; 27 | let result = ''; 28 | 29 | for (let i = 0; i < hexString.length; i += 12){ 30 | if(hexString[i + 12]) { 31 | hexChunks.push(hexString.slice(i, i + 12)); 32 | } else { 33 | hexChunks.push(hexString.slice(i)); 34 | } 35 | } 36 | 37 | for (let j = 0; j < hexChunks.length; j++) { 38 | let n = parseInt(hexChunks[j],16); 39 | while (n > 0) { 40 | let charCode = n % 62; 41 | result = charSet[charCode] + result; 42 | n = (n-charCode) /62; 43 | } 44 | } 45 | 46 | return result; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /client/assets/codemirror-themes/zenburn.css: -------------------------------------------------------------------------------- 1 | /** 2 | * " 3 | * Using Zenburn color palette from the Emacs Zenburn Theme 4 | * https://github.com/bbatsov/zenburn-emacs/blob/master/zenburn-theme.el 5 | * 6 | * Also using parts of https://github.com/xavi/coderay-lighttable-theme 7 | * " 8 | * From: https://github.com/wisenomad/zenburn-lighttable-theme/blob/master/zenburn.css 9 | */ 10 | 11 | .cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; } 12 | .cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; } 13 | .cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white; } 14 | .cm-s-zenburn { background-color: #3f3f3f; color: #dcdccc; } 15 | .cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; } 16 | .cm-s-zenburn span.cm-comment { color: #7f9f7f; } 17 | .cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; } 18 | .cm-s-zenburn span.cm-atom { color: #bfebbf; } 19 | .cm-s-zenburn span.cm-def { color: #dcdccc; } 20 | .cm-s-zenburn span.cm-variable { color: #dfaf8f; } 21 | .cm-s-zenburn span.cm-variable-2 { color: #dcdccc; } 22 | .cm-s-zenburn span.cm-string { color: #cc9393; } 23 | .cm-s-zenburn span.cm-string-2 { color: #cc9393; } 24 | .cm-s-zenburn span.cm-number { color: #dcdccc; } 25 | .cm-s-zenburn span.cm-tag { color: #93e0e3; } 26 | .cm-s-zenburn span.cm-property { color: #dfaf8f; } 27 | .cm-s-zenburn span.cm-attribute { color: #dfaf8f; } 28 | .cm-s-zenburn span.cm-qualifier { color: #7cb8bb; } 29 | .cm-s-zenburn span.cm-meta { color: #f0dfaf; } 30 | .cm-s-zenburn span.cm-header { color: #f0efd0; } 31 | .cm-s-zenburn span.cm-operator { color: #f0efd0; } 32 | .cm-s-zenburn span.CodeMirror-matchingbracket { box-sizing: border-box; background: transparent; border-bottom: 1px solid; } 33 | .cm-s-zenburn span.CodeMirror-nonmatchingbracket { border-bottom: 1px solid; background: none; } 34 | .cm-s-zenburn .CodeMirror-activeline { background: #000000; } 35 | .cm-s-zenburn .CodeMirror-activeline-background { background: #000000; } 36 | .cm-s-zenburn div.CodeMirror-selected { background: #545454; } 37 | .cm-s-zenburn .CodeMirror-focused div.CodeMirror-selected { background: #4f4f4f; } 38 | -------------------------------------------------------------------------------- /client/app/redux/actions.js: -------------------------------------------------------------------------------- 1 | export const setSnippetMap = (snippetMap) => { 2 | return { 3 | type: 'SET_SNIPPET_MAP', 4 | snippetMap 5 | }; 6 | }; 7 | export const addSnippetMap = (filePath, snippetMapNode) => { 8 | return { 9 | type: 'ADD_SNIPPET_MAP', 10 | snippetMapNode, 11 | filePath 12 | }; 13 | }; 14 | export const removeSnippetMap = (filePath) => { 15 | return { 16 | type: 'REMOVE_SNIPPET_MAP', 17 | filePath 18 | }; 19 | }; 20 | export const updateSnippetMap = (oldFilePath, updateFilePath, updateNodeValues) => { 21 | return { 22 | type: 'UPDATE_SNIPPET_MAP', 23 | oldFilePath, 24 | updateFilePath, 25 | updateNodeValues 26 | }; 27 | }; 28 | export const clearSnippetMap = () => { 29 | return { 30 | type: 'DROP_SNIPPET_MAP' 31 | }; 32 | }; 33 | 34 | //Handling which snippet is currently selected 35 | export const setSelectedSnippet = (snippetPath) => { 36 | return { 37 | type: 'SET_SELECTED_SNIPPET', 38 | snippetPath 39 | }; 40 | }; 41 | export const removeSelectedSnippet = () => { 42 | return { 43 | type: 'REMOVE_SELECTED_SNIPPET' 44 | }; 45 | }; 46 | 47 | //Handling which folder is currently selected 48 | export const setSelectedFolder = (folderPath) => { 49 | return { 50 | type: 'SET_SELECTED_FOLDER', 51 | folderPath 52 | }; 53 | }; 54 | export const removeSelectedFolder = () => { 55 | return { 56 | type: 'REMOVE_SELECTED_FOLDER' 57 | }; 58 | }; 59 | 60 | //Handling public snippets 61 | export const setPublicList = (publicList) => { 62 | return { 63 | type: 'SET_PUBLIC_LIST', 64 | publicList 65 | }; 66 | }; 67 | export const setSelectedPublicSnippet = (snippetPath) => { 68 | return { 69 | type: 'SET_SELECTED_PUBLIC_SNIPPET', 70 | snippetPath 71 | }; 72 | }; 73 | export const removeSelectedPublicSnippet = () => { 74 | return { 75 | type: 'REMOVE_SELECTED_PUBLIC_SNIPPET' 76 | }; 77 | }; 78 | 79 | export const setActiveUser = (user) => { 80 | return { 81 | type: 'SET_ACTIVE_USER', 82 | user 83 | }; 84 | }; 85 | export const removeActiveUser = () => { 86 | return { 87 | type: 'REMOVE_ACTIVE_USER' 88 | }; 89 | }; 90 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/autosave/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce._beforeUnloadHandler=function(){var a;return tinymce.each(tinymce.editors,function(b){b.plugins.autosave&&b.plugins.autosave.storeDraft(),!a&&b.isDirty()&&b.getParam("autosave_ask_before_unload",!0)&&(a=b.translate("You have unsaved changes are you sure you want to navigate away?"))}),a},tinymce.PluginManager.add("autosave",function(a){function b(a,b){var c={s:1e3,m:6e4};return a=/^(\d+)([ms]?)$/.exec(""+(a||b)),(a[2]?c[a[2]]:1)*parseInt(a,10)}function c(){var a=parseInt(n.getItem(k+"time"),10)||0;return(new Date).getTime()-a>m.autosave_retention?(d(!1),!1):!0}function d(b){n.removeItem(k+"draft"),n.removeItem(k+"time"),b!==!1&&a.fire("RemoveDraft")}function e(){!j()&&a.isDirty()&&(n.setItem(k+"draft",a.getContent({format:"raw",no_events:!0})),n.setItem(k+"time",(new Date).getTime()),a.fire("StoreDraft"))}function f(){c()&&(a.setContent(n.getItem(k+"draft"),{format:"raw"}),a.fire("RestoreDraft"))}function g(){l||(setInterval(function(){a.removed||e()},m.autosave_interval),l=!0)}function h(){var b=this;b.disabled(!c()),a.on("StoreDraft RestoreDraft RemoveDraft",function(){b.disabled(!c())}),g()}function i(){a.undoManager.beforeChange(),f(),d(),a.undoManager.add()}function j(b){var c=a.settings.forced_root_block;return b=tinymce.trim("undefined"==typeof b?a.getBody().innerHTML:b),""===b||new RegExp("^<"+c+"[^>]*>((\xa0| |[ ]|]*>)+?|)|
$","i").test(b)}var k,l,m=a.settings,n=tinymce.util.LocalStorage;k=m.autosave_prefix||"tinymce-autosave-{path}{query}-{id}-",k=k.replace(/\{path\}/g,document.location.pathname),k=k.replace(/\{query\}/g,document.location.search),k=k.replace(/\{id\}/g,a.id),m.autosave_interval=b(m.autosave_interval,"30s"),m.autosave_retention=b(m.autosave_retention,"20m"),a.addButton("restoredraft",{title:"Restore last draft",onclick:i,onPostRender:h}),a.addMenuItem("restoredraft",{text:"Restore last draft",onclick:i,onPostRender:h,context:"file"}),a.settings.autosave_restore_when_empty!==!1&&(a.on("init",function(){c()&&j()&&f()}),a.on("saveContent",function(){d()})),window.onbeforeunload=tinymce._beforeUnloadHandler,this.hasDraft=c,this.storeDraft=e,this.restoreDraft=f,this.removeDraft=d,this.isEmpty=j}); -------------------------------------------------------------------------------- /client/assets/codemirror-themes/3024-day.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Name: 3024 day 4 | Author: Jan T. Sott (http://github.com/idleberg) 5 | 6 | CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) 7 | Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) 8 | 9 | */ 10 | 11 | .cm-s-3024-day.CodeMirror { background: #f7f7f7; color: #3a3432; } 12 | .cm-s-3024-day div.CodeMirror-selected { background: #d6d5d4; } 13 | 14 | .cm-s-3024-day .CodeMirror-line::selection, .cm-s-3024-day .CodeMirror-line > span::selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d6d5d4; } 15 | .cm-s-3024-day .CodeMirror-line::-moz-selection, .cm-s-3024-day .CodeMirror-line > span::-moz-selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d9d9d9; } 16 | 17 | .cm-s-3024-day .CodeMirror-gutters { background: #f7f7f7; border-right: 0px; } 18 | .cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; } 19 | .cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; } 20 | .cm-s-3024-day .CodeMirror-linenumber { color: #807d7c; } 21 | 22 | .cm-s-3024-day .CodeMirror-cursor { border-left: 1px solid #5c5855; } 23 | 24 | .cm-s-3024-day span.cm-comment { color: #cdab53; } 25 | .cm-s-3024-day span.cm-atom { color: #a16a94; } 26 | .cm-s-3024-day span.cm-number { color: #a16a94; } 27 | 28 | .cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute { color: #01a252; } 29 | .cm-s-3024-day span.cm-keyword { color: #db2d20; } 30 | .cm-s-3024-day span.cm-string { color: #fded02; } 31 | 32 | .cm-s-3024-day span.cm-variable { color: #01a252; } 33 | .cm-s-3024-day span.cm-variable-2 { color: #01a0e4; } 34 | .cm-s-3024-day span.cm-def { color: #e8bbd0; } 35 | .cm-s-3024-day span.cm-bracket { color: #3a3432; } 36 | .cm-s-3024-day span.cm-tag { color: #db2d20; } 37 | .cm-s-3024-day span.cm-link { color: #a16a94; } 38 | .cm-s-3024-day span.cm-error { background: #db2d20; color: #5c5855; } 39 | 40 | .cm-s-3024-day .CodeMirror-activeline-background { background: #e8f2ff; } 41 | .cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important; } 42 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/importcss/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("importcss",function(a){function b(a){var b=tinymce.Env.cacheSuffix;return"string"==typeof a&&(a=a.replace("?"+b,"").replace("&"+b,"")),a}function c(b){var c=a.settings,d=c.skin!==!1?c.skin||"lightgray":!1;if(d){var e=c.skin_url;return e=e?a.documentBaseURI.toAbsolute(e):tinymce.baseURL+"/skins/"+d,b===e+"/content"+(a.inline?".inline":"")+".min.css"}return!1}function d(a){return"string"==typeof a?function(b){return-1!==b.indexOf(a)}:a instanceof RegExp?function(b){return a.test(b)}:a}function e(d,e){function f(a,d){var i,j=a.href;if(j=b(j),j&&e(j,d)&&!c(j)){h(a.imports,function(a){f(a,!0)});try{i=a.cssRules||a.rules}catch(k){}h(i,function(a){a.styleSheet?f(a.styleSheet,!0):a.selectorText&&h(a.selectorText.split(","),function(a){g.push(tinymce.trim(a))})})}}var g=[],i={};h(a.contentCSS,function(a){i[a]=!0}),e||(e=function(a,b){return b||i[a]});try{h(d.styleSheets,function(a){f(a)})}catch(j){}return g}function f(b){var c,d=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(b);if(d){var e=d[1],f=d[2].substr(1).split(".").join(" "),g=tinymce.makeMap("a,img");return d[1]?(c={title:b},a.schema.getTextBlockElements()[e]?c.block=e:a.schema.getBlockElements()[e]||g[e.toLowerCase()]?c.selector=e:c.inline=e):d[2]&&(c={inline:"span",title:b.substr(1),classes:f}),a.settings.importcss_merge_classes!==!1?c.classes=f:c.attributes={"class":f},c}}var g=this,h=tinymce.each;a.on("renderFormatsMenu",function(b){var c=a.settings,i={},j=c.importcss_selector_converter||f,k=d(c.importcss_selector_filter),l=b.control;a.settings.importcss_append||l.items().remove();var m=[];tinymce.each(c.importcss_groups,function(a){a=tinymce.extend({},a),a.filter=d(a.filter),m.push(a)}),h(e(b.doc||a.getDoc(),d(c.importcss_file_filter)),function(b){if(-1===b.indexOf(".mce-")&&!i[b]&&(!k||k(b))){var c,d=j.call(g,b);if(d){var e=d.name||tinymce.DOM.uniqueId();if(m)for(var f=0;f 2 |
3 |
4 |
X
5 |
6 |
7 |
8 | 19 |
20 |
21 |
22 |
23 | 24 | 25 |

Invalid information. Try again.

26 |
27 |
28 | 29 | 30 |
31 |
32 | 33 |
34 |
35 |
36 | Don't have an account? Signup ... 37 |
38 |
39 |
40 |
41 | 42 | -------------------------------------------------------------------------------- /client/assets/codemirror-themes/paraiso-light.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Name: Paraíso (Light) 4 | Author: Jan T. Sott 5 | 6 | Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) 7 | Inspired by the art of Rubens LP (http://www.rubenslp.com.br) 8 | 9 | */ 10 | 11 | .cm-s-paraiso-light.CodeMirror { background: #e7e9db; color: #41323f; } 12 | .cm-s-paraiso-light div.CodeMirror-selected { background: #b9b6b0; } 13 | .cm-s-paraiso-light .CodeMirror-line::selection, .cm-s-paraiso-light .CodeMirror-line > span::selection, .cm-s-paraiso-light .CodeMirror-line > span > span::selection { background: #b9b6b0; } 14 | .cm-s-paraiso-light .CodeMirror-line::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span > span::-moz-selection { background: #b9b6b0; } 15 | .cm-s-paraiso-light .CodeMirror-gutters { background: #e7e9db; border-right: 0px; } 16 | .cm-s-paraiso-light .CodeMirror-guttermarker { color: black; } 17 | .cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; } 18 | .cm-s-paraiso-light .CodeMirror-linenumber { color: #8d8687; } 19 | .cm-s-paraiso-light .CodeMirror-cursor { border-left: 1px solid #776e71; } 20 | 21 | .cm-s-paraiso-light span.cm-comment { color: #e96ba8; } 22 | .cm-s-paraiso-light span.cm-atom { color: #815ba4; } 23 | .cm-s-paraiso-light span.cm-number { color: #815ba4; } 24 | 25 | .cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute { color: #48b685; } 26 | .cm-s-paraiso-light span.cm-keyword { color: #ef6155; } 27 | .cm-s-paraiso-light span.cm-string { color: #fec418; } 28 | 29 | .cm-s-paraiso-light span.cm-variable { color: #48b685; } 30 | .cm-s-paraiso-light span.cm-variable-2 { color: #06b6ef; } 31 | .cm-s-paraiso-light span.cm-def { color: #f99b15; } 32 | .cm-s-paraiso-light span.cm-bracket { color: #41323f; } 33 | .cm-s-paraiso-light span.cm-tag { color: #ef6155; } 34 | .cm-s-paraiso-light span.cm-link { color: #815ba4; } 35 | .cm-s-paraiso-light span.cm-error { background: #ef6155; color: #776e71; } 36 | 37 | .cm-s-paraiso-light .CodeMirror-activeline-background { background: #CFD1C4; } 38 | .cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } 39 | -------------------------------------------------------------------------------- /client/assets/codemirror-themes/twilight.css: -------------------------------------------------------------------------------- 1 | .cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/ 2 | .cm-s-twilight div.CodeMirror-selected { background: #323232; } /**/ 3 | .cm-s-twilight .CodeMirror-line::selection, .cm-s-twilight .CodeMirror-line > span::selection, .cm-s-twilight .CodeMirror-line > span > span::selection { background: rgba(50, 50, 50, 0.99); } 4 | .cm-s-twilight .CodeMirror-line::-moz-selection, .cm-s-twilight .CodeMirror-line > span::-moz-selection, .cm-s-twilight .CodeMirror-line > span > span::-moz-selection { background: rgba(50, 50, 50, 0.99); } 5 | 6 | .cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; } 7 | .cm-s-twilight .CodeMirror-guttermarker { color: white; } 8 | .cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; } 9 | .cm-s-twilight .CodeMirror-linenumber { color: #aaa; } 10 | .cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white; } 11 | 12 | .cm-s-twilight .cm-keyword { color: #f9ee98; } /**/ 13 | .cm-s-twilight .cm-atom { color: #FC0; } 14 | .cm-s-twilight .cm-number { color: #ca7841; } /**/ 15 | .cm-s-twilight .cm-def { color: #8DA6CE; } 16 | .cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/ 17 | .cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def { color: #607392; } /**/ 18 | .cm-s-twilight .cm-operator { color: #cda869; } /**/ 19 | .cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/ 20 | .cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/ 21 | .cm-s-twilight .cm-string-2 { color:#bd6b18; } /*?*/ 22 | .cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/ 23 | .cm-s-twilight .cm-builtin { color: #cda869; } /*?*/ 24 | .cm-s-twilight .cm-tag { color: #997643; } /**/ 25 | .cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/ 26 | .cm-s-twilight .cm-header { color: #FF6400; } 27 | .cm-s-twilight .cm-hr { color: #AEAEAE; } 28 | .cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/ 29 | .cm-s-twilight .cm-error { border-bottom: 1px solid red; } 30 | 31 | .cm-s-twilight .CodeMirror-activeline-background { background: #27282E; } 32 | .cm-s-twilight .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } 33 | -------------------------------------------------------------------------------- /client/app/controllers/main/main.js: -------------------------------------------------------------------------------- 1 | import * as FT from '../../redux/fileTree.js'; 2 | 3 | class MainCtrl { 4 | constructor($ngRedux, $state, $auth, Folders, Auth, Snippets, Public, focus) { 5 | if($auth.isAuthenticated()) { 6 | Auth.getUserInfo(); 7 | } 8 | this.$state = $state; 9 | this.Auth = Auth; 10 | this.Folders = Folders; 11 | this.Snippets = Snippets; 12 | this.Public = Public; 13 | this.focus = focus; 14 | this.signinModalShow = false; 15 | this.signupModalShow = false; 16 | $ngRedux.connect(this.mapStateToThis.bind(this))(this); 17 | } 18 | 19 | toggleSideView(path) { 20 | this.Public.removeSelectedPublicSnippet(); 21 | if(this.$state.is('main.' + path)) { 22 | this.$state.go('main.editor'); 23 | } else { 24 | this.$state.go('main.' + path); 25 | } 26 | } 27 | 28 | openBlankTextEditor() { 29 | this.Public.removeSelectedPublicSnippet(); 30 | this.Snippets.deselectSnippet(); 31 | this.$state.go('main.editor'); 32 | } 33 | 34 | changeActiveTab(folderPath) { 35 | this.Folders.selectFolder(folderPath); 36 | } 37 | 38 | signout() { 39 | this.Auth.signout(); 40 | } 41 | 42 | toggleSigninModal() { 43 | this.signinModalShow = !this.signinModalShow; 44 | } 45 | toggleSignupModal() { 46 | this.signupModalShow = !this.signupModalShow; 47 | } 48 | mapStateToThis(state) { 49 | let { snippetMap, selectedFolder, activeUser } = state; 50 | let boundFT = snippetMap ? FT.createBoundMethods(snippetMap) : null; 51 | this.avatar = activeUser ? activeUser.avatar_url : null; 52 | 53 | let parents = selectedFolder ? boundFT.parents(selectedFolder).reverse() : []; 54 | this.breadcrumbPath = selectedFolder ? parents.concat(boundFT.node(selectedFolder)) : []; 55 | if(this.breadcrumbPath[0]) { 56 | this.breadcrumbPath[0].value = 'Home'; 57 | } 58 | return { 59 | snippetMap, 60 | selectedFolder, 61 | activeUser 62 | }; 63 | } 64 | 65 | } 66 | 67 | const mainPage = () => { 68 | return { 69 | url: '/main', 70 | restrict: 'E', 71 | controllerAs: 'mainCtrl', 72 | controller: MainCtrl, 73 | template: require('./main.html'), 74 | scope: {}, 75 | access: { restricted: false } 76 | }; 77 | }; 78 | 79 | export default mainPage; 80 | 81 | -------------------------------------------------------------------------------- /client/styles/materialize.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // Mixins 4 | @import "node_modules/materialize-css/sass/components/prefixer"; 5 | @import "node_modules/materialize-css/sass/components/mixins"; 6 | @import "node_modules/materialize-css/sass/components/color"; 7 | 8 | // Variables; 9 | @import "variables"; 10 | 11 | // Reset 12 | @import "node_modules/materialize-css/sass/components/normalize"; 13 | 14 | // node_modules/materialize-css/sass/components 15 | @import "node_modules/materialize-css/sass/components/global"; 16 | @import "node_modules/materialize-css/sass/components/icons-material-design"; 17 | @import "node_modules/materialize-css/sass/components/grid"; 18 | @import "node_modules/materialize-css/sass/components/navbar"; 19 | @import "node_modules/materialize-css/sass/components/roboto"; 20 | @import "node_modules/materialize-css/sass/components/typography"; 21 | @import "node_modules/materialize-css/sass/components/cards"; 22 | @import "node_modules/materialize-css/sass/components/toast"; 23 | //@import "node_modules/materialize-css/sass/components/tabs"; 24 | @import "node_modules/materialize-css/sass/components/tooltip"; 25 | @import "node_modules/materialize-css/sass/components/buttons"; 26 | //@import "node_modules/materialize-css/sass/components/dropdown"; 27 | @import "node_modules/materialize-css/sass/components/waves"; 28 | @import "node_modules/materialize-css/sass/components/modal"; 29 | @import "node_modules/materialize-css/sass/components/collapsible"; 30 | @import "node_modules/materialize-css/sass/components/chips"; 31 | @import "node_modules/materialize-css/sass/components/materialbox"; 32 | @import "node_modules/materialize-css/sass/components/form"; 33 | //@import "node_modules/materialize-css/sass/components/table_of_contents"; 34 | @import "node_modules/materialize-css/sass/components/sideNav"; 35 | @import "node_modules/materialize-css/sass/components/preloader"; 36 | @import "node_modules/materialize-css/sass/components/slider"; 37 | @import "node_modules/materialize-css/sass/components/carousel"; 38 | //@import "node_modules/materialize-css/sass/components/date_picker/default.scss"; 39 | //@import "node_modules/materialize-css/sass/components/date_picker/default.date.scss"; 40 | //@import "node_modules/materialize-css/sass/components/date_picker/default.time.scss"; 41 | 42 | //our styles 43 | //@import "style" -------------------------------------------------------------------------------- /client/app/redux/reducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { insertNode, deleteNode, updateNode } from './fileTree.js'; 3 | 4 | const modifySelectedSnippet = (state = '', action) => { 5 | switch (action.type) { 6 | case 'SET_SELECTED_SNIPPET': 7 | return action.snippetPath; 8 | case 'REMOVE_SELECTED_SNIPPET': 9 | return ''; 10 | default: 11 | return state; 12 | } 13 | }; 14 | 15 | const modifySelectedFolder = (state = '', action) => { 16 | switch (action.type) { 17 | case 'SET_SELECTED_FOLDER': 18 | return action.folderPath; 19 | case 'REMOVE_SELECTED_FOLDER': 20 | return ''; 21 | default: 22 | return state; 23 | } 24 | }; 25 | 26 | const modifySnippetMap = (state = {}, action) => { 27 | switch (action.type) { 28 | case 'SET_SNIPPET_MAP': 29 | return action.snippetMap; 30 | case 'ADD_SNIPPET_MAP': 31 | return insertNode(state, action.filePath, action.snippetMapNode); 32 | case 'REMOVE_SNIPPET_MAP': 33 | return deleteNode(state, action.filePath); 34 | case 'UPDATE_SNIPPET_MAP': 35 | let { oldFilePath, updateFilePath, updateNodeValues } = action; 36 | return updateNode(state, oldFilePath, updateFilePath, updateNodeValues); 37 | case 'DROP_SNIPPET_MAP': 38 | return {}; 39 | default: 40 | return state; 41 | } 42 | }; 43 | 44 | const modifyActiveUser = (state = {}, action) => { 45 | switch (action.type) { 46 | case 'SET_ACTIVE_USER': 47 | return action.user; 48 | case 'REMOVE_ACTIVE_USER': 49 | return {}; 50 | default: 51 | return state; 52 | } 53 | }; 54 | 55 | const modifySelectedPublicSnippet = (state = '', action) => { 56 | switch (action.type) { 57 | case 'SET_SELECTED_PUBLIC_SNIPPET': 58 | return action.snippetPath; 59 | case 'REMOVE_SELECTED_PUBLIC_SNIPPET': 60 | return ''; 61 | default: 62 | return state; 63 | } 64 | }; 65 | 66 | const modifyPublicList = (state = {}, action) => { 67 | switch (action.type) { 68 | case 'SET_PUBLIC_LIST': 69 | return action.publicList; 70 | default: 71 | return state; 72 | } 73 | }; 74 | 75 | export const finalReducer = combineReducers({ 76 | selectedSnippet: modifySelectedSnippet, 77 | selectedFolder: modifySelectedFolder, 78 | snippetMap: modifySnippetMap, 79 | activeUser: modifyActiveUser, 80 | publicList: modifyPublicList, 81 | selectedPublicSnippet: modifySelectedPublicSnippet 82 | }); 83 | -------------------------------------------------------------------------------- /client/app/controllers/main/public/public.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 | 8 |

never:code

9 |
Your personal code library
10 |
11 |
12 |
13 |
14 |
15 |

Public Snippets

16 | 21 |
22 |
23 |
24 |
    25 | 46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | 62 | 63 | 64 |
65 | -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/content.inline.min.css: -------------------------------------------------------------------------------- 1 | .mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}hr{cursor:default}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #f00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #bbb}td[data-mce-selected],th[data-mce-selected]{background-color:#39f !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7acaff}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1} -------------------------------------------------------------------------------- /client/assets/codemirror-themes/material.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Name: material 4 | Author: Michael Kaminsky (http://github.com/mkaminsky11) 5 | 6 | Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme) 7 | 8 | */ 9 | 10 | .cm-s-material { 11 | background-color: #263238; 12 | color: rgba(233, 237, 237, 1); 13 | } 14 | .cm-s-material .CodeMirror-gutters { 15 | background: #263238; 16 | color: rgb(83,127,126); 17 | border: none; 18 | } 19 | .cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); } 20 | .cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } 21 | .cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); } 22 | .cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } 23 | .cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); } 24 | .cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); } 25 | 26 | .cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); } 27 | .cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); } 28 | .cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); } 29 | .cm-s-material .cm-variable-2 { color: #80CBC4; } 30 | .cm-s-material .cm-variable-3 { color: #82B1FF; } 31 | .cm-s-material .cm-builtin { color: #DECB6B; } 32 | .cm-s-material .cm-atom { color: #F77669; } 33 | .cm-s-material .cm-number { color: #F77669; } 34 | .cm-s-material .cm-def { color: rgba(233, 237, 237, 1); } 35 | .cm-s-material .cm-string { color: #C3E88D; } 36 | .cm-s-material .cm-string-2 { color: #80CBC4; } 37 | .cm-s-material .cm-comment { color: #546E7A; } 38 | .cm-s-material .cm-variable { color: #82B1FF; } 39 | .cm-s-material .cm-tag { color: #80CBC4; } 40 | .cm-s-material .cm-meta { color: #80CBC4; } 41 | .cm-s-material .cm-attribute { color: #FFCB6B; } 42 | .cm-s-material .cm-property { color: #80CBAE; } 43 | .cm-s-material .cm-qualifier { color: #DECB6B; } 44 | .cm-s-material .cm-variable-3 { color: #DECB6B; } 45 | .cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); } 46 | .cm-s-material .cm-error { 47 | color: rgba(255, 255, 255, 1.0); 48 | background-color: #EC5F67; 49 | } 50 | .cm-s-material .CodeMirror-matchingbracket { 51 | text-decoration: underline; 52 | color: white !important; 53 | } 54 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/textpattern/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("textpattern",function(a){function b(){return j&&(i.sort(function(a,b){return a.start.length>b.start.length?-1:a.start.lengthh&&e[d]==g&&(h=d);if(0>c){for(d=0;d-1?(e[h].style.zIndex=f[i],e[i].style.zIndex=f[h]):f[h]>0&&(e[h].style.zIndex=f[h]-1)}else{for(d=0;df[h]){i=d;break}i>-1?(e[h].style.zIndex=f[i],e[i].style.zIndex=f[h]):e[h].style.zIndex=f[h]+1}a.execCommand("mceRepaint")}function e(){var b=a.dom,c=b.getPos(b.getParent(a.selection.getNode(),"*")),d=a.getBody();a.dom.add(d,"div",{style:{position:"absolute",left:c.x,top:c.y>20?c.y:20,width:100,height:100},"class":"mceItemVisualAid mceItemLayer"},a.selection.getContent()||a.getLang("layer.content")),tinymce.Env.ie&&b.setHTML(d,d.innerHTML)}function f(){var c=b(a.selection.getNode());c||(c=a.dom.getParent(a.selection.getNode(),"DIV,P,IMG")),c&&("absolute"==c.style.position.toLowerCase()?(a.dom.setStyles(c,{position:"",left:"",top:"",width:"",height:""}),a.dom.removeClass(c,"mceItemVisualAid"),a.dom.removeClass(c,"mceItemLayer")):(c.style.left||(c.style.left="20px"),c.style.top||(c.style.top="20px"),c.style.width||(c.style.width=c.width?c.width+"px":"100px"),c.style.height||(c.style.height=c.height?c.height+"px":"100px"),c.style.position="absolute",a.dom.setAttrib(c,"data-mce-style",""),a.addVisual(a.getBody())),a.execCommand("mceRepaint"),a.nodeChanged())}a.addCommand("mceInsertLayer",e),a.addCommand("mceMoveForward",function(){d(1)}),a.addCommand("mceMoveBackward",function(){d(-1)}),a.addCommand("mceMakeAbsolute",function(){f()}),a.addButton("moveforward",{title:"layer.forward_desc",cmd:"mceMoveForward"}),a.addButton("movebackward",{title:"layer.backward_desc",cmd:"mceMoveBackward"}),a.addButton("absolute",{title:"layer.absolute_desc",cmd:"mceMakeAbsolute"}),a.addButton("insertlayer",{title:"layer.insertlayer_desc",cmd:"mceInsertLayer"}),a.on("init",function(){tinymce.Env.ie&&a.getDoc().execCommand("2D-Position",!1,!0)}),a.on("mouseup",function(c){var d=b(c.target);d&&a.dom.setAttrib(d,"data-mce-style","")}),a.on("mousedown",function(c){var d,e=c.target,f=a.getDoc();tinymce.Env.gecko&&(b(e)?"on"!==f.designMode&&(f.designMode="on",e=f.body,d=e.parentNode,d.removeChild(e),d.appendChild(e)):"on"==f.designMode&&(f.designMode="off"))}),a.on("NodeChange",c)}); -------------------------------------------------------------------------------- /client/js/tinymce/skins/lightgray/content.min.css: -------------------------------------------------------------------------------- 1 | body{background-color:#fff;color:#000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;scrollbar-3dlight-color:#f0f0ee;scrollbar-arrow-color:#676662;scrollbar-base-color:#f0f0ee;scrollbar-darkshadow-color:#ddd;scrollbar-face-color:#e0e0dd;scrollbar-highlight-color:#f0f0ee;scrollbar-shadow-color:#f0f0ee;scrollbar-track-color:#f5f5f5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}hr{cursor:default}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #f00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #bbb}td[data-mce-selected],th[data-mce-selected]{background-color:#39f !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7acaff}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1} -------------------------------------------------------------------------------- /client/js/tinymce/plugins/codesample/css/prism.css: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */ 2 | /** 3 | * prism.js default theme for JavaScript, CSS and HTML 4 | * Based on dabblet (http://dabblet.com) 5 | * @author Lea Verou 6 | */ 7 | 8 | code[class*="language-"], 9 | pre[class*="language-"] { 10 | color: black; 11 | text-shadow: 0 1px white; 12 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 13 | direction: ltr; 14 | text-align: left; 15 | white-space: pre; 16 | word-spacing: normal; 17 | word-break: normal; 18 | word-wrap: normal; 19 | line-height: 1.5; 20 | 21 | -moz-tab-size: 4; 22 | -o-tab-size: 4; 23 | tab-size: 4; 24 | 25 | -webkit-hyphens: none; 26 | -moz-hyphens: none; 27 | -ms-hyphens: none; 28 | hyphens: none; 29 | } 30 | 31 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 32 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 33 | text-shadow: none; 34 | background: #b3d4fc; 35 | } 36 | 37 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 38 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 39 | text-shadow: none; 40 | background: #b3d4fc; 41 | } 42 | 43 | @media print { 44 | code[class*="language-"], 45 | pre[class*="language-"] { 46 | text-shadow: none; 47 | } 48 | } 49 | 50 | /* Code blocks */ 51 | pre[class*="language-"] { 52 | padding: 1em; 53 | margin: .5em 0; 54 | overflow: auto; 55 | } 56 | 57 | :not(pre) > code[class*="language-"], 58 | pre[class*="language-"] { 59 | background: #f5f2f0; 60 | } 61 | 62 | /* Inline code */ 63 | :not(pre) > code[class*="language-"] { 64 | padding: .1em; 65 | border-radius: .3em; 66 | } 67 | 68 | .token.comment, 69 | .token.prolog, 70 | .token.doctype, 71 | .token.cdata { 72 | color: slategray; 73 | } 74 | 75 | .token.punctuation { 76 | color: #999; 77 | } 78 | 79 | .namespace { 80 | opacity: .7; 81 | } 82 | 83 | .token.property, 84 | .token.tag, 85 | .token.boolean, 86 | .token.number, 87 | .token.constant, 88 | .token.symbol, 89 | .token.deleted { 90 | color: #905; 91 | } 92 | 93 | .token.selector, 94 | .token.attr-name, 95 | .token.string, 96 | .token.char, 97 | .token.builtin, 98 | .token.inserted { 99 | color: #690; 100 | } 101 | 102 | .token.operator, 103 | .token.entity, 104 | .token.url, 105 | .language-css .token.string, 106 | .style .token.string { 107 | color: #a67f59; 108 | background: hsla(0, 0%, 100%, .5); 109 | } 110 | 111 | .token.atrule, 112 | .token.attr-value, 113 | .token.keyword { 114 | color: #07a; 115 | } 116 | 117 | .token.function { 118 | color: #DD4A68; 119 | } 120 | 121 | .token.regex, 122 | .token.important, 123 | .token.variable { 124 | color: #e90; 125 | } 126 | 127 | .token.important, 128 | .token.bold { 129 | font-weight: bold; 130 | } 131 | .token.italic { 132 | font-style: italic; 133 | } 134 | 135 | .token.entity { 136 | cursor: help; 137 | } 138 | 139 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/bbcode/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){tinymce.create("tinymce.plugins.BBCodePlugin",{init:function(a){var b=this,c=a.getParam("bbcode_dialect","punbb").toLowerCase();a.on("beforeSetContent",function(a){a.content=b["_"+c+"_bbcode2html"](a.content)}),a.on("postProcess",function(a){a.set&&(a.content=b["_"+c+"_bbcode2html"](a.content)),a.get&&(a.content=b["_"+c+"_html2bbcode"](a.content))})},getInfo:function(){return{longname:"BBCode Plugin",author:"Ephox Corp",authorurl:"http://www.tinymce.com",infourl:"http://www.tinymce.com/wiki.php/Plugin:bbcode"}},_punbb_html2bbcode:function(a){function b(b,c){a=a.replace(b,c)}return a=tinymce.trim(a),b(/(.*?)<\/a>/gi,"[url=$1]$2[/url]"),b(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),b(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),b(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),b(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),b(/(.*?)<\/span>/gi,"[color=$1]$2[/color]"),b(/(.*?)<\/font>/gi,"[color=$1]$2[/color]"),b(/(.*?)<\/span>/gi,"[size=$1]$2[/size]"),b(/(.*?)<\/font>/gi,"$1"),b(//gi,"[img]$1[/img]"),b(/(.*?)<\/span>/gi,"[code]$1[/code]"),b(/(.*?)<\/span>/gi,"[quote]$1[/quote]"),b(/(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"),b(/(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"),b(/(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"),b(/(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"),b(/(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"),b(/(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"),b(/<\/(strong|b)>/gi,"[/b]"),b(/<(strong|b)>/gi,"[b]"),b(/<\/(em|i)>/gi,"[/i]"),b(/<(em|i)>/gi,"[i]"),b(/<\/u>/gi,"[/u]"),b(/(.*?)<\/span>/gi,"[u]$1[/u]"),b(//gi,"[u]"),b(/]*>/gi,"[quote]"),b(/<\/blockquote>/gi,"[/quote]"),b(/
/gi,"\n"),b(//gi,"\n"),b(/
/gi,"\n"),b(/

/gi,""),b(/<\/p>/gi,"\n"),b(/ |\u00a0/gi," "),b(/"/gi,'"'),b(/</gi,"<"),b(/>/gi,">"),b(/&/gi,"&"),a},_punbb_bbcode2html:function(a){function b(b,c){a=a.replace(b,c)}return a=tinymce.trim(a),b(/\n/gi,"
"),b(/\[b\]/gi,""),b(/\[\/b\]/gi,""),b(/\[i\]/gi,""),b(/\[\/i\]/gi,""),b(/\[u\]/gi,""),b(/\[\/u\]/gi,""),b(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'$2'),b(/\[url\](.*?)\[\/url\]/gi,'$1'),b(/\[img\](.*?)\[\/img\]/gi,''),b(/\[color=(.*?)\](.*?)\[\/color\]/gi,'$2'),b(/\[code\](.*?)\[\/code\]/gi,'$1 '),b(/\[quote.*?\](.*?)\[\/quote\]/gi,'$1 '),a}}),tinymce.PluginManager.add("bbcode",tinymce.plugins.BBCodePlugin)}(); -------------------------------------------------------------------------------- /client/js/tinymce/plugins/legacyoutput/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(a){a.on("AddEditor",function(a){a.editor.settings.inline_styles=!1}),a.PluginManager.add("legacyoutput",function(b,c,d){b.on("init",function(){var c="p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img",d=a.explode(b.settings.font_size_style_values),e=b.schema;b.formatter.register({alignleft:{selector:c,attributes:{align:"left"}},aligncenter:{selector:c,attributes:{align:"center"}},alignright:{selector:c,attributes:{align:"right"}},alignjustify:{selector:c,attributes:{align:"justify"}},bold:[{inline:"b",remove:"all"},{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}}],italic:[{inline:"i",remove:"all"},{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}}],underline:[{inline:"u",remove:"all"},{inline:"span",styles:{textDecoration:"underline"},exact:!0}],strikethrough:[{inline:"strike",remove:"all"},{inline:"span",styles:{textDecoration:"line-through"},exact:!0}],fontname:{inline:"font",attributes:{face:"%value"}},fontsize:{inline:"font",attributes:{size:function(b){return a.inArray(d,b.value)+1}}},forecolor:{inline:"font",attributes:{color:"%value"}},hilitecolor:{inline:"font",styles:{backgroundColor:"%value"}}}),a.each("b,i,u,strike".split(","),function(a){e.addValidElements(a+"[*]")}),e.getElementRule("font")||e.addValidElements("font[face|size|color|style]"),a.each(c.split(","),function(a){var b=e.getElementRule(a);b&&(b.attributes.align||(b.attributes.align={},b.attributesOrder.push("align")))})}),b.addButton("fontsizeselect",function(){var a=[],c="8pt=1 10pt=2 12pt=3 14pt=4 18pt=5 24pt=6 36pt=7",d=b.settings.fontsize_formats||c;return b.$.each(d.split(" "),function(b,c){var d=c,e=c,f=c.split("=");f.length>1&&(d=f[0],e=f[1]),a.push({text:d,value:e})}),{type:"listbox",text:"Font Sizes",tooltip:"Font Sizes",values:a,fixedWidth:!0,onPostRender:function(){var a=this;b.on("NodeChange",function(){var c;c=b.dom.getParent(b.selection.getNode(),"font"),c?a.value(c.size):a.value("")})},onclick:function(a){a.control.settings.value&&b.execCommand("FontSize",!1,a.control.settings.value)}}}),b.addButton("fontselect",function(){function a(a){a=a.replace(/;$/,"").split(";");for(var b=a.length;b--;)a[b]=a[b].split("=");return a}var c="Andale Mono=andale mono,monospace;Arial=arial,helvetica,sans-serif;Arial Black=arial black,sans-serif;Book Antiqua=book antiqua,palatino,serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,palatino,serif;Helvetica=helvetica,arial,sans-serif;Impact=impact,sans-serif;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco,monospace;Times New Roman=times new roman,times,serif;Trebuchet MS=trebuchet ms,geneva,sans-serif;Verdana=verdana,geneva,sans-serif;Webdings=webdings;Wingdings=wingdings,zapf dingbats",e=[],f=a(b.settings.font_formats||c);return d.each(f,function(a,b){e.push({text:{raw:b[0]},value:b[1],textStyle:-1==b[1].indexOf("dings")?"font-family:"+b[1]:""})}),{type:"listbox",text:"Font Family",tooltip:"Font Family",values:e,fixedWidth:!0,onPostRender:function(){var a=this;b.on("NodeChange",function(){var c;c=b.dom.getParent(b.selection.getNode(),"font"),c?a.value(c.face):a.value("")})},onselect:function(a){a.control.settings.value&&b.execCommand("FontName",!1,a.control.settings.value)}}})})}(tinymce); -------------------------------------------------------------------------------- /client/app/app.js: -------------------------------------------------------------------------------- 1 | import angular from 'angular'; 2 | import createLogger from 'redux-logger'; 3 | import {finalReducer} from './redux/reducers.js'; 4 | import {Folders, Auth, Snippets, Public, UrlEncoding} from './services/index.js'; 5 | import {createFolderModal, createEditorModal, createMoveModal, createAuthModal} from './modals/index.js'; 6 | import {mainPage, publicPage, editor, snippets, profile, downloadPage, aboutPage, search} from './controllers/index.js'; 7 | import setup from '../../setup.js'; 8 | import 'angular-ui-router'; 9 | import 'satellizer'; 10 | import 'ng-redux'; 11 | import 'angular-ui-codemirror'; 12 | import 'ngclipboard'; 13 | import 'angular-animate'; 14 | import './tinymce/tinymce.js'; 15 | import 'ng-focus-on'; 16 | 17 | angular.module('evercode', ['ngRedux', 'ui.router', 'satellizer','ui.codemirror', 'ngclipboard', 'ngAnimate', 'ui.tinymce', 'focusOn']) 18 | .config(($stateProvider, $urlRouterProvider, $httpProvider, $ngReduxProvider, $authProvider) => { 19 | 20 | $authProvider.oauth2({ 21 | name: 'github', 22 | url: '/user/auth/github', 23 | clientId: setup.githubClientId, 24 | redirectUri: window.location.origin, 25 | authorizationEndpoint: 'https://github.com/login/oauth/authorize' 26 | }); 27 | 28 | $urlRouterProvider.otherwise('/main/public'); 29 | $stateProvider 30 | .state('main', mainPage()) 31 | .state('main.public', publicPage()) 32 | .state('main.editor', editor()) 33 | .state('main.editor.snippets', snippets('/snippets')) 34 | .state('main.editor.favorites', snippets('/favorites')) 35 | .state('main.editor.profile', profile()) 36 | .state('main.editor.search', search()) 37 | .state('main.download', downloadPage()) 38 | .state('main.about', aboutPage()); 39 | 40 | $httpProvider.interceptors.push('AttachTokens'); 41 | $ngReduxProvider.createStoreWith(finalReducer, [createLogger()]); 42 | }) 43 | .service('Auth', Auth) 44 | .service('Folders', Folders) 45 | .service('Snippets', Snippets) 46 | .service('Public', Public) 47 | .service('UrlEncoding', UrlEncoding) 48 | .directive('signin', createAuthModal('/signin')) 49 | .directive('signup', createAuthModal('/signup')) 50 | .directive('editor', createEditorModal) 51 | .directive('folder', createFolderModal) 52 | .directive('move', createMoveModal) 53 | .factory('AttachTokens', ($window) => { 54 | var attach = { 55 | request: (object) => { 56 | var jwt = $window.localStorage.getItem('satellizer_token'); 57 | if (jwt) { 58 | object.headers.Authorization = jwt; 59 | } 60 | object.headers['Allow-Control-Allow-Origin'] = '*'; 61 | return object; 62 | } 63 | }; 64 | return attach; 65 | }) 66 | .run(($rootScope, $state, $auth, $location) => { 67 | $rootScope.$on('$stateChangeStart', (event, next, toParams, fromState) => { 68 | if (($location.absUrl().indexOf('?') === -1) && !$auth.isAuthenticated() && (next.access.restricted || next.name === 'main.editor')) { 69 | if (!fromState.name) { 70 | $state.go('main.public'); 71 | } 72 | event.preventDefault(); 73 | Materialize.toast('Please sign in first', 2000, 'rounded'); 74 | } 75 | }); 76 | $rootScope.$on('$stateChangeSuccess', () => { 77 | $('.material-tooltip').css('display', 'none'); 78 | if ($state.is('main')) { 79 | $state.go('.public'); 80 | } 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evercode", 3 | "version": "0.0.1", 4 | "description": "A place to store and easily retrieve pieces of code.", 5 | "dependencies": { 6 | "angular": "^1.5.0", 7 | "angular-animate": "^1.5.2", 8 | "angular-route": "^1.5.0", 9 | "angular-ui-codemirror": "^0.3.0", 10 | "angular-ui-router": "^0.2.18", 11 | "babel": "^6.5.2", 12 | "babel-preset-es2015": "^6.6.0", 13 | "bcrypt": "^0.8.5", 14 | "bluebird": "^3.3.4", 15 | "body-parser": "^1.15.0", 16 | "cluster": "^0.7.7", 17 | "codemirror": "^5.12.0", 18 | "email-verification": "^0.3.1", 19 | "express": "^4.4.5", 20 | "google-auth-library": "^0.9.7", 21 | "googleapis": "^3.1.0", 22 | "grunt": "^0.4.5", 23 | "html-webpack-plugin": "^2.10.0", 24 | "jshint": "^2.9.1", 25 | "jsonwebtoken": "^5.7.0", 26 | "materialize-css": "0.97.5", 27 | "mocks": "0.0.15", 28 | "mongoose": "^4.4.6", 29 | "morgan": "^1.7.0", 30 | "ng-focus-on": "^0.2.2", 31 | "ng-redux": "^3.3.3", 32 | "ngclipboard": "^1.1.1", 33 | "passport": "^0.3.2", 34 | "passport-github": "^1.1.0", 35 | "path": "^0.12.7", 36 | "precommit-hook": "^3.0.0", 37 | "querystring": "^0.2.0", 38 | "ramda": "^0.19.1", 39 | "raw-loader": "^0.5.1", 40 | "readline": "^1.3.0", 41 | "redis": "^2.5.0-1", 42 | "redux": "^3.3.1", 43 | "redux-logger": "^2.6.1", 44 | "request": "^2.69.0", 45 | "satellizer": "^0.14.0", 46 | "source-map-loader": "^0.1.5", 47 | "supertest": "^1.2.0", 48 | "webpack": "^1.12.14", 49 | "webpack-dev-server": "^1.14.1" 50 | }, 51 | "devDependencies": { 52 | "babel-core": "^6.7.2", 53 | "babel-loader": "^6.2.4", 54 | "babel-polyfill": "^6.5.0", 55 | "chai": "^3.4.1", 56 | "eslint": "^2.1.0", 57 | "eslint-config-hackreactor": "git://github.com/hackreactor-labs/eslint-config-hackreactor", 58 | "grunt-contrib-concat": "^1.0.0", 59 | "grunt-contrib-cssmin": "^1.0.1", 60 | "grunt-contrib-uglify": "^1.0.1", 61 | "grunt-ng-annotate": "^2.0.1", 62 | "gulp": "^3.9.1", 63 | "gulp-nodemon": "^1.0.4", 64 | "gulp-shell": "^0.2.7", 65 | "load-grunt-tasks": "^3.4.1", 66 | "mocha": "^2.3.4", 67 | "webpack-dev-server": "^1.14.1" 68 | }, 69 | "scripts": { 70 | "nginx": "sudo nginx", 71 | "user-server": "nodemon --harmony-destructuring user-server/noncluster.js", 72 | "files-server": "nodemon --harmony-destructuring files-server/noncluster.js", 73 | "start-servers": "npm run user-server & npm run files-server", 74 | "css": "node-sass client/styles/materialize.scss client/styles/materialize.css", 75 | "test": "mocha test --harmony-destructuring", 76 | "start": "node --harmony-destructuring server/noncluster.js", 77 | "cluster": "node --harmony-destructuring server/cluster.js", 78 | "dev": "webpack-dev-server --devtool source-map --progress --colors --hot --content-base client", 79 | "lint": "jshint .", 80 | "validate": "npm ls" 81 | }, 82 | "repository": { 83 | "type": "git", 84 | "url": "https://github.com/precocious-tangerine/nevercode.git" 85 | }, 86 | "author": "Edison D. Huff, Gerrit Yntema, Max Kroshka, Orlando Castillo", 87 | "license": "UNLICENSED", 88 | "bugs": { 89 | "url": "https://github.com/precocious-tangerine/nevercode.git/issues" 90 | }, 91 | "homepage": "https://github.com/precocious-tangerine/nevercode.git#readme", 92 | "pre-commit": [ 93 | "lint", 94 | "test" 95 | ] 96 | } 97 | -------------------------------------------------------------------------------- /client/app/modals/editormodal/editorModal.html: -------------------------------------------------------------------------------- 1 |

2 |
3 |
4 |
X
5 |
6 | {{editorModal.snippetObj.name}}
7 | {{editorModal.snippetObj.description}} 8 |
9 |
10 | 14 |
15 |
16 |
17 | TAGS: 18 | 20 | {{ tag }} 21 | 22 |
23 |
24 |
25 |
26 | 33 | assignment 34 | 35 |
36 | 42 |
43 |
44 | 50 |
51 | 58 | share 59 | 60 |
61 |
65 |
66 |
67 |
68 |
69 | 70 | -------------------------------------------------------------------------------- /client/app/services/Auth.js: -------------------------------------------------------------------------------- 1 | import * as Actions from '../redux/actions.js'; 2 | 3 | export default class Auth { 4 | constructor($http, $auth, $ngRedux, Folders) { 5 | $ngRedux.connect(this.mapStateToThis, this.mapDispatchToThis)(this); 6 | this.$http = $http; 7 | this.Folders = Folders; 8 | this.$auth = $auth; 9 | } 10 | mapDispatchToThis(dispatch) { 11 | return { 12 | signin(user) { 13 | return this.$http({ 14 | method: 'POST', 15 | url: 'user/signin', 16 | data: user 17 | }).then((res) => { 18 | this.$auth.setToken(res.data.token); 19 | this.getUserInfo(); 20 | $('#snippets-modal').closeModal({ 21 | dismissible: true, 22 | complete: () => { 23 | $('.lean-overlay').remove(); 24 | } 25 | }); 26 | Materialize.toast('Successfully signed in!', 5000, 'rounded'); 27 | }) 28 | .catch(error => { 29 | console.error(error); 30 | }); 31 | }, 32 | 33 | githubSignin() { 34 | this.$auth.authenticate('github') 35 | .then(() => { 36 | this.getUserInfo(); 37 | Materialize.toast('Successfully signed in!', 5000, 'rounded'); 38 | }) 39 | .catch(error => { 40 | console.error(error); 41 | }); 42 | }, 43 | 44 | signup(user) { 45 | return this.$http({ 46 | method: 'POST', 47 | url: 'user/signup', 48 | data: user 49 | }) 50 | .then(() => { 51 | Materialize.toast('Success! Check your e-mail for verification', 4000, 'rounded'); 52 | }) 53 | .catch(error => { 54 | this.failed = false; 55 | console.error(error); 56 | }); 57 | }, 58 | 59 | getUserInfo() { 60 | return this.$http({ 61 | method: 'GET', 62 | url: '/user/api/userInfo' 63 | }).then(res => { 64 | dispatch(Actions.setActiveUser(res.data)); 65 | this.Folders.getFileTree(); 66 | if(res.data.selectedSnippet) { 67 | dispatch(Actions.setSelectedSnippet(res.data.selectedSnippet)); 68 | } 69 | }) 70 | .catch(error => { 71 | console.error(error); 72 | }); 73 | }, 74 | 75 | updateUser(userObj) { 76 | return this.$http({ 77 | method: 'PUT', 78 | url: 'user/api/userInfo', 79 | data: userObj 80 | }).then(res => { 81 | dispatch(Actions.setActiveUser(res.data)); 82 | }) 83 | .catch(error => { 84 | console.error(error); 85 | }); 86 | }, 87 | 88 | updatePassword(infoObj){ 89 | return this.$http({ 90 | method: 'PUT', 91 | url: 'user/api/updatePassword', 92 | data: infoObj 93 | }).then(() => { 94 | Materialize.toast('Password was succesfully changed!', 4000, 'rounded'); 95 | }).catch(err => { 96 | console.error(err); 97 | }); 98 | }, 99 | 100 | signout() { 101 | this.$auth.logout(); 102 | dispatch(Actions.removeActiveUser()); 103 | dispatch(Actions.removeSelectedFolder()); 104 | dispatch(Actions.removeSelectedSnippet()); 105 | dispatch(Actions.clearSnippetMap()); 106 | } 107 | }; 108 | } 109 | } -------------------------------------------------------------------------------- /client/js/tinymce/plugins/textcolor/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("textcolor",function(a){function b(b){var c;return a.dom.getParents(a.selection.getStart(),function(a){var d;(d=a.style["forecolor"==b?"color":"background-color"])&&(c=d)}),c}function c(){var b,c,d=[];for(c=a.settings.textcolor_map||["000000","Black","993300","Burnt orange","333300","Dark olive","003300","Dark green","003366","Dark azure","000080","Navy Blue","333399","Indigo","333333","Very dark gray","800000","Maroon","FF6600","Orange","808000","Olive","008000","Green","008080","Teal","0000FF","Blue","666699","Grayish blue","808080","Gray","FF0000","Red","FF9900","Amber","99CC00","Yellow green","339966","Sea green","33CCCC","Turquoise","3366FF","Royal blue","800080","Purple","999999","Medium gray","FF00FF","Magenta","FFCC00","Gold","FFFF00","Yellow","00FF00","Lime","00FFFF","Aqua","00CCFF","Sky blue","993366","Red violet","FFFFFF","White","FF99CC","Pink","FFCC99","Peach","FFFF99","Light yellow","CCFFCC","Pale green","CCFFFF","Pale cyan","99CCFF","Light sky blue","CC99FF","Plum"],b=0;b
'+(c?"×":"")+"
"}var d,e,f,g,h,k,l,m=this,n=m._id,o=0;for(d=c(),d.push({text:tinymce.translate("No color"),color:"transparent"}),f='',g=d.length-1,k=0;j>k;k++){for(f+="",h=0;i>h;h++)l=k*i+h,l>g?f+="":(e=d[l],f+=b(e.color,e.text));f+=""}if(a.settings.color_picker_callback){for(f+='",f+="",h=0;i>h;h++)f+=b("","Custom color");f+=""}return f+="
"}function e(b,c){a.undoManager.transact(function(){a.focus(),a.formatter.apply(b,{value:c}),a.nodeChanged()})}function f(b){a.undoManager.transact(function(){a.focus(),a.formatter.remove(b,{value:null},null,!0),a.nodeChanged()})}function g(c){function d(a){k.hidePanel(),k.color(a),e(k.settings.format,a)}function g(){k.hidePanel(),k.resetColor(),f(k.settings.format)}function h(a,b){a.style.background=b,a.setAttribute("data-mce-color",b)}var j,k=this.parent();tinymce.DOM.getParent(c.target,".mce-custom-color-btn")&&(k.hidePanel(),a.settings.color_picker_callback.call(a,function(a){var b,c,e,f=k.panel.getEl().getElementsByTagName("table")[0];for(b=tinymce.map(f.rows[f.rows.length-1].childNodes,function(a){return a.firstChild}),e=0;ee;e++)h(b[e],b[e+1].getAttribute("data-mce-color"));h(c,a),d(a)},b(k.settings.format))),j=c.target.getAttribute("data-mce-color"),j?(this.lastId&&document.getElementById(this.lastId).setAttribute("aria-selected",!1),c.target.setAttribute("aria-selected",!0),this.lastId=c.target.id,"transparent"==j?g():d(j)):null!==j&&k.hidePanel()}function h(){var a=this;a._color?e(a.settings.format,a._color):f(a.settings.format)}var i,j;j=a.settings.textcolor_rows||5,i=a.settings.textcolor_cols||8,a.addButton("forecolor",{type:"colorbutton",tooltip:"Text color",format:"forecolor",panel:{role:"application",ariaRemember:!0,html:d,onclick:g},onclick:h}),a.addButton("backcolor",{type:"colorbutton",tooltip:"Background color",format:"hilitecolor",panel:{role:"application",ariaRemember:!0,html:d,onclick:g},onclick:h})}); -------------------------------------------------------------------------------- /client/app/controllers/main/editor/search/search.html: -------------------------------------------------------------------------------- 1 | 78 | 87 | -------------------------------------------------------------------------------- /client/app/modals/authmodals/signup.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
X
5 |
6 |
7 |
8 | 19 |
20 |
21 |
22 | 23 | 24 |

Email is too short.

25 |

Email is too long.

26 |

User with this e-mail already exists.

27 |
28 |
29 | 30 | 31 |

Username is too short.

32 |

Username is too long.

33 |
34 |
35 | 36 | 37 |

Password is too short.

38 |

Password is too long.

39 |
40 |
41 | 42 | 43 |

Passwords dont match.

44 |
45 | 46 |
47 | Already have an account? Signin ... 48 |
49 |
50 |
51 |
52 |
53 | -------------------------------------------------------------------------------- /client/app/controllers/main/editor/profile/profile.html: -------------------------------------------------------------------------------- 1 | 75 | 76 | -------------------------------------------------------------------------------- /client/app/services/Folders.js: -------------------------------------------------------------------------------- 1 | import * as Actions from '../redux/actions.js'; 2 | import { convertToTree, createBoundMethods } from '../redux/fileTree.js'; 3 | 4 | export default class Folders { 5 | constructor($http, $ngRedux) { 6 | this.$http = $http; 7 | $ngRedux.connect(this.mapStateToThis, this.mapDispatchToThis)(this); 8 | } 9 | 10 | mapDispatchToThis(dispatch) { 11 | return { 12 | getFileTree(snippetPath) { 13 | return this.$http({ 14 | method: 'GET', 15 | url: 'files/api/user/snippets' 16 | }) 17 | .then(res => { 18 | var snippetMap = convertToTree(res.data); 19 | dispatch(Actions.setSnippetMap(snippetMap)); 20 | if(!this.selectedFolder) { 21 | dispatch(Actions.setSelectedFolder('/' + this.email)); 22 | } 23 | if(snippetPath) { 24 | dispatch(Actions.setSelectedSnippet(snippetPath)); 25 | } 26 | }) 27 | .catch(error => { 28 | console.error(error); 29 | }); 30 | }, 31 | 32 | addFolder(folder) { 33 | return this.$http({ 34 | method: 'POST', 35 | url: 'files/api/folders', 36 | data: folder 37 | }) 38 | .then(snippet => { 39 | dispatch(Actions.addSnippetMap(snippet.data.filePath, snippet.data)); 40 | }) 41 | .catch(error => { 42 | console.error(error); 43 | }); 44 | }, 45 | 46 | selectFolder(folderPath) { 47 | dispatch(Actions.setSelectedFolder(folderPath)); 48 | }, 49 | 50 | renameFolder(oldNode, newName) { 51 | let boundFT = createBoundMethods(this.snippetMap); 52 | let oldParent = boundFT.parent(oldNode.filePath); 53 | let newNode = Object.assign({}, oldNode, {value: newName, filePath: oldParent.filePath + '/' + newName}); 54 | 55 | let newChildren = []; 56 | 57 | let changeAllChildFolders = (node, currFilePath, parentFilePath) => { 58 | if(!node) { 59 | return; 60 | } 61 | if(typeof node.value === 'object') { 62 | let newValue = Object.assign({}, node.value, {filePath: currFilePath}); 63 | let newNode = Object.assign({}, node, {parent: parentFilePath, filePath: currFilePath, value: newValue}); 64 | newChildren.push(newNode); 65 | return; 66 | } else { 67 | node.children.forEach(child => { 68 | let childPathArr = child.split('/'); 69 | let newPath = currFilePath + '/' + childPathArr[childPathArr.length-1]; 70 | changeAllChildFolders(this.snippetMap[child], newPath, currFilePath); 71 | }); 72 | } 73 | }; 74 | 75 | changeAllChildFolders(newNode, newNode.filePath); 76 | 77 | newChildren.forEach((currChild, index) => { 78 | return this.$http ({ 79 | method: 'PUT', 80 | url: 'files/api/snippets', 81 | data: {snippetId: currChild.value._id, value: currChild.value} 82 | }) 83 | .then(() => { 84 | if(index === newChildren.length-1) { 85 | this.getFileTree(); 86 | } 87 | }); 88 | }); 89 | }, 90 | 91 | removeFolder(folderPath) { 92 | return this.$http({ 93 | method: 'DELETE', 94 | url: 'files/api/folders', 95 | params: { filePath: folderPath } 96 | }).then(() => { 97 | dispatch(Actions.removeSnippetMap(folderPath)); 98 | }) 99 | .catch(error => { 100 | console.error(error); 101 | }); 102 | } 103 | }; 104 | } 105 | 106 | mapStateToThis(state) { 107 | return { 108 | snippetMap: state.snippetMap, 109 | selectedFolder: state.selectedFolder, 110 | selectedSnippet: state.selectedSnippet, 111 | email: state.activeUser.email 112 | }; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /user-server/models/users.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let mongoose = require('mongoose'); 3 | let setup = require('../../setup.js'); 4 | let db = mongoose.createConnection(setup.mongodbHost + setup.mongodbPort + setup.mongodbUsersName); 5 | 6 | let Promise = require('bluebird'); 7 | let bcrypt = Promise.promisifyAll(require('bcrypt')); 8 | let utils = require('../config/utils.js'); 9 | 10 | let userSchema = mongoose.Schema({ 11 | _password: { type: String }, 12 | _createdAt: { type: Date, default: new Date() }, 13 | _updatedAt: { type: Date, default: new Date() }, 14 | github: { type: Number }, 15 | avatar_url: { type: String }, 16 | username: { type: String, required: true }, 17 | email: { type: String, required: true, unique: true, dropDups: true }, 18 | theme: { type: String, default: 'eclipse' }, 19 | language: { type: String, default: 'javascript' }, 20 | selectedSnippet: { type: String }, 21 | sublimeSecret: { type: String, default: 'No secret issued;' } 22 | }); 23 | 24 | 25 | let userStatics = { 26 | makeUser(userObj, callback) { 27 | let pw = userObj._password; 28 | if (typeof pw === 'string' && pw !== '') { 29 | bcrypt.genSaltAsync(13) 30 | .then((salt) => bcrypt.hashAsync(pw, salt)) 31 | .then((hash) => { 32 | userObj._password = hash; 33 | return utils.createRootFolderAsync(userObj); 34 | }) 35 | .then(() => this.create(userObj)) 36 | .then(result => { 37 | callback(null, result); 38 | }) 39 | .catch(err => callback(err, null)); 40 | } else if (userObj.github) { 41 | // OAuth based login (no supplied password) 42 | utils.createRootFolderAsync(userObj) 43 | .then(() => this.create(userObj)) 44 | .then(() => callback(null, userObj)) 45 | .catch(err => callback(err, null)); 46 | } else { 47 | callback(new Error('must login via github or local session'), null); 48 | } 49 | }, 50 | getUser(email, callback) { 51 | this.findOne({ email }) 52 | .then((userObj) => { 53 | callback(null, userObj); 54 | }) 55 | .catch(callback); 56 | }, 57 | updateUser(email, newProps, callback) { 58 | newProps._updatedAt = new Date(); 59 | this.update({ email }, newProps, { multi: false }, callback); 60 | }, 61 | removeUser(email, callback) { 62 | this.findOne({ email }).remove(callback); 63 | }, 64 | checkCredentials(email, attempt, callback) { 65 | let userData = {}; 66 | this.findOne({ email }) 67 | .then(foundUser => { 68 | if (foundUser) { 69 | userData = foundUser.toObject(); 70 | bcrypt.compareAsync(attempt, foundUser._password) 71 | .then(success => { 72 | if (success) { 73 | delete userData._password; 74 | callback(null, userData); 75 | } else { 76 | callback(new Error('Incorrect Password'), null); 77 | } 78 | }) 79 | .catch(callback); 80 | } else { 81 | callback(new Error('Email not found'), null); 82 | } 83 | }); 84 | }, 85 | createSublimeSecretAsync(email) { 86 | return this.findOne({ email }) 87 | .then(foundUser => { 88 | if (foundUser) { 89 | var newseed = (Math.random() * 100).toString(); 90 | return bcrypt.genSaltAsync(13) 91 | .then(salt => bcrypt.hashAsync(newseed, salt)) 92 | .then(hash => { 93 | foundUser.sublimeSecret = hash; 94 | return this.updateUserAsync(foundUser.email, foundUser); 95 | }) 96 | .then(() => { 97 | return foundUser.sublimeSecret; 98 | }); 99 | } 100 | else { 101 | return new Promise((_,reject) => reject('User not found')); 102 | } 103 | }); 104 | }, 105 | exchangeSecretForTokenAsync(sublimeSecret) { 106 | return this.findOne({ sublimeSecret }); 107 | } 108 | }; 109 | 110 | let userStaticsAsync = Promise.promisifyAll(userStatics); 111 | Object.assign(userSchema.statics, userStaticsAsync); 112 | let User = db.model('User', userSchema); 113 | module.exports = User; -------------------------------------------------------------------------------- /client/js/tinymce/plugins/template/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("template",function(a){function b(b){return function(){var c=a.settings.templates;return"function"==typeof c?void c(b):void("string"==typeof c?tinymce.util.XHR.send({url:c,success:function(a){b(tinymce.util.JSON.parse(a))}}):b(c))}}function c(b){function c(b){function c(b){if(-1==b.indexOf("")){var c="";tinymce.each(a.contentCSS,function(b){c+=''}),b=""+c+""+b+""}b=f(b,"template_preview_replace_values");var e=d.find("iframe")[0].getEl().contentWindow.document;e.open(),e.write(b),e.close()}var g=b.control.value();g.url?tinymce.util.XHR.send({url:g.url,success:function(a){e=a,c(e)}}):(e=g.content,c(e)),d.find("#description")[0].text(b.control.value().description)}var d,e,h=[];if(!b||0===b.length){var i=a.translate("No templates defined.");return void a.notificationManager.open({text:i,type:"info"})}tinymce.each(b,function(a){h.push({selected:!h.length,text:a.title,value:{url:a.url,content:a.content,description:a.description}})}),d=a.windowManager.open({title:"Insert template",layout:"flex",direction:"column",align:"stretch",padding:15,spacing:10,items:[{type:"form",flex:0,padding:0,items:[{type:"container",label:"Templates",items:{type:"listbox",label:"Templates",name:"template",values:h,onselect:c}}]},{type:"label",name:"description",label:"Description",text:"\xa0"},{type:"iframe",flex:1,border:1}],onsubmit:function(){g(!1,e)},width:a.getParam("template_popup_width",600),height:a.getParam("template_popup_height",500)}),d.find("listbox")[0].fire("select")}function d(b,c){function d(a,b){if(a=""+a,a.length0&&(i=k.create("div",null),i.appendChild(j[0].cloneNode(!0))),h(k.select("*",i),function(b){g(b,a.getParam("template_cdate_classes","cdate").replace(/\s+/g,"|"))&&(b.innerHTML=d(a.getParam("template_cdate_format",a.getLang("template.cdate_format")))),g(b,a.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(b.innerHTML=d(a.getParam("template_mdate_format",a.getLang("template.mdate_format")))),g(b,a.getParam("template_selected_content_classes","selcontent").replace(/\s+/g,"|"))&&(b.innerHTML=l)}),e(i),a.execCommand("mceInsertContent",!1,i.innerHTML),a.addVisual()}var h=tinymce.each;a.addCommand("mceInsertTemplate",g),a.addButton("template",{title:"Insert template",onclick:b(c)}),a.addMenuItem("template",{text:"Insert template",onclick:b(c),context:"insert"}),a.on("PreProcess",function(b){var c=a.dom;h(c.select("div",b.node),function(b){c.hasClass(b,"mceTmpl")&&(h(c.select("*",b),function(b){c.hasClass(b,a.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(b.innerHTML=d(a.getParam("template_mdate_format",a.getLang("template.mdate_format"))))}),e(b))})})}); -------------------------------------------------------------------------------- /client/app/services/Snippets.js: -------------------------------------------------------------------------------- 1 | import * as Actions from '../redux/actions.js'; 2 | 3 | export default class Snippets { 4 | constructor($http, $ngRedux, Folders, Auth) { 5 | this.$http = $http; 6 | this.Folders = Folders; 7 | this.Auth = Auth; 8 | $ngRedux.connect(this.mapStateToThis, this.mapDispatchToThis)(this); 9 | } 10 | 11 | mapDispatchToThis(dispatch) { 12 | return { 13 | getSnippet(snippetId) { 14 | return this.$http({ 15 | method: 'GET', 16 | url: 'files/api/snippets?_id=' + snippetId 17 | }); 18 | }, 19 | 20 | addSnippet(snippetObj) { 21 | return this.$http({ 22 | method: 'POST', 23 | url: 'files/api/snippets', 24 | data: snippetObj 25 | }).then((res) => { 26 | dispatch(Actions.addSnippetMap(res.data.filePath, res.data)); 27 | dispatch(Actions.removeSelectedPublicSnippet()); 28 | this.changeSelectedSnippet(res.data.filePath); 29 | Materialize.toast('Snippet added!', 3000, 'rounded'); 30 | }) 31 | .catch(error => { 32 | console.error(error); 33 | }); 34 | }, 35 | 36 | updateSnippet(snippetObj, oldFilePath) { 37 | //delete old id so mongoose doesn't get upset 38 | let snippetId = snippetObj._id; 39 | delete snippetObj.Id; 40 | return this.$http({ 41 | method: 'PUT', 42 | url: 'files/api/snippets', 43 | data: { snippetId, value: snippetObj } 44 | }).then(res => { 45 | let nodeToPass = Object.assign({}, this.snippetMap[oldFilePath], { filePath: res.data.filePath, value: res.data }); 46 | Materialize.toast('Snippet updated!', 3000, 'rounded'); 47 | dispatch(Actions.updateSnippetMap(oldFilePath, res.data.filePath, nodeToPass)); 48 | if(this.activeUser.selectedSnippet === oldFilePath) { 49 | this.Auth.updateUser({ selectedSnippet: res.data.filePath }); 50 | } 51 | if(this.selectedPublicSnippet === oldFilePath) { 52 | dispatch(Actions.setSelectedPublicSnippet(res.data.filePath)); 53 | } 54 | dispatch(Actions.setSelectedSnippet(res.data.filePath)); 55 | }) 56 | .catch(error => { 57 | console.error(error); 58 | }); 59 | 60 | }, 61 | 62 | removeSnippet(snippetObj) { 63 | return this.$http({ 64 | method: 'DELETE', 65 | url: 'files/api/snippets', 66 | params: { snippetId: snippetObj.value._id } 67 | }).then(() => { 68 | this.deselectSnippet(); 69 | dispatch(Actions.removeSnippetMap(snippetObj.filePath)); 70 | if(this.activeUser.selectedSnippet === snippetObj.filePath) { 71 | this.Auth.updateUser({ selectedSnippet: null }); 72 | } 73 | Materialize.toast('Successfully removed!', 3000, 'rounded'); 74 | }) 75 | .catch(error => { 76 | console.error(error); 77 | }); 78 | }, 79 | 80 | changeSelectedSnippet(snippetFilePath) { 81 | dispatch(Actions.removeSelectedPublicSnippet()); 82 | dispatch(Actions.setSelectedSnippet(snippetFilePath)); 83 | this.Auth.updateUser({ selectedSnippet: snippetFilePath }); 84 | }, 85 | 86 | deselectSnippet() { 87 | dispatch(Actions.removeSelectedSnippet()); 88 | }, 89 | 90 | updateUsername(userObj) { 91 | return this.$http({ 92 | method: 'PUT', 93 | url: 'files/api/user/snippets', 94 | data: userObj 95 | }).then(() => { 96 | this.Auth.updateUser({ username: userObj.username }); 97 | this.Folders.getFileTree(); 98 | }) 99 | .catch(error => { 100 | console.error(error); 101 | }); 102 | } 103 | }; 104 | } 105 | mapStateToThis(state) { 106 | return { 107 | snippetMap: state.snippetMap, 108 | selectedFolder: state.selectedFolder, 109 | selectedSnippet: state.selectedSnippet, 110 | activeUser: state.activeUser, 111 | selectedPublicSnippet: state.selectedPublicSnippet 112 | }; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/link/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("link",function(a){function b(b){return function(){var c=a.settings.link_list;"string"==typeof c?tinymce.util.XHR.send({url:c,success:function(a){b(tinymce.util.JSON.parse(a))}}):"function"==typeof c?c(b):b(c)}}function c(a,b,c){function d(a,c){return c=c||[],tinymce.each(a,function(a){var e={text:a.text||a.title};a.menu?e.menu=d(a.menu):(e.value=a.value,b&&b(e)),c.push(e)}),c}return d(a,c||[])}function d(b){function d(a){var b=l.find("#text");(!b.value()||a.lastControl&&b.value()==a.lastControl.text())&&b.value(a.control.text()),l.find("#href").value(a.control.value())}function e(b){var c=[];return tinymce.each(a.dom.select("a:not([href])"),function(a){var d=a.name||a.id;d&&c.push({text:d,value:"#"+d,selected:-1!=b.indexOf("#"+d)})}),c.length?(c.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:c,onselect:d}):void 0}function f(){!k&&0===u.text.length&&m&&this.parent().parent().find("#text")[0].value(this.value())}function g(b){var c=b.meta||{};o&&o.value(a.convertURL(this.value(),"href")),tinymce.each(b.meta,function(a,b){l.find("#"+b).value(a)}),c.text||f.call(this)}function h(a){var b=v.getContent();if(/]+>[^<]+<\/a>$/.test(b)||-1==b.indexOf("href=")))return!1;if(a){var c,d=a.childNodes;if(0===d.length)return!1;for(c=d.length-1;c>=0;c--)if(3!=d[c].nodeType)return!1}return!0}var i,j,k,l,m,n,o,p,q,r,s,t,u={},v=a.selection,w=a.dom;i=v.getNode(),j=w.getParent(i,"a[href]"),m=h(),u.text=k=j?j.innerText||j.textContent:v.getContent({format:"text"}),u.href=j?w.getAttrib(j,"href"):"",j?u.target=w.getAttrib(j,"target"):a.settings.default_link_target&&(u.target=a.settings.default_link_target),(t=w.getAttrib(j,"rel"))&&(u.rel=t),(t=w.getAttrib(j,"class"))&&(u["class"]=t),(t=w.getAttrib(j,"title"))&&(u.title=t),m&&(n={name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){u.text=this.value()}}),b&&(o={type:"listbox",label:"Link list",values:c(b,function(b){b.value=a.convertURL(b.value||b.url,"href")},[{text:"None",value:""}]),onselect:d,value:a.convertURL(u.href,"href"),onPostRender:function(){o=this}}),a.settings.target_list!==!1&&(a.settings.target_list||(a.settings.target_list=[{text:"None",value:""},{text:"New window",value:"_blank"}]),q={name:"target",type:"listbox",label:"Target",values:c(a.settings.target_list)}),a.settings.rel_list&&(p={name:"rel",type:"listbox",label:"Rel",values:c(a.settings.rel_list)}),a.settings.link_class_list&&(r={name:"class",type:"listbox",label:"Class",values:c(a.settings.link_class_list,function(b){b.value&&(b.textStyle=function(){return a.formatter.getCssText({inline:"a",classes:[b.value]})})})}),a.settings.link_title!==!1&&(s={name:"title",type:"textbox",label:"Title",value:u.title}),l=a.windowManager.open({title:"Insert link",data:u,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:g,onkeyup:f},n,s,e(u.href),o,p,q,r],onSubmit:function(b){function c(b,c){var d=a.selection.getRng();tinymce.util.Delay.setEditorTimeout(a,function(){a.windowManager.confirm(b,function(b){a.selection.setRng(d),c(b)})})}function d(){var b={href:e,target:u.target?u.target:null,rel:u.rel?u.rel:null,"class":u["class"]?u["class"]:null,title:u.title?u.title:null};j?(a.focus(),m&&u.text!=k&&("innerText"in j?j.innerText=u.text:j.textContent=u.text),w.setAttribs(j,b),v.select(j),a.undoManager.add()):m?a.insertContent(w.createHTML("a",b,w.encode(u.text))):a.execCommand("mceInsertLink",!1,b)}var e;return u=tinymce.extend(u,b.data),(e=u.href)?e.indexOf("@")>0&&-1==e.indexOf("//")&&-1==e.indexOf("mailto:")?void c("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(a){a&&(e="mailto:"+e),d()}):a.settings.link_assume_external_targets&&!/^\w+:/i.test(e)||!a.settings.link_assume_external_targets&&/^\s*www[\.|\d\.]/i.test(e)?void c("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(a){a&&(e="http://"+e),d()}):void d():void a.execCommand("unlink")}})}a.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Meta+K",onclick:b(d),stateSelector:"a[href]"}),a.addButton("unlink",{icon:"unlink",tooltip:"Remove link",cmd:"unlink",stateSelector:"a[href]"}),a.addShortcut("Meta+K","",b(d)),a.addCommand("mceLink",b(d)),this.showDialog=d,a.addMenuItem("link",{icon:"link",text:"Insert/edit link",shortcut:"Meta+K",onclick:b(d),stateSelector:"a[href]",context:"insert",prependToContext:!0})}); -------------------------------------------------------------------------------- /files-server/models/snippets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let mongoose = require('mongoose'); 3 | let setup = require('../../setup.js'); 4 | let db = mongoose.createConnection(setup.mongodbHost + setup.mongodbPort + setup.mongodbFilesName); 5 | 6 | let Promise = require('bluebird'); 7 | 8 | let snippetSchema = mongoose.Schema({ 9 | _createdAt: { type: Date, default: new Date() }, 10 | _updatedAt: { type: Date, default: new Date() }, 11 | createdBy: { type: String, required: true }, 12 | username: { type: String, required: true }, 13 | data: { type: String, default: '' }, 14 | name: { type: String, required: true }, 15 | filePath: { type: String, required: true }, 16 | tags: { type: [String], default: [] }, 17 | annotation: { type: String }, 18 | description: { type: String }, 19 | public: { type: Boolean, default: true }, 20 | favorite: { type: Boolean, default: false }, 21 | shortcut: { type: String }, 22 | language: { type: String, default: 'javascript' } 23 | }); 24 | 25 | let snippetStatics = { 26 | makeSnippet(snippetObj, callback) { 27 | this.findOne({filePath: snippetObj.filePath}) 28 | .then(result => { 29 | if (!result) { 30 | this.create(snippetObj) 31 | .then((result) => callback(null, result)) 32 | .catch(callback); 33 | } else { 34 | callback(null, result); 35 | } 36 | }); 37 | }, 38 | 39 | getSnippet(_id, callback) { 40 | this.findOne({_id: mongoose.Types.ObjectId(_id)}) 41 | .then(snippetObj => callback(null, snippetObj)) 42 | .catch(callback); 43 | }, 44 | 45 | updateSnippet(_id, newProps, callback) { 46 | newProps._updatedAt = new Date(); 47 | this.update({ _id: mongoose.Types.ObjectId(_id) }, newProps, { multi: false }, callback); 48 | }, 49 | 50 | removeSnippet(_id, callback) { 51 | this.findOne({ _id: mongoose.Types.ObjectId(_id) }).remove(callback); 52 | }, 53 | 54 | getSnippetsByUser(email, callback) { 55 | this.find({ createdBy: email }) 56 | .then((foundSnippets) => { 57 | if (Array.isArray(foundSnippets) && foundSnippets.length !== 0) { 58 | callback(null, foundSnippets); 59 | } else { 60 | callback(new Error('no snippets found'), null); 61 | } 62 | }) 63 | .catch(callback); 64 | }, 65 | 66 | updateSnippetsByUser(email, newProps, callback) { 67 | newProps._updatedAt = new Date(); 68 | this.update({ createdBy: email }, newProps, {multi: true}, callback); 69 | }, 70 | 71 | getSnippetsByFolder(email, folder, callback) { 72 | this.find({ createdBy: email, filePath: new RegExp(folder + '.*', 'igm') }) 73 | .then((foundSnippets) => { 74 | if (Array.isArray(foundSnippets) && foundSnippets.length !== 0) { 75 | callback(null, foundSnippets); 76 | } else { 77 | callback(new Error('password invalid'), null); 78 | } 79 | }).catch(callback); 80 | }, 81 | 82 | makeSubFolder(email, username, filepath, callback) { 83 | filepath = (filepath.charAt(0) !== '/') ? '/' + filepath : filepath; 84 | this.makeSnippet({ name: '.config', data: '..', createdBy: email, username: username, filePath: filepath + '/.config' }, callback); 85 | }, 86 | 87 | makeRootFolder(email, username, callback) { 88 | this.makeSnippet({ name: '.config', data: '..', createdBy: email, username: username, filePath: '/' + email + '/.config' }, callback); 89 | }, 90 | 91 | removeFolder(email, folder, callback) { 92 | this.getSnippetsByFolder(email, folder, (err, snippets) => { 93 | if (err) { 94 | callback(err); 95 | } else { 96 | let removeSnippetAsync = Promise.promisify(this.removeSnippet.bind(this)); 97 | let promiseArray = snippets.map(snip => removeSnippetAsync(snip._id)); 98 | Promise.all(promiseArray) 99 | .then(response => { 100 | callback(null, response); 101 | }) 102 | .catch(callback); 103 | } 104 | }); 105 | }, 106 | 107 | getPublic(page, callback) { 108 | page = page || 0; 109 | this.find({ public: 1, name: { $ne: '.config' } },{}, {limit:24 , skip: 24 * page}) 110 | .then((foundSnippets) => { 111 | callback(null, foundSnippets.sort({ _createdAt: -1 })); 112 | }) 113 | .catch(callback); 114 | } 115 | }; 116 | 117 | let snippetStaticsAsync = Promise.promisifyAll(snippetStatics); 118 | 119 | Object.assign(snippetSchema.statics, snippetStaticsAsync); 120 | let Snippet = db.model('Snippet', snippetSchema); 121 | 122 | module.exports = Snippet; 123 | -------------------------------------------------------------------------------- /client/app/controllers/main/editor/snippets/snippets.js: -------------------------------------------------------------------------------- 1 | import { getAllFoldersPaths } from '../../../../redux/fileTree.js'; 2 | 3 | class SnippetsCtrl { 4 | constructor($ngRedux, Snippets, Folders, Public, $state, focus) { 5 | $ngRedux.connect(this.mapStateToThis)(this); 6 | this.Public = Public; 7 | this.Folders = Folders; 8 | this.Snippets = Snippets; 9 | this.folderInput = false; 10 | this.folderModalShow = false; 11 | this.moveModalShow = false; 12 | this.folderModal = {}; 13 | this.moveModal = {}; 14 | this.$state = $state; 15 | this.focus = focus; 16 | } 17 | 18 | focusNameInput(filePath) { 19 | this.changeSelectedSnippet(filePath); 20 | this.focus('snippet-input-name'); 21 | } 22 | 23 | toggleFolderModal(folderObj) { 24 | this.folderModal = folderObj; 25 | this.folderModalShow = !this.folderModalShow; 26 | } 27 | 28 | toggleMoveModal(snippetObj) { 29 | this.paths = getAllFoldersPaths(this.snippetMap, this.snippetMap.__root.filePath); 30 | this.moveModal = snippetObj; 31 | this.moveModalShow = !this.moveModalShow; 32 | } 33 | 34 | addFolder() { 35 | let path = this.selectedFolder + '/' + this.subFolder.name; 36 | if (!this.snippetMap[path]) { 37 | this.Folders.addFolder({ path: path }); 38 | this.subFolder.name = ''; 39 | } else { 40 | Materialize.toast('Can not use duplicate name', 3000, 'rounded'); 41 | } 42 | } 43 | removeFolder(folderPath) { 44 | this.Folders.removeFolder(folderPath); 45 | } 46 | changeActiveTab(folderPath) { 47 | this.Folders.selectFolder(folderPath); 48 | } 49 | toggleFolderNameInput() { 50 | this.folderInput = !this.folderInput; 51 | } 52 | copySnippet(snippet) { 53 | this.Snippets.getSnippet({ snippetId: snippet._id }); 54 | } 55 | toggleFavorite(snippet) { 56 | let _id = snippet.value ? snippet.value._id : snippet._id; 57 | let favorite = snippet.value ? !snippet.value.favorite : !snippet.favorite; 58 | this.Snippets.updateSnippet({ _id, favorite }, snippet.filePath); 59 | } 60 | changeSelectedSnippet(snippetPath) { 61 | if (this.selectedPublicSnippet) { 62 | if (this.selectedPublicSnippet !== snippetPath) { 63 | this.Public.setSelectedPublicSnippet(snippetPath); 64 | } 65 | } else { 66 | if (this.selectedSnippet !== snippetPath) { 67 | this.Snippets.changeSelectedSnippet(snippetPath); 68 | } 69 | } 70 | } 71 | deselectSnippet() { 72 | this.Public.removeSelectedPublicSnippet(); 73 | this.Snippets.deselectSnippet(); 74 | this.focus('snippet-input-name'); 75 | } 76 | removeSnippet(snippetObj) { 77 | this.Snippets.removeSnippet(snippetObj); 78 | } 79 | 80 | closeSideNav() { 81 | this.$state.go('main.editor'); 82 | } 83 | 84 | showToolbar(id) { 85 | $('#' + id).toggle(400); 86 | $('.tooltipped').tooltip({ delay: 50 }); 87 | } 88 | 89 | mapStateToThis(state) { 90 | let { selectedFolder, snippetMap, selectedSnippet, selectedPublicSnippet, publicList } = state; 91 | let visibleFolders = [], 92 | visibleSnippets = []; 93 | let selectedFolderObj = snippetMap[selectedFolder]; 94 | if (selectedPublicSnippet) { 95 | visibleSnippets = publicList; 96 | } else if (selectedFolderObj) { 97 | selectedFolderObj.children.forEach(childKey => { 98 | let child = snippetMap[childKey]; 99 | if (typeof child.value === 'string') { 100 | visibleFolders.push(child); 101 | } else if (child.value.name !== '.config') { 102 | visibleSnippets.push(child); 103 | } 104 | }); 105 | } 106 | let favoritesArr = []; 107 | Object.keys(snippetMap).forEach(key => { 108 | let snippetVal = snippetMap[key].value; 109 | if (typeof snippetVal === 'object') { 110 | if (snippetVal.name !== '.config' && snippetVal.name !== '/.config') { 111 | favoritesArr.push(snippetVal); 112 | } 113 | } 114 | }); 115 | return { 116 | selectedPublicSnippet, 117 | visibleSnippets, 118 | visibleFolders, 119 | selectedFolderObj, 120 | selectedFolder, 121 | selectedSnippet, 122 | snippetMap, 123 | favoritesArr 124 | }; 125 | } 126 | } 127 | 128 | const snippets = (url) => { 129 | return { 130 | url: url, 131 | controllerAs: 'snippets', 132 | controller: SnippetsCtrl, 133 | template: require(`.${url}.html`), 134 | access: { restricted: true } 135 | }; 136 | }; 137 | 138 | export default snippets; 139 | -------------------------------------------------------------------------------- /client/app/redux/fileTree.js: -------------------------------------------------------------------------------- 1 | export const getNode = (tree, filePath) => { 2 | return tree[filePath] ? Object.assign({}, tree[filePath]) : null; 3 | }; 4 | export let getParent = (tree, filePath) => { 5 | return tree[filePath] && tree[filePath].parent ? getNode(tree,tree[filePath].parent) : null; 6 | }; 7 | export let getChildren = (tree, filePath, showConfigs) => { 8 | let children = tree[filePath].children.map(childPath => getNode(tree, childPath)); 9 | if(!showConfigs) { 10 | return children.filter(child => child.value.name !== '.config'); 11 | } else { 12 | return children; 13 | } 14 | }; 15 | export let getAllParents = (tree, filePath) => { 16 | let results = [], parent = getParent(tree,filePath); 17 | while (parent) { 18 | results = [...results, parent]; 19 | filePath = parent.filePath; 20 | parent = getParent(tree,filePath); 21 | } 22 | return results; 23 | }; 24 | export let getAllChildren = (tree, filePath, showConfigs) => { 25 | let children = getChildren(tree, filePath, showConfigs); 26 | if(children.length === 0) { 27 | return []; 28 | } else { 29 | return children.reduce((results, child) => { 30 | let childPath = child.filePath; 31 | let children = getChildren(tree, childPath, showConfigs); 32 | return results.concat(child, children); 33 | }, []); 34 | } 35 | }; 36 | export const insertNode = (origTree, filePath, node) => { 37 | let tree = Object.assign({}, origTree, {__root: origTree.__root}); 38 | let folders = filePath.split('/').filter(a => a).concat(node); 39 | let allOK = folders.reduce((prevPath, currItem) => { 40 | if(typeof currItem === 'object') { 41 | tree[prevPath].value = currItem; 42 | return true; 43 | } else { 44 | let currPath = prevPath + '/' + currItem; 45 | let parentObj = tree[prevPath], currObj = tree[currPath]; 46 | if(prevPath && !parentObj) { 47 | tree[prevPath] = {filePath: prevPath, children: []}; 48 | } 49 | if(parentObj && parentObj.children.indexOf(currPath) === -1) { 50 | tree[prevPath].children.push(currPath); 51 | } 52 | tree[currPath] = currObj ? currObj : {children: []}; 53 | tree[currPath].parent = prevPath; 54 | tree[currPath].value = currItem; 55 | tree[currPath].filePath = currPath; 56 | if(tree.__root === undefined) { 57 | Object.defineProperty(tree, '__root', { 58 | value: tree[currPath] 59 | }); 60 | } 61 | return currPath; 62 | } 63 | }, ''); 64 | return allOK ? tree : new Error('Error parsing filepath'); 65 | }; 66 | export const deleteNode = (origTree, filePath) => { 67 | let tree = Object.assign({}, origTree, {__root: origTree.__root}); 68 | let childrenPaths = getAllChildren(tree, filePath, true).map(child => child.filePath); 69 | let parent = getParent(tree, filePath); 70 | childrenPaths.forEach(childPath => { 71 | delete tree[childPath]; 72 | }); 73 | parent.children.splice(parent.children.indexOf(filePath), 1); 74 | // parent.children = parent.children.filter(childPath => childPath !== filePath); 75 | delete tree[filePath]; 76 | return tree; 77 | }; 78 | export const updateNode = (origTree, origFilePath, updatedFilePath, updatedNode) => { 79 | let tree = Object.assign({}, origTree); 80 | let nodeToUpdate = Object.assign({}, tree[origFilePath], updatedNode); 81 | tree = deleteNode(tree, origFilePath); 82 | return insertNode(tree, updatedFilePath, nodeToUpdate.value); 83 | }; 84 | export const convertToTree = (snippetObj) => { 85 | let userTreeMap = Object.keys(snippetObj).reduce( (prevTree, key) => { 86 | return insertNode(prevTree, key, snippetObj[key]); 87 | }, {}); 88 | return userTreeMap; 89 | }; 90 | export let getAllFoldersPaths = (tree, rootPath) => { 91 | let results = []; 92 | let traverse = (nodePath) => { 93 | if(typeof tree[nodePath].value === 'string') { 94 | results.push(tree[nodePath].filePath); 95 | tree[nodePath].children.forEach(childPath => { 96 | traverse(childPath); 97 | }); 98 | } 99 | }; 100 | traverse(rootPath); 101 | return results; 102 | }; 103 | export const createBoundMethods = (...args) => { 104 | return { 105 | node: getNode.bind(null,...args), 106 | parent: getParent.bind(null,...args), 107 | children: getChildren.bind(null,...args), 108 | parents: getAllParents.bind(null,...args), 109 | allChildren: getAllChildren.bind(null,...args) 110 | }; 111 | 112 | }; 113 | -------------------------------------------------------------------------------- /client/assets/codemirror-themes/mdn-like.css: -------------------------------------------------------------------------------- 1 | /* 2 | MDN-LIKE Theme - Mozilla 3 | Ported to CodeMirror by Peter Kroon 4 | Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues 5 | GitHub: @peterkroon 6 | 7 | The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation 8 | 9 | */ 10 | .cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; } 11 | .cm-s-mdn-like div.CodeMirror-selected { background: #cfc; } 12 | .cm-s-mdn-like .CodeMirror-line::selection, .cm-s-mdn-like .CodeMirror-line > span::selection, .cm-s-mdn-like .CodeMirror-line > span > span::selection { background: #cfc; } 13 | .cm-s-mdn-like .CodeMirror-line::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span > span::-moz-selection { background: #cfc; } 14 | 15 | .cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; } 16 | .cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; padding-left: 8px; } 17 | .cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; } 18 | 19 | .cm-s-mdn-like .cm-keyword { color: #6262FF; } 20 | .cm-s-mdn-like .cm-atom { color: #F90; } 21 | .cm-s-mdn-like .cm-number { color: #ca7841; } 22 | .cm-s-mdn-like .cm-def { color: #8DA6CE; } 23 | .cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; } 24 | .cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def { color: #07a; } 25 | 26 | .cm-s-mdn-like .cm-variable { color: #07a; } 27 | .cm-s-mdn-like .cm-property { color: #905; } 28 | .cm-s-mdn-like .cm-qualifier { color: #690; } 29 | 30 | .cm-s-mdn-like .cm-operator { color: #cda869; } 31 | .cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; } 32 | .cm-s-mdn-like .cm-string { color:#07a; font-style:italic; } 33 | .cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/ 34 | .cm-s-mdn-like .cm-meta { color: #000; } /*?*/ 35 | .cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/ 36 | .cm-s-mdn-like .cm-tag { color: #997643; } 37 | .cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/ 38 | .cm-s-mdn-like .cm-header { color: #FF6400; } 39 | .cm-s-mdn-like .cm-hr { color: #AEAEAE; } 40 | .cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } 41 | .cm-s-mdn-like .cm-error { border-bottom: 1px solid red; } 42 | 43 | div.cm-s-mdn-like .CodeMirror-activeline-background { background: #efefff; } 44 | div.cm-s-mdn-like span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; } 45 | 46 | .cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); } 47 | -------------------------------------------------------------------------------- /client/app/controllers/main/download/download.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 8 |
Easily integrate your code snippets and templates with sublime's snippet templates
9 |
10 |
11 |
12 |
13 |
14 | Client Secret:{{downloadCtrl.activeUser.sublimeSecret}} 15 | 22 | assignment 23 | 24 | 25 |
26 |
27 | 30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |

Sublime Plugin Guide

38 |
39 |
Automatic Installation (supported only on OS X)
40 |
    41 |
  1. Download the compressed file below and unzip it in a local directory
  2. 42 |
  3. Run the setup file by clicking on "setup.command" If this doesn't run in a terminal emulator, navigate to the folder in your terminal and run "./setup.command". (Modify the executable permissions by typing "chmod +x ./setup.command" in your terminal if this doesn't work)
  4. 43 |
  5. A prompt will appear asking for your valid Nevercode client secret. Copy it above using the clipboard button, paste it into the setup script, and allow the script to run.
  6. 44 |
  7. Once setup is complete, your Sublime Editor should now contain a "Nevercode" menu in Preferences with two options, "Sync with Nevercode" and "Input Client Secret"
  8. 45 |
46 |
47 |
Manual Installation
48 |
    49 |
  1. Copy the compressed zip file above to a local directory and decompress the file
  2. 50 |
  3. Inside the uncompressed archive, there should be a file called "setup.sh" and a folder called "Nevercode". Copy the Nevercode folder into your Sublime's "Packages" folder.
  4. 51 |
  5. Re-open Sublime and there should now be a "Nevercode Menu" with two options, "Sync with Nevercode" and "Input Client Secret". Click on "Input Client Secret" and an input box should appear at the bottom of your test editor
  6. 52 |
  7. Copy the client secret on your account to your clipboard, pase it into the input field in Sublime, and then hit enter
  8. 53 |
  9. A dialog box should appear indicating your client secret is valid. Once you see this, installation has completed.
  10. 54 |
55 |
56 |
Syncing your local Snippets with Sublime
57 |
    58 |
  1. Inside the "Nevercode" menu which is nested inside of "Preferences", click "Sync with Nevercode"
  2. 59 |
  3. A new window should appear in sublime which indicates the progress of the plugin. Once it is completed, a dialog box should appear indicating the new snippets which have been downloaded locally and integrated with Sublime.
  4. 60 |
  5. All shortcuts which are set in Nevercode are first prefixed with "NC_" are set as triggers for pasting the snippets into your code. So, for example, if you set a shortcut for a particular snippet to be "NchooseK", you could input this snippet into your text by typing "NC_NchooseK" then hitting the Tab button
  6. 61 |
62 |
63 |
Uploading Snippet to Nevercode
64 |
    65 |
  1. If you compose a snippet in Sublime and wish to upload it to your Nevercode account, highlight the code, right-click, and then click "Upload Selection to Nevercode". 66 |
  2. The input box should appear at the bottom of the page asking you to input a name for the file. Enter a name and then hit Enter.
  3. 67 |
  4. Another input box should appear at the botom of the page asking for a shortcut. This will be the shortcut that you use in order to paste the code into your current open file. Enter a unique shortcut and then hit Enter.
  5. 68 |
  6. A dialogue box should appear indicating the result of the upload. If sucessful, be sure to re-sync in order to store snippet locally. 69 |
70 |
71 |
Resetting your Client Secret
72 |
    73 |
  1. In the event that your client secret has been compromised, generate a new client secret by clicking the corresponding button on the Sublime plugin link page.
  2. 74 |
  3. A new client secret should then appear. Copy the client secret to your clipboard and then open Sublime.
  4. 75 |
  5. Open the "Nevercode" submenu nested inside of "Preferences" and click on "Input Client Secret"
  6. 76 |
  7. An input box should appear at the bottom of the page with an old client secret. Erase it and paste your new client secret, then hit enter
  8. 77 |
  9. A dialogue box should appear once the client secret is confirmed as valid by the server. Click OK to finish setting up your new secret
  10. 78 |
79 |
80 | 81 | -------------------------------------------------------------------------------- /client/js/tinymce/plugins/visualblocks/css/visualblocks.css: -------------------------------------------------------------------------------- 1 | .mce-visualblocks p { 2 | padding-top: 10px; 3 | border: 1px dashed #BBB; 4 | margin-left: 3px; 5 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); 6 | } 7 | 8 | .mce-visualblocks h1 { 9 | padding-top: 10px; 10 | border: 1px dashed #BBB; 11 | margin-left: 3px; 12 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); 13 | } 14 | 15 | .mce-visualblocks h2 { 16 | padding-top: 10px; 17 | border: 1px dashed #BBB; 18 | margin-left: 3px; 19 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); 20 | } 21 | 22 | .mce-visualblocks h3 { 23 | padding-top: 10px; 24 | border: 1px dashed #BBB; 25 | margin-left: 3px; 26 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); 27 | } 28 | 29 | .mce-visualblocks h4 { 30 | padding-top: 10px; 31 | border: 1px dashed #BBB; 32 | margin-left: 3px; 33 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); 34 | } 35 | 36 | .mce-visualblocks h5 { 37 | padding-top: 10px; 38 | border: 1px dashed #BBB; 39 | margin-left: 3px; 40 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); 41 | } 42 | 43 | .mce-visualblocks h6 { 44 | padding-top: 10px; 45 | border: 1px dashed #BBB; 46 | margin-left: 3px; 47 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); 48 | } 49 | 50 | .mce-visualblocks div:not([data-mce-bogus]) { 51 | padding-top: 10px; 52 | border: 1px dashed #BBB; 53 | margin-left: 3px; 54 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); 55 | } 56 | 57 | .mce-visualblocks section { 58 | padding-top: 10px; 59 | border: 1px dashed #BBB; 60 | margin: 0 0 1em 3px; 61 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); 62 | } 63 | 64 | .mce-visualblocks article { 65 | padding-top: 10px; 66 | border: 1px dashed #BBB; 67 | margin: 0 0 1em 3px; 68 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); 69 | } 70 | 71 | .mce-visualblocks blockquote { 72 | padding-top: 10px; 73 | border: 1px dashed #BBB; 74 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); 75 | } 76 | 77 | .mce-visualblocks address { 78 | padding-top: 10px; 79 | border: 1px dashed #BBB; 80 | margin: 0 0 1em 3px; 81 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); 82 | } 83 | 84 | .mce-visualblocks pre { 85 | padding-top: 10px; 86 | border: 1px dashed #BBB; 87 | margin-left: 3px; 88 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); 89 | } 90 | 91 | .mce-visualblocks figure { 92 | padding-top: 10px; 93 | border: 1px dashed #BBB; 94 | margin: 0 0 1em 3px; 95 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); 96 | } 97 | 98 | .mce-visualblocks hgroup { 99 | padding-top: 10px; 100 | border: 1px dashed #BBB; 101 | margin: 0 0 1em 3px; 102 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); 103 | } 104 | 105 | .mce-visualblocks aside { 106 | padding-top: 10px; 107 | border: 1px dashed #BBB; 108 | margin: 0 0 1em 3px; 109 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); 110 | } 111 | 112 | .mce-visualblocks figcaption { 113 | border: 1px dashed #BBB; 114 | } 115 | 116 | .mce-visualblocks ul { 117 | padding-top: 10px; 118 | border: 1px dashed #BBB; 119 | margin: 0 0 1em 3px; 120 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==) 121 | } 122 | 123 | .mce-visualblocks ol { 124 | padding-top: 10px; 125 | border: 1px dashed #BBB; 126 | margin: 0 0 1em 3px; 127 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); 128 | } 129 | 130 | .mce-visualblocks dl { 131 | padding-top: 10px; 132 | border: 1px dashed #BBB; 133 | margin: 0 0 1em 3px; 134 | background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); 135 | } 136 | --------------------------------------------------------------------------------