sufia 3.7.2 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (275) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Gemfile +3 -0
  4. data/README.md +88 -11
  5. data/SUFIA_VERSION +1 -1
  6. data/app/assets/images/old_main_tulips.jpg +0 -0
  7. data/app/assets/javascripts/contact_form.js +0 -16
  8. data/app/assets/javascripts/jquery.blacklightTagCloud.js +44 -0
  9. data/app/assets/javascripts/jquery.tagcloud.js +116 -0
  10. data/app/assets/javascripts/jquery.tinysort.min.js +7 -0
  11. data/app/assets/javascripts/sufia.js +41 -44
  12. data/app/assets/javascripts/sufia/edit_metadata.js +1 -1
  13. data/app/assets/javascripts/sufia/editor.js +12 -0
  14. data/app/assets/javascripts/sufia/featured_works.js +64 -0
  15. data/app/assets/javascripts/sufia/fileupload.js +1 -1
  16. data/app/assets/javascripts/sufia/multiForm.js +1 -1
  17. data/app/assets/javascripts/sufia/permissions.js +4 -8
  18. data/app/assets/javascripts/sufia/single_use_link.js +1 -2
  19. data/app/assets/javascripts/sufia/trophy.js +42 -27
  20. data/app/assets/javascripts/terms_of_service.js +1 -1
  21. data/app/assets/stylesheets/dashboard.css.scss +81 -40
  22. data/app/assets/stylesheets/featured.css.scss +16 -0
  23. data/app/assets/stylesheets/fileupload/{jquery.fileupload-ui.css → jquery.fileupload-ui.css.erb} +2 -2
  24. data/app/assets/stylesheets/{generic_files.css → generic_files.css.erb} +6 -7
  25. data/app/assets/stylesheets/header.css.scss +93 -0
  26. data/app/assets/stylesheets/home-page.css.scss +50 -0
  27. data/app/assets/stylesheets/nestable.css.scss +111 -0
  28. data/app/assets/stylesheets/styles.css.scss +106 -0
  29. data/app/assets/stylesheets/sufia.css.scss +13 -8
  30. data/app/assets/stylesheets/tagcloud.css +83 -0
  31. data/app/assets/stylesheets/usage-stats.css +30 -0
  32. data/app/controllers/batch_controller.rb +0 -1
  33. data/app/controllers/concerns/sufia/catalog.rb +64 -0
  34. data/app/controllers/concerns/sufia/dashboard_controller_behavior.rb +16 -13
  35. data/app/controllers/content_blocks_controller.rb +8 -0
  36. data/app/controllers/featured_work_lists_controller.rb +16 -0
  37. data/app/controllers/featured_works_controller.rb +26 -0
  38. data/app/controllers/mailbox_controller.rb +1 -1
  39. data/app/controllers/pages_controller.rb +7 -0
  40. data/app/controllers/single_use_links_viewer_controller.rb +2 -5
  41. data/app/controllers/tinymce_assets_controller.rb +12 -0
  42. data/app/helpers/content_block_helper.rb +21 -0
  43. data/app/helpers/generic_file_helper.rb +2 -2
  44. data/app/helpers/sufia_helper.rb +8 -4
  45. data/app/helpers/trophy_helper.rb +15 -7
  46. data/app/models/content_block.rb +2 -0
  47. data/app/models/featured_work_list.rb +42 -0
  48. data/app/models/tinymce_asset.rb +3 -0
  49. data/app/uploaders/tinymce_asset_uploader.rb +51 -0
  50. data/app/views/_add_assets_links.html.erb +0 -16
  51. data/app/views/_controls.html.erb +17 -0
  52. data/app/views/_flash_msg.html.erb +2 -18
  53. data/app/views/_footer.html.erb +10 -15
  54. data/app/views/_ga.html.erb +0 -16
  55. data/app/views/_logo.html.erb +2 -2
  56. data/app/views/_masthead.html.erb +9 -36
  57. data/app/views/_user_util_links.html.erb +16 -11
  58. data/app/views/advanced/_advanced_search_facets.html.erb +0 -16
  59. data/app/views/advanced/_advanced_search_fields.html.erb +0 -16
  60. data/app/views/advanced/_advanced_search_help.html.erb +0 -16
  61. data/app/views/advanced/_facet_layout.html.erb +0 -16
  62. data/app/views/advanced/_facet_limit.html.erb +0 -16
  63. data/app/views/advanced/index.html.erb +2 -18
  64. data/app/views/batch/_metadata.html.erb +3 -3
  65. data/app/views/batch/edit.html.erb +4 -21
  66. data/app/views/catalog/_facet_limit.html.erb +11 -12
  67. data/app/views/catalog/_featured_researcher.html.erb +2 -0
  68. data/app/views/catalog/_home.html.erb +6 -2
  69. data/app/views/catalog/_home_content.html.erb +36 -0
  70. data/app/views/catalog/_home_header.html.erb +15 -0
  71. data/app/views/catalog/_recent_document.html.erb +1 -1
  72. data/app/views/catalog/_recents.html.erb +3 -4
  73. data/app/views/catalog/_search_form.html.erb +13 -9
  74. data/app/views/catalog/_tagcloud.html.erb +7 -0
  75. data/app/views/catalog/index.html.erb +4 -10
  76. data/app/views/contact_form/create.html.erb +0 -16
  77. data/app/views/contact_form/new.html.erb +0 -16
  78. data/app/views/dashboard/_constraints.html.erb +3 -19
  79. data/app/views/dashboard/_did_you_mean.html.erb +0 -16
  80. data/app/views/dashboard/_document_list.html.erb +0 -16
  81. data/app/views/dashboard/_facet_layout.html.erb +1 -17
  82. data/app/views/dashboard/_facet_limit.html.erb +5 -5
  83. data/app/views/dashboard/_facet_selected.html.erb +1 -17
  84. data/app/views/dashboard/_facets.html.erb +0 -18
  85. data/app/views/dashboard/_heading.html.erb +1 -1
  86. data/app/views/dashboard/_index_partials/_default_group.html.erb +7 -23
  87. data/app/views/dashboard/_index_partials/_list_files.html.erb +62 -57
  88. data/app/views/dashboard/_search_form.html.erb +10 -7
  89. data/app/views/dashboard/_show_partials/_default.html.erb +0 -18
  90. data/app/views/dashboard/_show_partials/_default_details.html.erb +0 -16
  91. data/app/views/dashboard/_show_partials/_facets.html.erb +0 -16
  92. data/app/views/dashboard/_sort_and_per_page.html.erb +10 -9
  93. data/app/views/dashboard/facet.html.erb +4 -19
  94. data/app/views/dashboard/index.html.erb +27 -49
  95. data/app/views/error/401.html.erb +1 -17
  96. data/app/views/error/404.html.erb +0 -16
  97. data/app/views/error/500.html.erb +0 -16
  98. data/app/views/error/single_use_error.html.erb +1 -17
  99. data/app/views/generic_files/_asset_deleted_flash.html.erb +0 -16
  100. data/app/views/generic_files/_asset_permissions_denial_flash.html.erb +0 -16
  101. data/app/views/generic_files/_asset_saved_flash.html.erb +0 -16
  102. data/app/views/generic_files/_asset_updated_flash.html.erb +0 -16
  103. data/app/views/generic_files/_breadcrumbs.html.erb +0 -16
  104. data/app/views/generic_files/_browse_everything.html.erb +24 -0
  105. data/app/views/generic_files/_descriptions.html.erb +1 -1
  106. data/app/views/generic_files/_field_form.html.erb +5 -5
  107. data/app/views/generic_files/_media_display.html.erb +3 -3
  108. data/app/views/generic_files/_permission_form.html.erb +5 -5
  109. data/app/views/generic_files/_rights_modal.html.erb +13 -29
  110. data/app/views/generic_files/_show_actions.html.erb +13 -1
  111. data/app/views/generic_files/_versioning.html.erb +14 -10
  112. data/app/views/generic_files/citation.html.erb +0 -16
  113. data/app/views/generic_files/edit.html.erb +10 -12
  114. data/app/views/generic_files/edit_fields/_default.html.erb +1 -1
  115. data/app/views/generic_files/edit_fields/_description.html.erb +1 -1
  116. data/app/views/generic_files/edit_fields/_resource_type.html.erb +2 -3
  117. data/app/views/generic_files/edit_fields/_rights.html.erb +1 -1
  118. data/app/views/generic_files/new.html.erb +11 -26
  119. data/app/views/generic_files/show.html.erb +7 -25
  120. data/app/views/generic_files/stats.html.erb +141 -0
  121. data/app/views/homepage/_featured.html.erb +11 -0
  122. data/app/views/homepage/_featured_fields.html.erb +18 -0
  123. data/app/views/homepage/_featured_works.html.erb +17 -0
  124. data/app/views/homepage/_sortable_featured.html.erb +26 -0
  125. data/app/views/layouts/_head_tag_content.html.erb +1 -1
  126. data/app/views/layouts/_homepage_sidebar2.html.erb +14 -0
  127. data/app/views/layouts/error.html.erb +3 -21
  128. data/app/views/layouts/homepage.html.erb +8 -37
  129. data/app/views/layouts/sufia-dashboard.html.erb +46 -0
  130. data/app/views/layouts/sufia-one-column.html.erb +8 -24
  131. data/app/views/layouts/sufia-two-column.html.erb +9 -8
  132. data/app/views/pages/show.html.erb +4 -0
  133. data/app/views/single_use_links_viewer/show.html.erb +2 -2
  134. data/app/views/static/agreement.html.erb +0 -17
  135. data/app/views/static/help.html.erb +0 -17
  136. data/app/views/static/mendeley.html.erb +0 -16
  137. data/app/views/static/subject_libraries.html.erb +0 -17
  138. data/app/views/static/terms.html.erb +0 -16
  139. data/app/views/static/zotero.html.erb +0 -16
  140. data/app/views/users/_activity_log.html.erb +2 -2
  141. data/app/views/users/_contributions.html.erb +6 -2
  142. data/app/views/users/_follower_modal.html.erb +2 -2
  143. data/app/views/users/_following_modal.html.erb +2 -2
  144. data/app/views/users/_left_sidebar.html.erb +1 -1
  145. data/app/views/users/_notify_link.html.erb +1 -1
  146. data/app/views/users/_notify_number.html.erb +1 -1
  147. data/app/views/users/_profile_actions.html.erb +3 -3
  148. data/app/views/users/_profile_tabs.html.erb +1 -1
  149. data/app/views/users/_search_form.html.erb +3 -2
  150. data/app/views/users/_social_media_info.html.erb +3 -3
  151. data/app/views/users/_trophy_edit.html.erb +2 -2
  152. data/app/views/users/_user_info.html.erb +27 -27
  153. data/app/views/users/_vitals.html.erb +2 -2
  154. data/app/views/users/edit.html.erb +39 -39
  155. data/app/views/users/index.html.erb +3 -3
  156. data/app/views/users/show.html.erb +7 -9
  157. data/config/locales/sufia.en.yml +15 -7
  158. data/config/routes.rb +12 -9
  159. data/lib/generators/sufia/sufia_generator.rb +18 -15
  160. data/lib/generators/sufia/templates/catalog_controller.rb +11 -73
  161. data/lib/generators/sufia/templates/config/tinymce.yml +7 -0
  162. data/lib/sufia.rb +7 -0
  163. data/lib/sufia/downloads_controller_behavior.rb +3 -4
  164. data/lib/sufia/files_controller_behavior.rb +38 -27
  165. data/lib/sufia/version.rb +1 -1
  166. data/spec/controllers/batch_controller_spec.rb +1 -1
  167. data/spec/controllers/batch_edits_controller_spec.rb +5 -5
  168. data/spec/controllers/catalog_controller_spec.rb +37 -58
  169. data/spec/controllers/content_blocks_controller_spec.rb +37 -0
  170. data/spec/controllers/downloads_controller_spec.rb +3 -11
  171. data/spec/controllers/featured_work_lists_controller_spec.rb +20 -0
  172. data/spec/controllers/featured_works_controller_spec.rb +50 -0
  173. data/spec/controllers/generic_files_controller_spec.rb +74 -9
  174. data/spec/controllers/mailbox_controller_spec.rb +1 -1
  175. data/spec/controllers/pages_controller_spec.rb +25 -0
  176. data/spec/controllers/single_use_links_controller_spec.rb +1 -1
  177. data/spec/controllers/single_use_links_viewer_controller_spec.rb +1 -1
  178. data/spec/controllers/tinymce_assets_controller_spec.rb +39 -0
  179. data/spec/controllers/users_controller_spec.rb +3 -8
  180. data/spec/factories/content_blocks.rb +4 -0
  181. data/spec/factories/featured_works.rb +4 -0
  182. data/spec/factories/generic_files.rb +46 -39
  183. data/spec/factories/users.rb +18 -18
  184. data/spec/features/browse_dashboard_files_spec.rb +6 -7
  185. data/spec/features/browse_files_spec.rb +9 -6
  186. data/spec/features/cloud_upload_spec.rb +18 -0
  187. data/spec/features/single_use_links_spec.rb +2 -3
  188. data/spec/helpers/content_block_helper_spec.rb +31 -0
  189. data/spec/helpers/generic_file_helper_spec.rb +3 -3
  190. data/spec/helpers/sufia_helper_spec.rb +13 -81
  191. data/spec/helpers/trophy_helper_spec.rb +39 -0
  192. data/spec/jobs/import_url_job_spec.rb +1 -1
  193. data/spec/jobs/ingest_local_file_job_spec.rb +1 -1
  194. data/spec/lib/sufia/usage_statistics_spec.rb +75 -0
  195. data/spec/models/ability_spec.rb +31 -0
  196. data/spec/models/active_fedora_pid_based_job_spec.rb +1 -1
  197. data/spec/models/audit_job_spec.rb +1 -1
  198. data/spec/models/batch_spec.rb +1 -1
  199. data/spec/models/batch_update_job_spec.rb +1 -1
  200. data/spec/models/event_jobs_spec.rb +1 -1
  201. data/spec/models/featured_work_list_spec.rb +23 -0
  202. data/spec/models/featured_work_spec.rb +42 -0
  203. data/spec/models/fits_datastream_spec.rb +2 -2
  204. data/spec/models/generic_file/reload_on_save_spec.rb +1 -1
  205. data/spec/models/generic_file/web_form_spec.rb +4 -4
  206. data/spec/models/generic_file_spec.rb +41 -40
  207. data/spec/models/pageview.rb +19 -0
  208. data/spec/models/properties_datastream_spec.rb +2 -2
  209. data/spec/models/solr_document_spec.rb +9 -0
  210. data/spec/models/user_spec.rb +2 -2
  211. data/spec/routing/featured_works_route_spec.rb +16 -0
  212. data/spec/routing/route_spec.rb +10 -15
  213. data/spec/spec_helper.rb +3 -0
  214. data/spec/support/lib/generators/test_app_generator.rb +19 -8
  215. data/spec/views/dashboard/facet_limit.html.erb_spec.rb +2 -2
  216. data/spec/views/generic_file/show.html.erb_spec.rb +44 -0
  217. data/spec/views/generic_file/stats.html.erb_spec.rb +47 -0
  218. data/spec/views/users/_follower_modal.html.erb_spec.rb +18 -0
  219. data/spec/views/users/_following_modal.html.erb_spec.rb +18 -0
  220. data/spec/views/users/index.html.erb_spec.rb +1 -1
  221. data/sufia-models/app/models/batch.rb +1 -1
  222. data/sufia-models/app/models/concerns/sufia/properties_datastream_behavior.rb +30 -0
  223. data/sufia-models/app/models/concerns/sufia/user.rb +1 -1
  224. data/sufia-models/app/models/datastreams/batch_rdf_datastream.rb +4 -7
  225. data/sufia-models/app/models/datastreams/fits_datastream.rb +3 -0
  226. data/sufia-models/app/models/datastreams/generic_file_rdf_datastream.rb +53 -51
  227. data/sufia-models/app/models/datastreams/properties_datastream.rb +1 -15
  228. data/sufia-models/app/models/featured_work.rb +22 -0
  229. data/sufia-models/app/models/sufia/pageview.rb +9 -0
  230. data/sufia-models/{lib/sufia/models → app/services/sufia}/id_service.rb +0 -0
  231. data/sufia-models/{lib/sufia/models → app/services/sufia}/noid.rb +0 -0
  232. data/sufia-models/app/services/sufia/usage_statistics.rb +73 -0
  233. data/sufia-models/config/locales/sufia.en.yml +3 -4
  234. data/sufia-models/lib/generators/sufia/models/install_generator.rb +23 -8
  235. data/sufia-models/lib/generators/sufia/models/templates/config/analytics.yml +9 -0
  236. data/sufia-models/lib/generators/sufia/models/templates/config/mime_types.rb +6 -0
  237. data/sufia-models/lib/generators/sufia/models/templates/config/sufia.rb +11 -2
  238. data/sufia-models/lib/generators/sufia/models/templates/migrations/create_content_blocks.rb +10 -0
  239. data/sufia-models/lib/generators/sufia/models/templates/migrations/create_featured_works.rb +12 -0
  240. data/sufia-models/lib/generators/sufia/models/templates/migrations/create_tinymce_assets.rb +8 -0
  241. data/sufia-models/lib/generators/sufia/models/usagestats_generator.rb +19 -0
  242. data/sufia-models/lib/sufia/ability.rb +34 -0
  243. data/sufia-models/lib/sufia/models/engine.rb +5 -3
  244. data/sufia-models/lib/sufia/models/generic_file.rb +4 -2
  245. data/sufia-models/lib/sufia/models/generic_file/export.rb +3 -3
  246. data/sufia-models/lib/sufia/models/generic_file/featured.rb +14 -0
  247. data/sufia-models/lib/sufia/models/solr_document_behavior.rb +11 -4
  248. data/sufia-models/lib/sufia/models/version.rb +1 -1
  249. data/sufia-models/sufia-models.gemspec +6 -5
  250. data/sufia.gemspec +6 -4
  251. data/tasks/release.rake +1 -0
  252. data/tasks/sufia-dev.rake +5 -1
  253. data/vendor/assets/javascripts/flot/excanvas.js +1428 -0
  254. data/vendor/assets/javascripts/flot/jquery.flot.js +3137 -0
  255. data/vendor/assets/javascripts/flot/jquery.flot.selection.js +360 -0
  256. data/vendor/assets/javascripts/flot/jquery.flot.time.js +431 -0
  257. data/vendor/assets/javascripts/nestable.js +647 -0
  258. data/vendor/assets/javascripts/video.js +135 -126
  259. data/{app → vendor}/assets/stylesheets/video-js.css.erb +7 -6
  260. metadata +155 -33
  261. data/app/assets/stylesheets/application-bootstrap.css.erb +0 -295
  262. data/app/assets/stylesheets/audio-js.css +0 -3
  263. data/app/assets/stylesheets/blacklight_more_facets.css +0 -427
  264. data/app/assets/stylesheets/bootstrap.min.css.erb +0 -1433
  265. data/app/assets/stylesheets/contact_form.css +0 -4
  266. data/app/assets/stylesheets/reset_body.css +0 -4
  267. data/app/assets/stylesheets/trophy.css +0 -7
  268. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +0 -84
  269. data/app/helpers/facets_helper.rb +0 -3
  270. data/app/helpers/sufia/facets_helper_behavior.rb +0 -23
  271. data/app/views/catalog/_home_text.html.erb +0 -10
  272. data/app/views/generic_files/_dropbox_import.html.erb +0 -3
  273. data/app/views/generic_files/upload/_dropbox_chooser.html.erb +0 -39
  274. data/app/views/static/about.html.erb +0 -21
  275. data/spec/helpers/render_constraints_helper_behavior_spec.rb +0 -42
