sharkey-web 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.md +19 -0
  5. data/README.md +188 -0
  6. data/Rakefile +8 -0
  7. data/bin/sharkey-web +9 -0
  8. data/config.ru +3 -0
  9. data/lib/sharkey.rb +12 -0
  10. data/lib/sharkey/app.rb +526 -0
  11. data/lib/sharkey/importerexporter.rb +79 -0
  12. data/lib/sharkey/models.rb +295 -0
  13. data/lib/sharkey/public/css/loading.gif +0 -0
  14. data/lib/sharkey/public/css/magicsuggest.css +232 -0
  15. data/lib/sharkey/public/css/nprogress.css +74 -0
  16. data/lib/sharkey/public/css/styles.css +263 -0
  17. data/lib/sharkey/public/css/ui.fancytree.css +545 -0
  18. data/lib/sharkey/public/data/sentences.txt +5 -0
  19. data/lib/sharkey/public/fonts/Quadrata.eot +0 -0
  20. data/lib/sharkey/public/fonts/Quadrata.svg +613 -0
  21. data/lib/sharkey/public/fonts/Quadrata.ttf +0 -0
  22. data/lib/sharkey/public/fonts/Quadrata.woff +0 -0
  23. data/lib/sharkey/public/fonts/Quadrata.zip +0 -0
  24. data/lib/sharkey/public/images/loader.gif +0 -0
  25. data/lib/sharkey/public/images/sharkey-logo.png +0 -0
  26. data/lib/sharkey/public/images/sharkey.png +0 -0
  27. data/lib/sharkey/public/js/ajaxmanager.js +67 -0
  28. data/lib/sharkey/public/js/keybindings.js +92 -0
  29. data/lib/sharkey/public/js/lib/bootstrap.min.js +6 -0
  30. data/lib/sharkey/public/js/lib/jquery-1.9.1.min.js +5 -0
  31. data/lib/sharkey/public/js/lib/jquery-ui.js +16150 -0
  32. data/lib/sharkey/public/js/lib/jquery.bootstrap-autohidingnavbar.js +213 -0
  33. data/lib/sharkey/public/js/lib/jquery.fancytree-all.js +6424 -0
  34. data/lib/sharkey/public/js/lib/jquery.tagcloud.js +92 -0
  35. data/lib/sharkey/public/js/lib/magicsuggest.js +1468 -0
  36. data/lib/sharkey/public/js/lib/mousetrap.min.js +9 -0
  37. data/lib/sharkey/public/js/lib/nprogress.js +476 -0
  38. data/lib/sharkey/public/js/page-add-link-autofill.js +102 -0
  39. data/lib/sharkey/public/js/page-add-link.js +156 -0
  40. data/lib/sharkey/public/js/page-categories.js +348 -0
  41. data/lib/sharkey/public/js/page-edit-link.js +103 -0
  42. data/lib/sharkey/public/js/page-links.js +54 -0
  43. data/lib/sharkey/public/js/page-settings.js +93 -0
  44. data/lib/sharkey/public/js/page-tagcloud.js +35 -0
  45. data/lib/sharkey/public/js/page-tags.js +287 -0
  46. data/lib/sharkey/public/js/scripts.js +147 -0
  47. data/lib/sharkey/public/themes/amelia/style.css +7 -0
  48. data/lib/sharkey/public/themes/bootstrap/style.css +5785 -0
  49. data/lib/sharkey/public/themes/cerulean/style.css +7 -0
  50. data/lib/sharkey/public/themes/cosmo/style.css +7 -0
  51. data/lib/sharkey/public/themes/cyborg/style.css +7 -0
  52. data/lib/sharkey/public/themes/darkly/style.css +7 -0
  53. data/lib/sharkey/public/themes/facebook-like/README.md +6 -0
  54. data/lib/sharkey/public/themes/facebook-like/style.css +6085 -0
  55. data/lib/sharkey/public/themes/flatly/style.css +7 -0
  56. data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.eot +0 -0
  57. data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.svg +229 -0
  58. data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.ttf +0 -0
  59. data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.woff +0 -0
  60. data/lib/sharkey/public/themes/holo-like/README.md +5 -0
  61. data/lib/sharkey/public/themes/holo-like/style.css +5997 -0
  62. data/lib/sharkey/public/themes/journal/style.css +7 -0
  63. data/lib/sharkey/public/themes/lumen/style.css +7 -0
  64. data/lib/sharkey/public/themes/readable/style.css +7 -0
  65. data/lib/sharkey/public/themes/simplex/style.css +7 -0
  66. data/lib/sharkey/public/themes/slate/style.css +7 -0
  67. data/lib/sharkey/public/themes/spacelab/style.css +7 -0
  68. data/lib/sharkey/public/themes/superhero/style.css +7 -0
  69. data/lib/sharkey/public/themes/united/style.css +7 -0
  70. data/lib/sharkey/public/themes/yeti/style.css +7 -0
  71. data/lib/sharkey/setting.rb +74 -0
  72. data/lib/sharkey/version.rb +5 -0
  73. data/lib/sharkey/views/404.slim +4 -0
  74. data/lib/sharkey/views/about.slim +7 -0
  75. data/lib/sharkey/views/add_link.slim +157 -0
  76. data/lib/sharkey/views/categories.slim +101 -0
  77. data/lib/sharkey/views/category.slim +22 -0
  78. data/lib/sharkey/views/centered.slim +49 -0
  79. data/lib/sharkey/views/dashboard.slim +107 -0
  80. data/lib/sharkey/views/dashboard_index.slim +26 -0
  81. data/lib/sharkey/views/edit_link.slim +121 -0
  82. data/lib/sharkey/views/help.slim +74 -0
  83. data/lib/sharkey/views/keybindings.slim +58 -0
  84. data/lib/sharkey/views/link.slim +30 -0
  85. data/lib/sharkey/views/links.slim +22 -0
  86. data/lib/sharkey/views/navbar.slim +68 -0
  87. data/lib/sharkey/views/settings.slim +74 -0
  88. data/lib/sharkey/views/settings_index.slim +220 -0
  89. data/lib/sharkey/views/single_category.slim +37 -0
  90. data/lib/sharkey/views/single_link.slim +95 -0
  91. data/lib/sharkey/views/single_tag.slim +33 -0
  92. data/lib/sharkey/views/tag.slim +22 -0
  93. data/lib/sharkey/views/tagcloud.slim +54 -0
  94. data/lib/sharkey/views/tags.slim +99 -0
  95. data/sharkey-web.gemspec +44 -0
  96. metadata +324 -0
