├── templates
├── button.html
├── content.html
├── successGistDialog.html
├── gist.html
├── panel.html
└── newGistDialog.html
├── readmefiles
├── panel.jpg
└── newgist.jpg
├── .gitmodules
├── .gitignore
├── strings.js
├── package.json
├── nls
├── strings.js
├── root
│ └── strings.js
└── de
│ └── strings.js
├── .jshintrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── styles
├── gist-manager.css
├── images
│ └── icon_gists.svg
└── gist-manager.less
└── main.js
/templates/button.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/readmefiles/panel.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FezVrasta/gist-manager/HEAD/readmefiles/panel.jpg
--------------------------------------------------------------------------------
/readmefiles/newgist.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FezVrasta/gist-manager/HEAD/readmefiles/newgist.jpg
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "thirdparty/async"]
2 | path = thirdparty/async
3 | url = https://github.com/caolan/async.git
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # https://git-scm.com/docs/gitignore
2 | # https://help.github.com/articles/ignoring-files
3 | # Example .gitignore files: https://github.com/github/gitignore
--------------------------------------------------------------------------------
/templates/content.html:
--------------------------------------------------------------------------------
1 |
6 |
7 | {{#gists}}
8 |
9 | {{/gists}}
10 |
11 |
--------------------------------------------------------------------------------
/strings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file provides the interface to user visible strings in Brackets. Code that needs
3 | * to display strings should should load this module by calling var Strings = require("strings").
4 | * The i18n plugin will dynamically load the strings for the right locale and populate
5 | * the exports variable. See nls/root/strings.js for the master file of English strings.
6 | */
7 | define(function (require, exports, module) {
8 | module.exports = require("i18n!nls/strings");
9 | });
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fezvrasta.gist-manager",
3 | "title": "Gist Manager",
4 | "description": "Create and view Github Gists within Brackets. (View > Show Gists Manager)",
5 | "keywords": ["gist", "GitHub", "snippets"],
6 | "homepage": "https://github.com/FezVrasta/gist-manager",
7 | "version": "0.1.1",
8 | "author": "Fez Vrasta (http://www.mywebexpression.com)",
9 | "license": "MIT",
10 | "engines": {
11 | "brackets": ">=0.24.0"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/templates/successGistDialog.html:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/nls/strings.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @see: https://github.com/adobe/brackets/tree/master/src/extensions/samples/LocalizationExample
3 | */
4 | define(function (require, exports, module) {
5 | // Code that needs to display user strings should call require("strings") to load
6 | // strings.js. This file will dynamically load strings.js for the specified by bracketes.locale.
7 | //
8 | // Translations for other locales should be placed in nls/>/strings.js
9 | // Localization is provided via the i18n plugin.
10 | // All other bundles for languages need to add a prefix to the exports below so i18n can find them.
11 | module.exports = {
12 | root: true,
13 | "de": true
14 | };
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/templates/gist.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
{{#public}}{{PUBLIC}}{{/public}}{{^public}}{{SECRET}}{{/public}} {{description}}
8 |
9 |
10 | {{#files}}
11 |
12 |
13 | {{filename}}
14 |
15 |
18 |
19 | {{/files}}
20 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "bitwise": true,
3 | "camelcase": true,
4 | "curly": true,
5 | "eqeqeq": false,
6 | "es3": false,
7 | "forin": true,
8 | "freeze": true,
9 | "immed": true,
10 | "indent": 4,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "noempty": true,
15 | "nonbsp": true,
16 | "nonew": true,
17 | "plusplus": false,
18 | "quotmark": "double",
19 | "undef": true,
20 | "unused": true,
21 | "strict": false,
22 | "trailing": true,
23 | "maxparams": 5,
24 | "maxdepth": 5,
25 | "maxstatements": 50,
26 | "maxlen": 150,
27 |
28 | "eqnull": true,
29 |
30 | "browser": false,
31 | "devel": false,
32 | "node": true,
33 |
34 | "white": true,
35 |
36 | "globals": {
37 | "$": true,
38 | "document": true,
39 | "brackets": true,
40 | "define": true,
41 | "Mustache": true,
42 | "window": true
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.1.1
2 | * Added Gist Manager button into main toolbar (you can disbled it from preferences file) by [malas34](https://github.com/malas34)
3 |
4 | ## 0.1.0
5 | * First stable release, fix of various critical bugs.
6 |
7 | ## 0.0.8
8 | * Now is possible to delete gists.
9 |
10 | ## 0.0.7
11 | * Added support for [GitHub authorization tokens](https://github.com/settings/applications).
12 | * Auth tokens are saved locally and can be loaded writing the owner's username in the username field.
13 |
14 | ## 0.0.6
15 | * Added option in menu to fastly create a Gist with the content of the current document.
16 | * Gists are now listed showing the first 15 chars of the description (if provided).
17 | * Added tool to filter gists by keywords.
18 |
19 | ## 0.0.5
20 | * Added Gist creation support (anonymous, public, secret)
21 |
22 | ## 0.0.4
23 | * Added support for localization.
24 | * Now is possible load public gists, user's public gists and user's secret gists.
25 | * Added buttons to download gist or open in browser
26 |
--------------------------------------------------------------------------------
/templates/panel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 FezVrasta
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/nls/root/strings.js:
--------------------------------------------------------------------------------
1 | /*jshint maxlen:false */
2 |
3 | define({
4 | SHOW_GIST_MANAGER: "Show Gist Manager",
5 | LOAD_GISTS: "Load Gists",
6 | NEW_GIST: "New Gist",
7 | GIST_FROM_CURRENT_FILE: "New Gist from current file",
8 | USERNAME: "username",
9 | PASSWORD: "password/token",
10 | FILTER: "Filter gists by keywords...",
11 | DOWNLOAD_GIST: "Download Gist",
12 | OPEN_IN_BROWSER: "Open in browser",
13 | PUBLIC: "Public",
14 | SECRET: "Secret",
15 | CREATE_NEW_GIST: "Create new Gist",
16 | ADD_FILE: "Add file",
17 | CANCEL: "Cancel",
18 | CREATE_PUBLIC_GIST: "Create public Gist",
19 | CREATE_SECRET_GIST: "Create secret Gist",
20 | GIST_DESCRIPTION_HERE: "Write your Gist description here...",
21 | FILENAME_HERE: "Write here an optional file name...",
22 | GIST_CONTENT_HERE: "Write your Gist content here...",
23 | CREATION_ERROR: "Failed to create Gist",
24 | CREATION_SUCCESS: "Gist successfully created",
25 | CLOSE: "Close",
26 | LOADING_ERROR: "Loading error",
27 | DELETE_GIST: "Delete Gist",
28 | DELETING_ERROR: "Error during Gist deletion!"
29 |
30 | });
31 |
--------------------------------------------------------------------------------
/nls/de/strings.js:
--------------------------------------------------------------------------------
1 | /*jshint maxlen:false */
2 |
3 | define({
4 | SHOW_GIST_MANAGER: "Gist Manager anzeigen",
5 | LOAD_GISTS: "Lade Gists",
6 | NEW_GIST: "Neues Gist",
7 | GIST_FROM_CURRENT_FILE: "Neues Gist aus aktueller Datei",
8 | USERNAME: "benutzername",
9 | PASSWORD: "passwort/token",
10 | FILTER: "Filtere Gists nach Keywords...",
11 | DOWNLOAD_GIST: "Downloade Gist",
12 | OPEN_IN_BROWSER: "Im Browser öffnen",
13 | PUBLIC: "Öffentlich",
14 | SECRET: "Geheim",
15 | CREATE_NEW_GIST: "Neues Gist erstellen",
16 | ADD_FILE: "Datei hinzufügen",
17 | CANCEL: "Abbrechen",
18 | CREATE_PUBLIC_GIST: "Öffentliches Gist erstellen",
19 | CREATE_SECRET_GIST: "Geheimes Gist erstellen",
20 | GIST_DESCRIPTION_HERE: "Beschreibung deines Gist",
21 | FILENAME_HERE: "Dateiname (optional)",
22 | GIST_CONTENT_HERE: "Inhalt deines Gist",
23 | CREATION_ERROR: "Erstellung des Gist fehlgeschlagen",
24 | CREATION_SUCCESS: "Gist erfolgreich erstellt",
25 | CLOSE: "Schließen",
26 | LOADING_ERROR: "Fehler beim Laden",
27 | DELETE_GIST: "Gist löschen",
28 | DELETING_ERROR: "Fehler beim Löschen deines Gist!"
29 |
30 | });
31 |
--------------------------------------------------------------------------------
/templates/newGistDialog.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
15 |
21 |
{{ADD_FILE}}
22 |
23 |
24 |
25 |
32 |
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Gist Manager
2 |
3 | Gist Manager is a [Brackets](https://github.com/adobe/brackets) and [Adobe Edge Code](http://html.adobe.com/edge/code/) extension which allows you to search, consult and create Gists from GitHub.
4 |
5 | It has lot of features and every help to improve them is very welcome.
6 |
7 | If you find a bug please [open an issue](https://github.com/FezVrasta/gist-manager/issues)!
8 |
9 | Do you like this project? Star it and [offer me some coffe](https://www.gittip.com/FezVrasta/)!
10 |
11 |
12 |
13 |
14 | ## Usage:
15 | To show Gist Manager click on **`View > Show Gist Manager`**, the panel will appear on bottom of Brackets.
16 | Writing an username of GitHub in the first field and clicking **Load Gists** will load the list of public Gists of the choosen user.
17 | You may specify the password to load even the secret Gists.
18 |
19 | To publish an anonymous Gist click on **New gist** and a dialog will guide you.
20 | If you have specified an username and password, clicking **New gist** will create a Gist in your account, and you'll be able to choose if make it public or secret.
21 |
22 | After you've published a new Gist a modal popup will appear letting you copy the Gist URL or open it in your browser.
23 |
24 | ## Supported features:
25 | - Create anonymous, public and secret Gists
26 | - Support for multi-file Gists
27 | - Creation of Gists starting from selected text
28 | - Load public Gists of a specific GitHub user.
29 | - Load public and secret Gists of a specific GitHub user (providing password).
30 | - Open Gist in browser
31 | - Delete Gist
32 | - Download Gist
33 | - Search Gist
34 | - Login with [application tokens](https://github.com/settings/applications).
35 | - Remember application tokens.
36 |
37 | ## To do:
38 | These are the features in the to do list of this extension:
39 | - Edit Gists
40 | - View and manage forks
41 |
42 |
43 | ## Screenshots:
44 | 
45 | 
46 |
--------------------------------------------------------------------------------
/styles/gist-manager.css:
--------------------------------------------------------------------------------
1 | #gist-manager-button{background:url(images/icon_gists.svg ) no-repeat center top transparent}#gist-manager-button.active{background-position:center bottom}#gist-manager .toolbar .title{margin-right:20px}#gist-manager .toolbar #filter-content{position:absolute;right:40px;top:5px}#gist-manager .toolbar .btn-group input{margin:0px;width:100px;border-right:0;padding-top:3px;border-radius:4px 0 0 4px}#gist-manager .toolbar .btn-group input:nth-child(2){border-radius:0}#gist-manager .gist-manager-content{overflow:hidden}#gist-manager .gist-manager-content .list{float:left;width:200px;background-color:#FFFFFF;height:100%;box-shadow:inset -1px 1px 0 #ddd;overflow-y:auto}#gist-manager .gist-manager-content .list .list-group{margin:0}#gist-manager .gist-manager-content .list .list-group .list-group-item{list-style:none}#gist-manager .gist-manager-content .list .list-group .list-group-item a{position:relative;display:block;padding:7px 15px;margin-bottom:-1px;border:1px solid #DDDDDD}#gist-manager .gist-manager-content .list .list-group .list-group-item a:hover{background-color:#F5F5F5;text-decoration:none}#gist-manager .gist-manager-content .list .list-group .list-group-item a.active{color:#FFFFFF;background-color:#428BCA;border-color:#428BCA}#gist-manager .gist-manager-content .viewer{margin-left:200px;padding:10px;overflow-y:scroll;height:100%;box-sizing:border-box}#gist-manager .gist-manager-content .viewer .gist{display:none}#gist-manager .gist-manager-content .viewer .gist .gist-overview{overflow:hidden;margin-bottom:8px}#gist-manager .gist-manager-content .viewer .gist .gist-overview summary{padding:0 10px 10px 10px}#gist-manager .gist-manager-content .viewer .gist .gist-overview summary .label{text-transform:capitalize;margin-right:10px;border:1px solid #d7d7d7;color:#d7d7d7;padding:3px 6px 2px;border-radius:3px;background:#F3F3F3}#gist-manager .gist-manager-content .viewer .gist .gist-overview summary .label.secret{border-width:0px;background-color:#f8eec7;color:#A1882B}#gist-manager .gist-manager-content .viewer .gist .gist-overview .btn-group{float:right}#gist-manager .gist-manager-content .viewer .gist .file{margin-bottom:15px;border:1px solid #DDDDDD;border-radius:3px}#gist-manager .gist-manager-content .viewer .gist .file .meta{padding:5px 10px;font-size:12px;text-align:left;color:#555;text-shadow:0 1px 0 #FFFFFF;border-bottom:1px solid #D8D8D8;background-color:#F7F7F7;border-top-left-radius:3px;border-top-right-radius:3px}#gist-manager .gist-manager-content .viewer .gist .file .blob pre{border-radius:0;border:0;margin:0}#gist-manager .gist-manager-content .viewer .gist .file .blob pre code{-webkit-user-select:initial;cursor:text}#gist-manager .gist-manager-content .viewer .gist .file:last-child{margin-bottom:0px}#gist-manager .gist-manager-content .viewer .gist .file:first-child{margin-bottom:15px !important}.new-gist-dialog .nav,.success-gist-dialog .nav{border-bottom:1px solid #c3c6c5;margin-bottom:5px}.new-gist-dialog .nav li,.success-gist-dialog .nav li{padding-bottom:1px}.new-gist-dialog .nav li a:hover,.success-gist-dialog .nav li a:hover{background-color:#ECECEC}.new-gist-dialog #prototype-file,.success-gist-dialog #prototype-file{display:none}.new-gist-dialog input,.success-gist-dialog input{width:100%;box-sizing:border-box;padding:15px 7px}.new-gist-dialog textarea,.success-gist-dialog textarea{box-sizing:border-box;width:100%;height:200px}
--------------------------------------------------------------------------------
/styles/images/icon_gists.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
23 |
25 |
26 |
27 |
29 |
31 |
32 |
36 |
40 |
41 |
42 |
44 |
46 |
47 |
49 |
50 |
51 |
53 |
55 |
56 |
58 |
59 |
--------------------------------------------------------------------------------
/styles/gist-manager.less:
--------------------------------------------------------------------------------
1 | // out: gist-manager.css, compress: true, strictMath: true
2 |
3 | // Variables
4 | @list-width: 200px;
5 |
6 | // Button
7 | #gist-manager-button{
8 | background: url( images/icon_gists.svg ) no-repeat center top transparent;
9 | &.active{
10 | background-position: center bottom;
11 | }
12 | }
13 |
14 | // Panel
15 | #gist-manager {
16 | .toolbar {
17 | .title {
18 | margin-right: 20px;
19 | }
20 | #filter-content {
21 | position: absolute;
22 | right: 40px;
23 | top: 5px;
24 | }
25 | .btn-group {
26 | input {
27 | margin: 0px;
28 | width: 100px;
29 | border-right: 0;
30 | padding-top: 3px;
31 | border-radius: 4px 0 0 4px;
32 | &:nth-child(2) {
33 | border-radius: 0;
34 | }
35 | }
36 | }
37 | }
38 | .gist-manager-content {
39 | overflow: hidden;
40 | .list {
41 | float: left;
42 | width: @list-width;
43 | background-color: #FFFFFF;
44 | height: 100%;
45 | box-shadow: inset -1px 1px 0px #DDDDDD;
46 | overflow-y: auto;
47 | .list-group {
48 | margin: 0;
49 | .list-group-item {
50 | list-style: none;
51 | a {
52 | position: relative;
53 | display: block;
54 | padding: 7px 15px;
55 | margin-bottom: -1px;
56 | border: 1px solid #DDDDDD;
57 | &:hover {
58 | background-color: #F5F5F5;
59 | text-decoration: none;
60 | }
61 | &.active {
62 | color: #FFFFFF;
63 | background-color: #428BCA;
64 | border-color: #428BCA;
65 | }
66 | }
67 | }
68 | }
69 | }
70 | .viewer {
71 | margin-left: @list-width;
72 | padding: 10px;
73 | overflow-y: scroll;
74 | height: 100%;
75 | box-sizing: border-box;
76 | .gist {
77 | display: none;
78 | .gist-overview {
79 | overflow: hidden;
80 | margin-bottom: 8px;
81 | summary {
82 | padding: 0 10px 10px 10px;
83 | .label {
84 | text-transform: capitalize;
85 | margin-right: 10px;
86 | border: 1px solid #d7d7d7;
87 | color: #d7d7d7;
88 | padding: 3px 6px 2px;
89 | border-radius: 3px;
90 | background: #F3F3F3;
91 | &.secret {
92 | border-width: 0px;
93 | background-color: #f8eec7;
94 | color: #A1882B;
95 | }
96 | }
97 | }
98 | .btn-group {
99 | float: right;
100 | }
101 | }
102 | .file {
103 | margin-bottom: 15px;
104 | border: 1px solid #DDDDDD;
105 | border-radius: 3px;
106 | .meta {
107 | padding: 5px 10px;
108 | font-size: 12px;
109 | text-align: left;
110 | color: #555;
111 | text-shadow: 0 1px 0 #FFFFFF;
112 | border-bottom: 1px solid #D8D8D8;
113 | background-color: #F7F7F7;
114 | border-top-left-radius: 3px;
115 | border-top-right-radius: 3px;
116 | }
117 | .blob pre{
118 | border-radius: 0;
119 | border: 0;
120 | margin: 0;
121 | code {
122 | -webkit-user-select: initial;
123 | cursor: text;
124 | }
125 | }
126 | &:last-child {
127 | margin-bottom: 0px;
128 | }
129 | &:first-child {
130 | margin-bottom: 15px !important;
131 | }
132 | }
133 | }
134 | }
135 | }
136 | }
137 |
138 | // Dialog
139 | .new-gist-dialog, .success-gist-dialog {
140 |
141 | .nav {
142 | border-bottom: 1px solid #c3c6c5;
143 | margin-bottom: 5px;
144 | li {
145 | padding-bottom: 1px;
146 | a:hover {
147 | background-color: #ECECEC;
148 | }
149 | }
150 | }
151 |
152 | #prototype-file {
153 | display: none;
154 | }
155 |
156 | input {
157 | width: 100%;
158 | box-sizing: border-box;
159 | padding: 15px 7px;
160 | }
161 |
162 | textarea {
163 | box-sizing: border-box;
164 | width: 100%;
165 | height: 200px;
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | /*global define, brackets, $, Mustache, btoa */
2 |
3 | define(function (require, exports, module) {
4 | "use strict";
5 |
6 | var panel = require("text!templates/panel.html"),
7 | content = require("text!templates/content.html"),
8 | gist = require("text!templates/gist.html"),
9 | button = require("text!templates/button.html"),
10 | newGistDialog = require("text!templates/newGistDialog.html"),
11 | successGistDialog = require("text!templates/successGistDialog.html");
12 |
13 | var CommandManager = brackets.getModule("command/CommandManager"),
14 | DocumentManager = brackets.getModule("document/DocumentManager"),
15 | PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
16 | Dialogs = brackets.getModule("widgets/Dialogs"),
17 | EditorManager = brackets.getModule("editor/EditorManager"),
18 | ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
19 | Menus = brackets.getModule("command/Menus"),
20 | PanelManager = brackets.getModule("view/PanelManager");
21 |
22 | var Strings = require("strings");
23 |
24 | var $panel = $(),
25 | $content = $(),
26 | $button = $(),
27 | gists = null;
28 |
29 | var PREFIX = "gist-manager",
30 | TOGGLE_PANEL = PREFIX + ".run",
31 | GIST_FROM_CURRENT_FILE = PREFIX + ".fromfile",
32 | GM_PANEL = PREFIX + ".panel",
33 | NEW_GIST_MENU = PREFIX + ".menu";
34 |
35 |
36 | // Load preferences var
37 | var prefs = PreferencesManager.getExtensionPrefs(PREFIX);
38 |
39 | var auths = prefs.get("auths") || false;
40 | if (!auths) {
41 | auths = {};
42 | prefs.set("auths", auths);
43 | prefs.save();
44 | }
45 |
46 | // If showButton preference is not defined, set it to true
47 | if (prefs.get("showButton") === undefined) {
48 | prefs.set("showButton", true);
49 | prefs.save();
50 | }
51 |
52 | // Make :contains case insensitive (:containsIN)
53 | $.extend($.expr[":"], {
54 | "containsIN": function(elem, i, match) {
55 | return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
56 | }
57 | });
58 |
59 | // Show or hide Gist Manager panel when called
60 | function _handlePanelToggle() {
61 |
62 | if ($panel.is(":visible")) {
63 | $panel.hide();
64 | $button.removeClass("active");
65 | CommandManager.get(TOGGLE_PANEL).setChecked(false);
66 | EditorManager.focusEditor();
67 | } else {
68 | $panel.show();
69 | $button.addClass("active");
70 | CommandManager.get(TOGGLE_PANEL).setChecked(true);
71 | }
72 | EditorManager.resizeEditor();
73 | }
74 |
75 |
76 | // Render a given Gist inside the Gist Manager panel
77 | function renderGist(gistData) {
78 |
79 | // If the gist we are trying to render is already loded
80 | // don't load it again but just show the cached version
81 | // if is not cached then load it from Gist API
82 | if (!$panel.find("#" + gistData.id).data("loaded")) {
83 |
84 | // Load Gist data and prepare it for Mustache
85 | $.getJSON(gistData.url, function(gistData) {
86 |
87 | // Convert .files from object to array (needed because Mustache is stupid I guess, or maybe I'm)
88 | gistData.files = $.map(gistData.files, function(value) {
89 | return [value];
90 | });
91 |
92 | // Render Gist using Mustache
93 | var vars = gistData;
94 | $.extend(vars, Strings);
95 | var $gist = $(Mustache.render(gist, vars));
96 |
97 | // Inject the rendered Gist in the Gist Manager panel
98 | $panel.find("#" + gistData.id).html($gist).data("loaded", true);
99 | });
100 | }
101 |
102 | // Move things around to show the selected Gist
103 | $panel
104 | .find(".gist").hide().end()
105 | .find("a").removeClass("active").end()
106 | .find("a[href=#" + gistData.id + "]").addClass("active").end()
107 | .find("#" + gistData.id).show();
108 | }
109 |
110 | function getAuth(username, password, action) {
111 |
112 | // These will be used in our Ajax call
113 | var url,
114 | headers;
115 |
116 | // Set headers and API URL depending if we are trying to get public gists
117 | // user's public gists or user's public & secret gists
118 | if (username.length && password.length && password.length !== 40) {
119 | // Basic login with username and password
120 | url = "https://api.github.com/gists";
121 | headers = { "Authorization": "Basic " + btoa(username + ":" + password) };
122 | } else if (username.length && !password.length) {
123 | // No login but filter by username
124 | url = "https://api.github.com/users/" + username + "/gists";
125 | headers = { };
126 | } else if (username.length && password.length == 40) {
127 | // OAuth login with authorization token
128 | url = "https://api.github.com/gists";
129 | headers = { "Authorization": "token " + password };
130 | // Store Auth token to Brackets preferences file
131 | auths[username] = {};
132 | auths[username].username = username;
133 | auths[username].password = password;
134 | prefs.set("auths", auths);
135 | prefs.save();
136 | } else {
137 | // No login, show public gists
138 | url = "https://api.github.com/gists";
139 | headers = { };
140 | }
141 |
142 | if (action === "GET") {
143 | return {"url": url, "headers": headers};
144 | } else if (action === "DELETE") {
145 | if (headers.Authorization) {
146 | return {"url": "https://api.github.com/gists/", "headers": headers};
147 | }
148 | }
149 |
150 | }
151 |
152 | // Load list of Gists
153 | // if no username is provided then load the public list
154 | // if username is provided then load the list of the selected username
155 | // if password is provided then load even the secret Gists of the selected user
156 | function loadContent(username, password) {
157 |
158 | // These will be used in our Ajax call
159 | var auth = getAuth(username, password, "GET");
160 |
161 | $.ajax({
162 | type: "GET",
163 | url: auth.url,
164 | dataType: "json",
165 | headers: auth.headers,
166 | success: function (data) {
167 | gists = data;
168 |
169 | $.map(gists, function(gist) {
170 |
171 | gist.shortDescription = "gist:" + gist.id;
172 | if (typeof gist.description != null && gist.description != null) {
173 | if (gist.description.length) {
174 | gist.shortDescription = gist.description.substring(0, 20);
175 | }
176 | }
177 | return gist;
178 |
179 | });
180 |
181 | _renderContent(gists);
182 | },
183 | error: function (err) {
184 | var response = JSON.parse(err.responseText);
185 | Dialogs.showModalDialog("error-dialog", Strings.LOADING_ERROR, response.message);
186 | console.error("gist-manager:", err);
187 | }
188 | });
189 |
190 | // Renders a given list of Gists inside the panel
191 | function _renderContent(gists) {
192 |
193 | var vars = {"gists": gists};
194 | $content = $(Mustache.render(content, vars));
195 | $panel.find(".gist-manager-content").html($content);
196 |
197 | // Render the first gist
198 | renderGist(gists[0]);
199 |
200 | // Add event handler on the list of Gists
201 | $panel.on("click", ".list-group-item", function(event) {
202 |
203 | gists.forEach( function(gist) {
204 | if (gist.id == $(event.target).data("id")) {
205 | renderGist(gist);
206 | return;
207 | }
208 | });
209 |
210 | });
211 | }
212 | }
213 |
214 | function deleteGist(username, password, id) {
215 |
216 | // These will be used in our Ajax call
217 | var auth = getAuth(username, password, "DELETE");
218 |
219 | if (typeof auth === undefined || auth === undefined) {
220 | Dialogs.showModalDialog("error-dialog", Strings.DELETING_ERROR, "You do not own this Gist, please check your login details.");
221 | return;
222 | }
223 |
224 | $.ajax({
225 | type: "DELETE",
226 | url: auth.url + id,
227 | dataType: "json",
228 | headers: auth.headers,
229 | success: function () {
230 | $panel.find("#" + id).remove();
231 | $panel.find("*[data-id=" + id + "]").parent().remove();
232 | $panel.find(".list li").first().addClass("active").find("a").trigger("click");
233 | },
234 | error: function (err) {
235 | var response = JSON.parse(err.responseText);
236 | Dialogs.showModalDialog("error-dialog", Strings.LOADING_ERROR, response.message);
237 | console.error("gist-manager:", err);
238 | }
239 | });
240 | }
241 |
242 | function filterContent(query) {
243 |
244 | $panel.find(".gist-manager-content .list li").show();
245 | $panel.find(".gist-manager-content .list li:not(:containsIN('" + query + "'))").hide();
246 |
247 | }
248 |
249 | // Post a new Gist
250 | function newGist(username, password, entireFile) {
251 |
252 | var content = "",
253 | gistFileName = "",
254 | filename = DocumentManager.getCurrentDocument().file._name,
255 | selection = EditorManager.getCurrentFullEditor().getSelectedText();
256 |
257 |
258 | if (entireFile) {
259 | content = DocumentManager.getCurrentDocument()._masterEditor.document.file._contents;
260 | } else if (selection.length) {
261 | content = selection;
262 | }
263 |
264 | if (content.length && filename.length) {
265 | gistFileName = filename;
266 | }
267 |
268 | var vars = $.extend({"content": content, "filename": gistFileName, "secret": (username.length && password.length)}, Strings);
269 |
270 | var dialog = Dialogs.showModalDialogUsingTemplate(Mustache.render(newGistDialog, vars)),
271 | $dialog = dialog.getElement();
272 |
273 | $dialog.
274 | on("click", "#add-file", function() {
275 | $dialog.find("#prototype-file .file").first().clone().appendTo("#files");
276 | });
277 |
278 | dialog.done(function (buttonId) {
279 | if (buttonId === "create-public-gist" || buttonId === "create-secret-gist") {
280 |
281 | var url = "https://api.github.com/gists",
282 | headers;
283 |
284 | var gistData = {
285 | "description": $dialog.find("[name=description]").val(),
286 | "public": (buttonId === "create-public-gist"),
287 | "files": { }
288 | };
289 |
290 | $dialog.find("#files .file").each( function() {
291 | gistData.files[$(this).find(".filename").val()] = {};
292 | gistData.files[$(this).find(".filename").val()].content = $(this).find(".content").val();
293 | });
294 |
295 | // Set header if user wants to be authenticated
296 | if (username.length && password.length) {
297 | headers = { "Authorization": "Basic " + btoa(username + ":" + password) };
298 | } else {
299 | headers = { };
300 | }
301 |
302 | $.ajax({
303 | type: "POST",
304 | url: url,
305 | dataType: "json",
306 | headers: headers,
307 | data: JSON.stringify(gistData),
308 | success: function (response) {
309 | var vars = $.extend(response, Strings);
310 | var dialog = Dialogs.showModalDialogUsingTemplate(Mustache.render(successGistDialog, vars));
311 |
312 | dialog.done(function (buttonId) {
313 | if (buttonId === "open") {
314 | brackets.app.openURLInDefaultBrowser(response.html_url);
315 | }
316 | });
317 |
318 | if (username.length && password.length) {
319 | loadContent(username, password);
320 | }
321 | },
322 | error: function (err) {
323 | var response = JSON.parse(err.responseText);
324 | Dialogs.showModalDialog("error-dialog", Strings.CREATION_ERROR, response.message);
325 | console.error("gist-manager:", err);
326 | }
327 | });
328 | }
329 | });
330 | }
331 |
332 | function loadToken(username) {
333 |
334 | if (auths[username]) {
335 | $panel.find("#github-password").val(auths[username].password);
336 | } else {
337 | $panel.find("#github-password").val("");
338 | }
339 |
340 | }
341 |
342 | function init() {
343 |
344 | // Load compiled CSS of Gist Manager
345 | ExtensionUtils.loadStyleSheet(module, "styles/gist-manager.css");
346 |
347 | // Add menu option to toggle Gist Manager panel
348 | CommandManager.register(Strings.SHOW_GIST_MANAGER, TOGGLE_PANEL, _handlePanelToggle);
349 | var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
350 | menu.addMenuItem(TOGGLE_PANEL, null, Menus.AFTER);
351 |
352 | // Add menu option to create Gist of the current file
353 | CommandManager.register(Strings.GIST_FROM_CURRENT_FILE, GIST_FROM_CURRENT_FILE, function() {
354 | newGist($panel.find("#github-username").val(), $panel.find("#github-password").val(), true);
355 | });
356 | var editMenu = Menus.getMenu(Menus.AppMenuBar.EDIT_MENU);
357 | editMenu.addMenuItem(GIST_FROM_CURRENT_FILE, null, Menus.AFTER);
358 |
359 | // Add context menu option to create gist
360 | CommandManager.register(
361 | Strings.CREATE_NEW_GIST,
362 | NEW_GIST_MENU,
363 | function() { newGist($panel.find("#github-username").val(), $panel.find("#github-password").val()); }
364 | );
365 | var contextMenu = Menus.getContextMenu(Menus.ContextMenuIds.EDITOR_MENU);
366 | contextMenu.addMenuItem(NEW_GIST_MENU);
367 |
368 | // Create Gist Manager panel
369 | var vars = Strings,
370 | authsMustache = [];
371 |
372 | $.each(auths, function(auth) {
373 | authsMustache.push(auth);
374 | });
375 |
376 | $.extend(vars, {"auths": authsMustache});
377 |
378 | PanelManager.createBottomPanel(GM_PANEL, $(Mustache.render(panel, vars)), 200);
379 |
380 | // Cache selection of Gist Manager panel
381 | $panel = $("#gist-manager");
382 |
383 | // Add events handler to Gist Manager panel
384 | $panel
385 | .on("click", "#load-gists", function() {
386 | loadContent($panel.find("#github-username").val(), $panel.find("#github-password").val());
387 | })
388 | .on("click", "#new-gist", function() {
389 | newGist($panel.find("#github-username").val(), $panel.find("#github-password").val());
390 | })
391 | .on("keyup", "#filter-content", function() {
392 | filterContent($panel.find("#filter-content").val());
393 | })
394 | .on("keyup", "#github-username", function() {
395 | loadToken($panel.find("#github-username").val());
396 | })
397 | .on("click", ".delete-gist", function() {
398 | deleteGist($panel.find("#github-username").val(), $panel.find("#github-password").val(), $(this).attr("data-id"));
399 | })
400 | .on("click", ".close", _handlePanelToggle);
401 |
402 | // Create button only if required by user settings
403 | if (prefs.get("showButton")) {
404 | // Append button to toolbar
405 | $("#main-toolbar .buttons").append(Mustache.render(button));
406 | $button = $("#gist-manager-button");
407 |
408 | // Add events handler to Gist Manager button if required
409 | $(document).on("click", "#gist-manager-button", _handlePanelToggle);
410 | }
411 | }
412 |
413 | init();
414 |
415 | });
416 |
--------------------------------------------------------------------------------