@@ -0,0 +1,647 @@
1
+ /*!
2
+ * This fork from: http://github.com/sul-dlss/Nestable
3
+ *
4
+ * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
5
+ * Dual-licensed under the BSD or MIT licenses
6
+ */
7
+ ;(function($, window, document, undefined)
8
+ {
9
+ var hasTouch = 'ontouchstart' in window;
10
+ var nestableCopy;
11
+
12
+ /**
13
+ * Detect CSS pointer-events property
14
+ * events are normally disabled on the dragging element to avoid conflicts
15
+ * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
16
+ */
17
+ var hasPointerEvents = (function()
18
+ {
19
+ var el = document.createElement('div'),
20
+ docEl = document.documentElement;
21
+ if (!('pointerEvents' in el.style)) {
22
+ return false;
23
+ }
24
+ el.style.pointerEvents = 'auto';
25
+ el.style.pointerEvents = 'x';
26
+ docEl.appendChild(el);
27
+ var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto';
28
+ docEl.removeChild(el);
29
+ return !!supports;
30
+ })();
31
+
32
+ var eStart = hasTouch ? 'touchstart' : 'mousedown',
33
+ eMove = hasTouch ? 'touchmove' : 'mousemove',
34
+ eEnd = hasTouch ? 'touchend' : 'mouseup',
35
+ eCancel = hasTouch ? 'touchcancel' : 'mouseup';
36
+
37
+ var defaults = {
38
+ listNodeName : 'ol',
39
+ itemNodeName : 'li',
40
+ rootClass : 'dd',
41
+ listClass : 'dd-list',
42
+ itemClass : 'dd-item',
43
+ dragClass : 'dd-dragel',
44
+ handleClass : 'dd-handle',
45
+ collapsedClass : 'dd-collapsed',
46
+ placeClass : 'dd-placeholder',
47
+ noDragClass : 'dd-nodrag',
48
+ noChildrenClass : 'dd-nochildren',
49
+ emptyClass : 'dd-empty',
50
+ expandBtnHTML : '<button data-action="expand" type="button">Expand</button>',
51
+ collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>',
52
+ group : 0,
53
+ maxDepth : 5,
54
+ threshold : 20,
55
+ reject : [],
56
+ //method for call when an item has been successfully dropped
57
+ //method has 1 argument in which sends an object containing all
58
+ //necessary details
59
+ dropCallback : null,
60
+ // When a node is dragged it is moved to its new location.
61
+ // You can set the next option to true to create a copy of the node that is dragged.
62
+ cloneNodeOnDrag : false,
63
+ // When the node is dragged and released outside its list delete it.
64
+ dragOutsideToDelete : false
65
+ };
66
+
67
+ function Plugin(element, options)
68
+ {
69
+ this.w = $(document);
70
+ this.el = $(element);
71
+ this.options = $.extend({}, defaults, options);
72
+ this.init();
73
+ }
74
+
75
+ Plugin.prototype = {
76
+
77
+ init: function()
78
+ {
79
+ var list = this;
80
+
81
+ list.reset();
82
+
83
+ list.el.data('nestable-group', this.options.group);
84
+
85
+ list.placeEl = $('<div class="' + list.options.placeClass + '"/>');
86
+
87
+ $.each(this.el.find(list.options.itemNodeName), function(k, el) {
88
+ list.setParent($(el));
89
+ });
90
+
91
+ list.el.on('click', 'button', function(e)
92
+ {
93
+ if (list.dragEl || (!hasTouch && e.button !== 0)) {
94
+ return;
95
+ }
96
+ var target = $(e.currentTarget),
97
+ action = target.data('action'),
98
+ item = target.parent(list.options.itemNodeName);
99
+ if (action === 'collapse') {
100
+ list.collapseItem(item);
101
+ }
102
+ if (action === 'expand') {
103
+ list.expandItem(item);
104
+ }
105
+ });
106
+
107
+ var onStartEvent = function(e)
108
+ {
109
+ var handle = $(e.target);
110
+
111
+ list.nestableCopy = handle.closest('.'+list.options.rootClass).clone(true);
112
+
113
+ if (!handle.hasClass(list.options.handleClass)) {
114
+ if (handle.closest('.' + list.options.noDragClass).length) {
115
+ return;
116
+ }
117
+ handle = handle.closest('.' + list.options.handleClass);
118
+ }
119
+ if (!handle.length || list.dragEl || (!hasTouch && e.which !== 1) || (hasTouch && e.touches.length !== 1)) {
120
+ return;
121
+ }
122
+ e.preventDefault();
123
+ list.dragStart(hasTouch ? e.touches[0] : e);
124
+ };
125
+
126
+ var onMoveEvent = function(e)
127
+ {
128
+ if (list.dragEl) {
129
+ e.preventDefault();
130
+ list.dragMove(hasTouch ? e.touches[0] : e);
131
+ }
132
+ };
133
+
134
+ var onEndEvent = function(e)
135
+ {
136
+ if (list.dragEl) {
137
+ e.preventDefault();
138
+ list.dragStop(hasTouch ? e.touches[0] : e);
139
+ }
140
+ };
141
+
142
+ if (hasTouch) {
143
+ list.el[0].addEventListener(eStart, onStartEvent, false);
144
+ window.addEventListener(eMove, onMoveEvent, false);
145
+ window.addEventListener(eEnd, onEndEvent, false);
146
+ window.addEventListener(eCancel, onEndEvent, false);
147
+ } else {
148
+ list.el.on(eStart, onStartEvent);
149
+ list.w.on(eMove, onMoveEvent);
150
+ list.w.on(eEnd, onEndEvent);
151
+ }
152
+
153
+ var destroyNestable = function()
154
+ {
155
+ if (hasTouch) {
156
+ list.el[0].removeEventListener(eStart, onStartEvent, false);
157
+ window.removeEventListener(eMove, onMoveEvent, false);
158
+ window.removeEventListener(eEnd, onEndEvent, false);
159
+ window.removeEventListener(eCancel, onEndEvent, false);
160
+ } else {
161
+ list.el.off(eStart, onStartEvent);
162
+ list.w.off(eMove, onMoveEvent);
163
+ list.w.off(eEnd, onEndEvent);
164
+ }
165
+
166
+ list.el.off('click');
167
+ list.el.unbind('destroy-nestable');
168
+
169
+ list.el.data("nestable", null);
170
+
171
+ var buttons = list.el[0].getElementsByTagName('button');
172
+
173
+ $(buttons).remove();
174
+ };
175
+
176
+ list.el.bind('destroy-nestable', destroyNestable);
177
+ },
178
+
179
+ destroy: function ()
180
+ {
181
+ this.expandAll();
182
+ this.el.trigger('destroy-nestable');
183
+ },
184
+
185
+ serialize: function()
186
+ {
187
+ var data,
188
+ depth = 0,
189
+ list = this;
190
+ step = function(level, depth)
191
+ {
192
+ var array = [ ],
193
+ items = level.children(list.options.itemNodeName);
194
+ items.each(function()
195
+ {
196
+ var li = $(this),
197
+ item = $.extend({}, li.data()),
198
+ sub = li.children(list.options.listNodeName);
199
+ if (sub.length) {
200
+ item.children = step(sub, depth + 1);
201
+ }
202
+ array.push(item);
203
+ });
204
+ return array;
205
+ };
206
+ var el;
207
+
208
+ if (list.el.is(list.options.listNodeName)) {
209
+ el = list.el;
210
+ } else {
211
+ el = list.el.find(list.options.listNodeName).first();
212
+ }
213
+ data = step(el, depth);
214
+ return data;
215
+ },
216
+
217
+ reset: function()
218
+ {
219
+ this.mouse = {
220
+ offsetX : 0,
221
+ offsetY : 0,
222
+ startX : 0,
223
+ startY : 0,
224
+ lastX : 0,
225
+ lastY : 0,
226
+ nowX : 0,
227
+ nowY : 0,
228
+ distX : 0,
229
+ distY : 0,
230
+ dirAx : 0,
231
+ dirX : 0,
232
+ dirY : 0,
233
+ lastDirX : 0,
234
+ lastDirY : 0,
235
+ distAxX : 0,
236
+ distAxY : 0
237
+ };
238
+ this.moving = false;
239
+ this.dragEl = null;
240
+ this.dragRootEl = null;
241
+ this.dragDepth = 0;
242
+ this.dragItem = null;
243
+ this.hasNewRoot = false;
244
+ this.pointEl = null;
245
+ this.sourceRoot = null;
246
+ this.isOutsideRoot = false;
247
+ },
248
+
249
+ expandItem: function(li)
250
+ {
251
+ li.removeClass(this.options.collapsedClass);
252
+ li.children('[data-action="expand"]').hide();
253
+ li.children('[data-action="collapse"]').show();
254
+ li.children(this.options.listNodeName).show();
255
+ this.el.trigger('expand', [li]);
256
+ li.trigger('expand');
257
+ },
258
+
259
+ collapseItem: function(li)
260
+ {
261
+ var lists = li.children(this.options.listNodeName);
262
+ if (lists.length) {
263
+ li.addClass(this.options.collapsedClass);
264
+ li.children('[data-action="collapse"]').hide();
265
+ li.children('[data-action="expand"]').show();
266
+ li.children(this.options.listNodeName).hide();
267
+ }
268
+ this.el.trigger('collapse', [li]);
269
+ li.trigger('collapse');
270
+ },
271
+
272
+ expandAll: function()
273
+ {
274
+ var list = this;
275
+ list.el.find(list.options.itemNodeName).each(function() {
276
+ list.expandItem($(this));
277
+ });
278
+ },
279
+
280
+ collapseAll: function()
281
+ {
282
+ var list = this;
283
+ list.el.find(list.options.itemNodeName).each(function() {
284
+ list.collapseItem($(this));
285
+ });
286
+ },
287
+
288
+ setParent: function(li)
289
+ {
290
+ if (li.children(this.options.listNodeName).length) {
291
+ li.prepend($(this.options.expandBtnHTML));
292
+ li.prepend($(this.options.collapseBtnHTML));
293
+ }
294
+ if( (' ' + li[0].className + ' ').indexOf(' ' + defaults.collapsedClass + ' ') > -1 )
295
+ {
296
+ li.children('[data-action="collapse"]').hide();
297
+ } else {
298
+ li.children('[data-action="expand"]').hide();
299
+ }
300
+ },
301
+
302
+ unsetParent: function(li)
303
+ {
304
+ li.removeClass(this.options.collapsedClass);
305
+ li.children('[data-action]').remove();
306
+ li.children(this.options.listNodeName).remove();
307
+ },
308
+
309
+ dragStart: function(e)
310
+ {
311
+ var mouse = this.mouse,
312
+ target = $(e.target),
313
+ dragItem = target.closest('.' + this.options.handleClass).closest(this.options.itemNodeName);
314
+
315
+ this.sourceRoot = target.closest('.' + this.options.rootClass);
316
+
317
+ this.dragItem = dragItem;
318
+
319
+ this.placeEl.css('height', dragItem.height());
320
+
321
+ mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left;
322
+ mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top;
323
+ mouse.startX = mouse.lastX = e.pageX;
324
+ mouse.startY = mouse.lastY = e.pageY;
325
+
326
+ this.dragRootEl = this.el;
327
+
328
+ this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass);
329
+ this.dragEl.css('width', dragItem.width());
330
+
331
+ // fix for zepto.js
332
+ //dragItem.after(this.placeEl).detach().appendTo(this.dragEl);
333
+ if(this.options.cloneNodeOnDrag) {
334
+ dragItem.after(dragItem.clone());
335
+ } else {
336
+ dragItem.after(this.placeEl);
337
+ }
338
+ dragItem[0].parentNode.removeChild(dragItem[0]);
339
+ dragItem.appendTo(this.dragEl);
340
+
341
+ $(document.body).append(this.dragEl);
342
+ this.dragEl.css({
343
+ 'left' : e.pageX - mouse.offsetX,
344
+ 'top' : e.pageY - mouse.offsetY
345
+ });
346
+ // total depth of dragging item
347
+ var i, depth,
348
+ items = this.dragEl.find(this.options.itemNodeName);
349
+ for (i = 0; i < items.length; i++) {
350
+ depth = $(items[i]).parents(this.options.listNodeName).length;
351
+ if (depth > this.dragDepth) {
352
+ this.dragDepth = depth;
353
+ }
354
+ }
355
+ },
356
+
357
+ dragStop: function(e)
358
+ {
359
+ // fix for zepto.js
360
+ //this.placeEl.replaceWith(this.dragEl.children(this.options.itemNodeName + ':first').detach());
361
+ var el = this.dragEl.children(this.options.itemNodeName).first();
362
+ el[0].parentNode.removeChild(el[0]);
363
+
364
+ if(this.isOutsideRoot && this.options.dragOutsideToDelete)
365
+ {
366
+ var parent = this.placeEl.parent();
367
+ this.placeEl.remove();
368
+ if (!parent.children().length) {
369
+ this.unsetParent(parent.parent());
370
+ }
371
+ // If all nodes where deleted, create a placeholder element.
372
+ if (!this.dragRootEl.find(this.options.itemNodeName).length)
373
+ {
374
+ this.dragRootEl.append('<div class="' + this.options.emptyClass + '"/>');
375
+ }
376
+ }
377
+ else
378
+ {
379
+ this.placeEl.replaceWith(el);
380
+ }
381
+
382
+ if (!this.moving)
383
+ {
384
+ $(this.dragItem).trigger('click');
385
+ }
386
+
387
+ var i;
388
+ var isRejected = false;
389
+ for (i in this.options.reject)
390
+ {
391
+ var reject = this.options.reject[i];
392
+ if (reject.rule.apply(this.dragRootEl))
393
+ {
394
+ var nestableDragEl = el.clone(true);
395
+ this.dragRootEl.html(this.nestableCopy.children().clone(true));
396
+ if (reject.action) {
397
+ reject.action.apply(this.dragRootEl, [nestableDragEl]);
398
+ }
399
+
400
+ isRejected = true;
401
+ break;
402
+ }
403
+ }
404
+
405
+ if (!isRejected)
406
+ {
407
+ this.dragEl.remove();
408
+ this.el.trigger('change');
409
+
410
+ //Let's find out new parent id
411
+ var parentItem = el.parent().parent();
412
+ var parentId = null;
413
+ if(parentItem !== null && !parentItem.is('.' + this.options.rootClass))
414
+ parentId = parentItem.data('id');
415
+
416
+ if($.isFunction(this.options.dropCallback))
417
+ {
418
+ var details = {
419
+ sourceId : el.data('id'),
420
+ destId : parentId,
421
+ sourceEl : el,
422
+ destParent : parentItem,
423
+ destRoot : el.closest('.' + this.options.rootClass),
424
+ sourceRoot : this.sourceRoot
425
+ };
426
+ this.options.dropCallback.call(this, details);
427
+ }
428
+
429
+ if (this.hasNewRoot) {
430
+ this.dragRootEl.trigger('change');
431
+ }
432
+
433
+ this.reset();
434
+ }
435
+ },
436
+
437
+ dragMove: function(e)
438
+ {
439
+ var list, parent, prev, next, depth,
440
+ opt = this.options,
441
+ mouse = this.mouse;
442
+
443
+ this.dragEl.css({
444
+ 'left' : e.pageX - mouse.offsetX,
445
+ 'top' : e.pageY - mouse.offsetY
446
+ });
447
+
448
+ // mouse position last events
449
+ mouse.lastX = mouse.nowX;
450
+ mouse.lastY = mouse.nowY;
451
+ // mouse position this events
452
+ mouse.nowX = e.pageX;
453
+ mouse.nowY = e.pageY;
454
+ // distance mouse moved between events
455
+ mouse.distX = mouse.nowX - mouse.lastX;
456
+ mouse.distY = mouse.nowY - mouse.lastY;
457
+ // direction mouse was moving
458
+ mouse.lastDirX = mouse.dirX;
459
+ mouse.lastDirY = mouse.dirY;
460
+ // direction mouse is now moving (on both axis)
461
+ mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
462
+ mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
463
+ // axis mouse is now moving on
464
+ var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
465
+
466
+ // do nothing on first move
467
+ if (!this.moving) {
468
+ mouse.dirAx = newAx;
469
+ this.moving = true;
470
+ return;
471
+ }
472
+
473
+ // calc distance moved on this axis (and direction)
474
+ if (mouse.dirAx !== newAx) {
475
+ mouse.distAxX = 0;
476
+ mouse.distAxY = 0;
477
+ } else {
478
+ mouse.distAxX += Math.abs(mouse.distX);
479
+ if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
480
+ mouse.distAxX = 0;
481
+ }
482
+ mouse.distAxY += Math.abs(mouse.distY);
483
+ if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
484
+ mouse.distAxY = 0;
485
+ }
486
+ }
487
+ mouse.dirAx = newAx;
488
+
489
+ /**
490
+ * move horizontal
491
+ */
492
+ if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
493
+ // reset move distance on x-axis for new phase
494
+ mouse.distAxX = 0;
495
+ prev = this.placeEl.prev(opt.itemNodeName);
496
+ // increase horizontal level if previous sibling exists and is not collapsed
497
+ if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass) && !prev.hasClass(opt.noChildrenClass)) {
498
+ // cannot increase level when item above is collapsed
499
+ list = prev.find(opt.listNodeName).last();
500
+ // check if depth limit has reached
501
+ depth = this.placeEl.parents(opt.listNodeName).length;
502
+ if (depth + this.dragDepth <= opt.maxDepth) {
503
+ // create new sub-level if one doesn't exist
504
+ if (!list.length) {
505
+ list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
506
+ list.append(this.placeEl);
507
+ prev.append(list);
508
+ this.setParent(prev);
509
+ } else {
510
+ // else append to next level up
511
+ list = prev.children(opt.listNodeName).last();
512
+ list.append(this.placeEl);
513
+ }
514
+ }
515
+ }
516
+ // decrease horizontal level
517
+ if (mouse.distX < 0) {
518
+ // we can't decrease a level if an item preceeds the current one
519
+ next = this.placeEl.next(opt.itemNodeName);
520
+ if (!next.length) {
521
+ parent = this.placeEl.parent();
522
+ this.placeEl.closest(opt.itemNodeName).after(this.placeEl);
523
+ if (!parent.children().length) {
524
+ this.unsetParent(parent.parent());
525
+ }
526
+ }
527
+ }
528
+ }
529
+
530
+ var isEmpty = false;
531
+
532
+ // find list item under cursor
533
+ if (!hasPointerEvents) {
534
+ this.dragEl[0].style.visibility = 'hidden';
535
+ }
536
+
537
+ this.pointEl = $(document.elementFromPoint(e.pageX - document.documentElement.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop)));
538
+
539
+ // Check if the node is dragged outside of its list.
540
+ if(this.dragRootEl.has(this.pointEl).length) {
541
+ this.isOutsideRoot = false;
542
+ this.dragEl[0].style.opacity = 1;
543
+ } else {
544
+ this.isOutsideRoot = true;
545
+ this.dragEl[0].style.opacity = 0.5;
546
+ }
547
+
548
+ // find parent list of item under cursor
549
+ var pointElRoot = this.pointEl.closest('.' + opt.rootClass),
550
+ isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
551
+
552
+ this.isOutsideRoot = !pointElRoot.length;
553
+
554
+ if (!hasPointerEvents) {
555
+ this.dragEl[0].style.visibility = 'visible';
556
+ }
557
+ if (this.pointEl.hasClass(opt.handleClass)) {
558
+ this.pointEl = this.pointEl.closest( opt.itemNodeName );
559
+ }
560
+
561
+ if (opt.maxDepth == 1 && !this.pointEl.hasClass(opt.itemClass)) {
562
+ this.pointEl = this.pointEl.closest("." + opt.itemClass);
563
+ }
564
+
565
+ if (this.pointEl.hasClass(opt.emptyClass)) {
566
+ isEmpty = true;
567
+ }
568
+ else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
569
+ return;
570
+ }
571
+
572
+ /**
573
+ * move vertical
574
+ */
575
+ if (!mouse.dirAx || isNewRoot || isEmpty) {
576
+ // check if groups match if dragging over new root
577
+ if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
578
+ return;
579
+ }
580
+ // check depth limit
581
+ depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
582
+ if (depth > opt.maxDepth) {
583
+ return;
584
+ }
585
+ var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
586
+ parent = this.placeEl.parent();
587
+ // if empty create new list to replace empty placeholder
588
+ if (isEmpty) {
589
+ list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
590
+ list.append(this.placeEl);
591
+ this.pointEl.replaceWith(list);
592
+ }
593
+ else if (before) {
594
+ this.pointEl.before(this.placeEl);
595
+ }
596
+ else {
597
+ this.pointEl.after(this.placeEl);
598
+ }
599
+ if (!parent.children().length) {
600
+ this.unsetParent(parent.parent());
601
+ }
602
+ if (!this.dragRootEl.find(opt.itemNodeName).length) {
603
+ this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>');
604
+ }
605
+ // parent root list has changed
606
+ this.dragRootEl = pointElRoot;
607
+ if (isNewRoot) {
608
+ this.hasNewRoot = this.el[0] !== this.dragRootEl[0];
609
+ }
610
+ }
611
+ }
612
+
613
+ };
614
+
615
+ $.fn.nestable = function(params)
616
+ {
617
+ var lists = this,
618
+ retval = this;
619
+
620
+ var generateUid = function (separator) {
621
+ var delim = separator || "-";
622
+
623
+ function S4() {
624
+ return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
625
+ }
626
+
627
+ return (S4() + S4() + delim + S4() + delim + S4() + delim + S4() + delim + S4() + S4() + S4());
628
+ };
629
+
630
+ lists.each(function()
631
+ {
632
+ var plugin = $(this).data("nestable");
633
+
634
+ if (!plugin) {
635
+ $(this).data("nestable", new Plugin(this, params));
636
+ $(this).data("nestable-id", generateUid());
637
+ } else {
638
+ if (typeof params === 'string' && typeof plugin[params] === 'function') {
639
+ retval = plugin[params]();
640
+ }
641
+ }
642
+ });
643
+
644
+ return retval || lists;
645
+ };
646
+
647
+ })(window.jQuery || window.Zepto, window, document);