@@ -0,0 +1,103 @@
1
+ /*global $*/
2
+
3
+ /**
4
+ * Scripts for the "Edit Link" dialog.
5
+ */
6
+ ($(function(){
7
+
8
+ var clearEditLinkDialog = function() {
9
+
10
+ $('#edit-link input').each(function(a, element) {
11
+ $(element).val('');
12
+ });
13
+
14
+ // This is due to the awesome tag-input helper
15
+ $('#edit-link #input-link-tags input').val('');
16
+
17
+ $('#edit-link select').val(0);
18
+ };
19
+
20
+ /**
21
+ * When you click to "Edit Link", Bootstrap will automatically
22
+ * show the dialog (modal).
23
+ * But we need to fill it with this link's current attributes.
24
+ */
25
+ $('button.link-edit').click(function() {
26
+
27
+ // Just in case we tried to edit a link before
28
+ // and bailed out
29
+ clearEditLinkDialog();
30
+
31
+ var link = $(
32
+ $(this).parents('li.link')
33
+ );
34
+
35
+ // First, we need to obtain the current data for the link
36
+ //
37
+ // I could make an AJAX request to the server, but I'd
38
+ // rather crawl everything from the current page.
39
+ //
40
+ // Unfortunately, if I change the layout then everything
41
+ // FUCKS UP
42
+
43
+ var link_id = link.attr('data-link-id');
44
+
45
+ var link_url = link.find('span.link-title > a').attr('href');
46
+ var link_title = link.find('span.link-title').text();
47
+
48
+ /* Creating an array of tag names */
49
+ var link_tags = link.find('.link-tags a');
50
+ if ((link_tags) && (link_tags.length > 0)) {
51
+ var tmp = [];
52
+ link_tags.each(function(a, element) {
53
+ tmp.push($(element).attr('title'));
54
+ });
55
+ link_tags = tmp;
56
+ }
57
+ else
58
+ link_tags = [];
59
+
60
+ var link_comments = link.find('span.link-description').text();
61
+
62
+ /* Creating an array of category names */
63
+ var link_category = link.find('.link-categories a');
64
+ if ((link_category) && (link_category.length > 0)) {
65
+ var tmp = link_category[0];
66
+
67
+ // It will be an <a> with href like `/category/id`
68
+ // When split it will become ["", "category", "id"]
69
+ link_category = $(tmp).attr('href').split('/')[2];
70
+ }
71
+ else
72
+ link_category = "";
73
+
74
+ // Now we fill the "Edit Link" form with the data
75
+ // we just got. Brace yourselves!
76
+ $('#edit-link #input-link-url').val(link_url);
77
+ $('#edit-link #input-link-title').val(link_title);
78
+
79
+ // Now here's an EXCEPTION
80
+ // Since we're using an awesome plugin to visually
81
+ // handle the tags, we must accommodate to it.
82
+ // It actually has a hidden input like this:
83
+ // THIS IS DUPLICATED CODE OMG WHAT DO I DO
84
+ $('#edit-link #input-link-tags').magicSuggest({
85
+ data: '/tags',
86
+ method: 'get',
87
+ typeDelay: 0,
88
+ noSuggestionText: 'No tags like this',
89
+ placeholder: 'Yeah',
90
+ useCommaKey: true,
91
+ maxSelection: null,
92
+ useZebraStyle: true
93
+ }).setValue(link_tags);
94
+
95
+ $('#edit-link #input-link-comment').val(link_comments);
96
+ $('#edit-link #input-link-category-one').val(link_category);
97
+
98
+ $( $('#edit-link form')[0]) .attr('action', '/update/link/' + link_id);
99
+ });
100
+
101
+ }));
102
+
103
+
@@ -0,0 +1,54 @@
1
+ /*global $*/
2
+
3
+ /**
4
+ * Scripts specific to the Links page.
5
+ *
6
+ * Requires jQuery.
7
+ */
8
+ ($(function(){
9
+
10
+ /* Whenever you click on a link, let's make an AJAX request
11
+ * to add it's visit count
12
+ */
13
+ $('.link-title > a').click(function(e) {
14
+
15
+ // Kinda ugly way of traversing the DOM
16
+ // It WILL mess up if I ever change the HTML
17
+ // structure... Maybe I should find a better way
18
+ var link_element = $(e.target).parents('li');
19
+ var link_id = link_element.attr('data-link-id');
20
+
21
+ $.ajax({
22
+ url: '/visit/' + link_id,
23
+ type: 'POST',
24
+
25
+ success: function(responseData, textStatus, jqXHR) {
26
+
27
+ // Updating the link's visited text with
28
+ // the new count.
29
+ var new_count = $.parseJSON(responseData).visitCount;
30
+ if (new_count) {
31
+
32
+ link_element.find('.link-visited-date').html(
33
+ 'Last visited a moment ago'
34
+ );
35
+ link_element.find('.link-visited-count').html(
36
+ '<span class="glyphicon glyphicon-open"></span> ' + new_count
37
+ );
38
+ }
39
+ },
40
+ error: function(responseData, textStatus, jqXHR) {
41
+ console.log(
42
+ "Error! Couldn't set Link as visited!\n" +
43
+ "responseData: " + responseData + "\n" +
44
+ "textStatus: " + textStatus + "\n" +
45
+ "jqXHR: " + jqXHR
46
+ );
47
+ }
48
+ });
49
+ });
50
+
51
+ }));
52
+
53
+
54
+
@@ -0,0 +1,93 @@
1
+ /*global $*/
2
+
3
+ /**
4
+ * Scripts specific for the Settings page
5
+ */
6
+ ($(function(){
7
+
8
+ // *****************************************************
9
+ // CODE DUPLICATION
10
+ // (see `scripts.js`)
11
+ /**
12
+ * Returns a new cute spinner GIF for
13
+ * showing indeterminate progress.
14
+ */
15
+ function newSpinner() {
16
+ return $('<img/>').attr("src", "/images/loader.gif");
17
+ }
18
+ /* Here we preload the image so it won't take long
19
+ * when creating it for the first time */
20
+ newSpinner().appendTo('body').hide();
21
+ // *****************************************************
22
+
23
+
24
+ /**
25
+ * AJAX requester for changing `input radio` settings.
26
+ *
27
+ * We need:
28
+ * - Parent `form`
29
+ * - Child `label` with class `ajax-radio`
30
+ */
31
+ $('.ajax-radio').click(function() {
32
+
33
+ // The button we just pressed - will add `.active` class
34
+ // on success
35
+ var this_button = $(this);
36
+
37
+ var parent_form = this_button.parents('form');
38
+
39
+ // The button neighbor to the just pressed - will remove
40
+ // `.active` class on success
41
+ var that_button = parent_form.find('label:not(.active)');
42
+
43
+ /* URL for AJAX request: like '/delete_/DELETE_ID' */
44
+ var setting_url = this_button.parents('form').attr('action');
45
+ var setting_value = this_button.children('input').attr('value');
46
+
47
+ /* Remove button to prevent double request
48
+ * and create the cute loader image */
49
+ var spinner = $(newSpinner()).appendTo(parent_form);
50
+
51
+ $.ajax({
52
+ url: setting_url,
53
+ type: 'POST',
54
+ data: {
55
+ name: this_button.children('input').attr('name'),
56
+ value: setting_value
57
+ },
58
+ success: function(responseData, textStatus, jqXHR) {
59
+
60
+ // When this request succeds, Bootstrap JS already changed
61
+ // the buttons' .active classes.
62
+ // So the button we just pressed is this...
63
+ parent_form
64
+ .find('label.active')
65
+ .attr('class', 'btn btn-primary ajax-radio active');
66
+
67
+ // and the other one is that...
68
+ parent_form
69
+ .find('label:not(.active)')
70
+ .attr('class', 'btn btn-default ajax-radio');
71
+ },
72
+ error: function(responseData, textStatus, jqXHR) {
73
+ /* This error-handling function sucks! */
74
+ parent_form.append(
75
+ $("<div>Couldn't apply the setting - please reload the page</div>")
76
+ .attr('class', 'alert alert-danger')
77
+ .attr('role', 'alert')
78
+ );
79
+ },
80
+ complete: function() {
81
+ spinner.remove();
82
+ }
83
+ });
84
+ });
85
+
86
+ // It may take a while.
87
+ // Let's warn the user...!
88
+ $('#button-import').click(function() {
89
+ $(this).html('Hold on, this might take a while... ');
90
+ $(this).append(newSpinner());
91
+ });
92
+ }));
93
+
@@ -0,0 +1,35 @@
1
+ /*global $,activateTagCloud*/
2
+
3
+ /**
4
+ * Scripts specific to the TagCloud page.
5
+ *
6
+ * NOTE: we require jQuery TagCloud!
7
+ */
8
+
9
+ $(function () {
10
+
11
+ /**
12
+ * This function activates the tag cloud functionality.
13
+ * Call it from the TagCloud page.
14
+ *`
15
+ * @note It's actually defined on the TagCloud page!
16
+ *
17
+ * @param smaller Tiniest possible font size allowed
18
+ * @param bigger Biggest possible font size allowed
19
+ */
20
+ activateTagCloud = function(smaller, bigger) {
21
+ $.fn.tagcloud.defaults = {
22
+ size: {
23
+ start: smaller,
24
+ end: bigger,
25
+ unit: 'pt'
26
+ },
27
+ color: {
28
+ start: '#f5f5f5',
29
+ end: '#428bca'
30
+ }
31
+ };
32
+ $('#tagcloud a').tagcloud();
33
+ };
34
+ });
35
+
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Scripts specific to the Tags page.
3
+ *
4
+ * Note that we assume jQuery, ajaxManager and other stuff.
5
+ */
6
+ /*global $,ajaxManager*/
7
+ ($(function() {
8
+
9
+ // When the page loads, focus on the Tag Browser
10
+ $('#tags .fancytree-container').focus();
11
+
12
+
13
+ /**
14
+ * Initializing the tree view for all the Tags
15
+ */
16
+ $('#tags').fancytree({
17
+ extensions: ["glyph", "childcounter"],
18
+ glyph: {
19
+ map: {
20
+ doc: "glyphicon glyphicon-link",
21
+ docOpen: "glyphicon glyphicon-link",
22
+ checkbox: "glyphicon glyphicon-unchecked",
23
+ checkboxSelected:"glyphicon glyphicon-check",
24
+ checkboxUnknown: "glyphicon glyphicon-edit",
25
+ expanderClosed: "glyphicon glyphicon-expand",
26
+ expanderLazy: "glyphicon glyphicon-expand",
27
+ expanderOpen: "glyphicon glyphicon-collapse-down",
28
+ folder: "glyphicon glyphicon-tag",
29
+ folderOpen: "glyphicon glyphicon-tag"
30
+ }
31
+ },
32
+ keyboard: true,
33
+
34
+ /* when an item is clicked (either Tag or Link) */
35
+ click: function(event, data) {
36
+
37
+ // Clicked item on the list
38
+ //var node = data.node;
39
+
40
+ /* Whenever you click on a link, let's make an
41
+ * AJAX request to add it's visit count
42
+ */
43
+ var element = event.toElement;
44
+
45
+ if ((element) && ($(element).attr('class') === 'link-link')) {
46
+
47
+ var link_id = $(element).attr('data-link-id');
48
+
49
+ $.ajax({
50
+ url: '/visit/' + link_id,
51
+ type: 'POST',
52
+
53
+ // Yeah, won't do anything if we succeed
54
+
55
+ success: function(responseData, textStatus, jqXHR) {
56
+ console.log($.parseJSON(responseData).visitCount);
57
+ },
58
+
59
+ error: function(responseData, textStatus, jqXHR) {
60
+ console.log(
61
+ "Error! Couldn't set Link as visited!\n" +
62
+ "responseData: " + responseData + "\n" +
63
+ "textStatus: " + textStatus + "\n" +
64
+ "jqXHR: " + jqXHR
65
+ );
66
+ }
67
+ });
68
+ }
69
+ },
70
+ /* when user presses ENTER or SPACE inside an item */
71
+ link: function(event, data) {
72
+ /* redirect to the internal link
73
+ * (either Category or Link) */
74
+ var href = $(
75
+ $.parseHTML(data.node.title)
76
+ ).attr('href');
77
+
78
+ window.location.href = href;
79
+ }
80
+ });
81
+ /**
82
+ * Helper to ease applying things to every
83
+ * node inside the tree view.
84
+ *
85
+ * @param apply Function to apply to each node.
86
+ */
87
+ var foreachNode = function(apply) {
88
+ $('#tags')
89
+ .fancytree('getTree')
90
+ .visit(function(node) {
91
+ apply(node);
92
+ });
93
+ };
94
+ /* Things using FancyTree's API */
95
+ $('#tags-expand').click(function() {
96
+ foreachNode(function(node) {
97
+ node.setExpanded(true);
98
+ });
99
+ });
100
+
101
+ $('#tags-collapse').click(function() {
102
+ foreachNode(function(node) {
103
+ node.setExpanded(false);
104
+ });
105
+ });
106
+
107
+ /*
108
+ * Now we define some functions that will handle the
109
+ * editing progress of the Tags.
110
+ */
111
+
112
+ // Flag to tell if we're editing the Tags
113
+ var tagIsEditing = false;
114
+
115
+ // All the buttons for the editing process
116
+ var tagEditButtons = $(
117
+ '#tags-select-all, #tags-select-none, #tags-select-toggle, #tags-delete, #tags-delete-links'
118
+ );
119
+ // Initially we're not editing
120
+ tagEditButtons.hide();
121
+
122
+ /* Start editing, baby! */
123
+ $('#tags-edit').click(function() {
124
+ tagIsEditing = !tagIsEditing;
125
+
126
+ if (tagIsEditing) {
127
+ // Change the button's appearance
128
+ $(this).html(
129
+ "<button class='btn btn-default'><span class='glyphicon glyphicon-ban-circle' /> Cancel</button>"
130
+ );
131
+
132
+ /* Reinitializing the tree view, this time
133
+ * enabling checkboxes and multi-selection
134
+ * mode */
135
+ $('#tags').fancytree({
136
+ checkbox: true,
137
+ selectMode: 2,
138
+
139
+ // When double-clicking, toggle!
140
+ dblclick: function(event, data) {
141
+ data.node.toggleSelected();
142
+ }
143
+ });
144
+ tagEditButtons.show();
145
+
146
+ // Here we only let the user select TAGS,
147
+ // not LINKS!
148
+ // Tags are considered folders, because they
149
+ foreachNode(function(node) {
150
+ if (! node.isFolder())
151
+ node.unselectable = true;
152
+ });
153
+
154
+ }
155
+ else {
156
+ // Change the button's appearance AGAIN
157
+ $(this).html(
158
+ "<button class='btn btn-default'><span class='glyphicon glyphicon-pencil' /> Edit</a>"
159
+ );
160
+ $('#tags').fancytree({
161
+ checkbox:false
162
+ });
163
+ tagEditButtons.hide();
164
+ }
165
+ });
166
+
167
+ // And now, what happens when you click
168
+ // on each of those fancy buttons
169
+
170
+ $('#tags-select-all').click(function() {
171
+ foreachNode(function(node) {
172
+ node.setSelected(true);
173
+ });
174
+ });
175
+ $('#tags-select-none').click(function() {
176
+ foreachNode(function(node) {
177
+ node.setSelected(false);
178
+ });
179
+ });
180
+ $('#tags-select-toggle').click(function() {
181
+ foreachNode(function(node) {
182
+ node.toggleSelected();
183
+ });
184
+ });
185
+
186
+ // Now, when you click to delete tags, we musc
187
+ // communicate with the server
188
+ $('#tags-delete').click(function() {
189
+
190
+ // Will also destroy links that has these tags
191
+ var destroyLinks = $('#tags-delete-links input').is(':checked');
192
+
193
+ // We will send several DELETE requests
194
+ // to the server, each with a selected
195
+ // tag's ID
196
+ var maxSize = $('#tags')
197
+ .fancytree('getTree')
198
+ .getSelectedNodes()
199
+ .length;
200
+
201
+ // And we place a beautiful progress bar,
202
+ // to make the user not think we crashed
203
+ var progressbarParent = $(
204
+ "<div class='progress progress-striped active'></div>"
205
+ );
206
+ var progressbarText = $("<span>0%</span>");
207
+ var progressbar = $(
208
+ "<div class='progress-bar' " +
209
+ "role='progressbar' " +
210
+ "aria-valuenow='0' " +
211
+ "aria-valuemin='0' " +
212
+ "aria-valuemax='" + maxSize + "'></div>"
213
+ );
214
+
215
+ // Replace the buttons by the progress bar
216
+ $('#tags-buttons').html('');
217
+ progressbarParent.appendTo($('#tags-buttons'));
218
+ progressbar.appendTo(progressbarParent);
219
+ progressbarText.appendTo(progressbar);
220
+
221
+ var deletedCount = 0;
222
+
223
+ foreachNode(function(node) {
224
+
225
+ if (!node.selected)
226
+ return;
227
+
228
+ // Each node has a `title` element,
229
+ // with an href like '/tag/(ID)'
230
+ var href = $(
231
+ $.parseHTML(node.title)
232
+ ).attr('href');
233
+
234
+ // Now, time for the AJAX request...!
235
+ ajaxManager.add({
236
+ url: href,
237
+ type: 'DELETE',
238
+ data: {
239
+ destroy_links: destroyLinks
240
+ },
241
+ /* Showing a red background on deleted tags */
242
+ success: function(responseData, textStatus, jqXHR) {
243
+
244
+ // Updating the progress bar
245
+ deletedCount += 1;
246
+ progressbar
247
+ .attr('style', 'width:' + (deletedCount/maxSize)*100 + '%')
248
+ .attr('aria-valuenow', deletedCount);
249
+ progressbarText
250
+ .text(Math.round( ((deletedCount/maxSize)*100) * 100)/100+ '%');
251
+
252
+ // This animation requires jQueryUI
253
+ $(node.span).animate({
254
+ backgroundColor: '#FFDFDF'
255
+ }, 1000);
256
+
257
+ // Removing the element on the raw list
258
+ // generated by sinatra
259
+ $('#tags')
260
+ .find("li span a[href='" + href + "']")
261
+ .each(function() {
262
+ $(this).parent('li').remove();
263
+ });
264
+ },
265
+ error: function(responseData, textStatus, jqXHR) {
266
+ /* This error-handling function sucks! */
267
+ alert("Couldn't remove tag! " + responseData + ', ' + textStatus);
268
+ }
269
+ });
270
+ });
271
+ // When everything's done...
272
+ ajaxManager.complete = function() {
273
+
274
+ // Now the progress bar is shown as completed
275
+ // and the user is advised to refresh the page
276
+ progressbarParent.removeClass('active');
277
+ progressbarParent.removeClass('progress-striped');
278
+ progressbar.addClass('progress-bar-success');
279
+ progressbarText.text("Done! Refresh page to see the changes");
280
+ };
281
+
282
+ // Now, do perform those requests for me!
283
+ ajaxManager.run();
284
+ });
285
+
286
+ }));
287
+