NEXT craftinamerica.org. Base setup for headless wordpress https://www.craftinamerica.org
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. (function() {
  2. var Candidate, Candidates, CandidatesView, Connection, Connections, ConnectionsView, CreatePostView, ENTER_KEY, MetaboxView, get_mustache_template, remove_row, row_wait;
  3. ENTER_KEY = 13;
  4. row_wait = function($td) {
  5. return $td.find('.p2p-icon').css('background-image', 'url(' + P2PAdminL10n.spinner + ')');
  6. };
  7. remove_row = function($td) {
  8. var $table;
  9. $table = $td.closest('table');
  10. $td.closest('tr').remove();
  11. if (!$table.find('tbody tr').length) {
  12. return $table.hide();
  13. }
  14. };
  15. get_mustache_template = function(name) {
  16. return jQuery('#p2p-template-' + name).html();
  17. };
  18. // Class for representing a single connection candidate
  19. Candidate = Backbone.Model.extend({});
  20. // Class for representing a single connection
  21. Connection = Backbone.Model.extend({});
  22. // Class for holding search parameters; not really a model
  23. Candidates = Backbone.Model.extend({
  24. // (Re)perform a search with the current parameters
  25. sync: function() {
  26. var params, _this = this;
  27. params = {
  28. subaction: 'search'
  29. };
  30. return this.ajax_request(params, function(response) {
  31. var _ref = response.navigation;
  32. _this.total_pages = (_ref ? _ref['total-pages-raw'] : void 0) || 1;
  33. _this.trigger('sync', response);
  34. });
  35. },
  36. // Validation function, called by Backbone when parameters are changed
  37. validate: function(attrs) {
  38. var _ref = attrs.paged;
  39. if (0 < _ref && _ref <= this.total_pages) {
  40. return null;
  41. }
  42. return 'invalid page';
  43. }
  44. });
  45. // Class for holding a list of connections
  46. Connections = Backbone.Collection.extend({
  47. model: Connection,
  48. // Create both a candidate item and a connection
  49. createItemAndConnect: function(title) {
  50. var data, _this = this;
  51. data = {
  52. subaction: 'create_post',
  53. post_title: title
  54. };
  55. return this.ajax_request(data, function(response) {
  56. _this.trigger('create', response);
  57. });
  58. },
  59. // Create a connection from a candidate
  60. create: function(candidate) {
  61. var data, _this = this;
  62. data = {
  63. subaction: 'connect',
  64. to: candidate.get('id')
  65. };
  66. return this.ajax_request(data, function(response) {
  67. _this.trigger('create', response);
  68. });
  69. },
  70. // Delete a connection
  71. "delete": function(connection) {
  72. var data, _this = this;
  73. data = {
  74. subaction: 'disconnect',
  75. p2p_id: connection.get('id')
  76. };
  77. return this.ajax_request(data, function(response) {
  78. _this.trigger('delete', response, connection);
  79. });
  80. },
  81. // Delete all connections
  82. clear: function() {
  83. var data, _this = this;
  84. data = {
  85. subaction: 'clear_connections'
  86. };
  87. return this.ajax_request(data, function(response) {
  88. _this.trigger('clear', response);
  89. });
  90. }
  91. });
  92. // View responsible for the connection list
  93. ConnectionsView = Backbone.View.extend({
  94. events: {
  95. 'click th.p2p-col-delete .p2p-icon': 'clear',
  96. 'click td.p2p-col-delete .p2p-icon': 'delete'
  97. },
  98. initialize: function(options) {
  99. this.options = options;
  100. this.maybe_make_sortable();
  101. this.collection.on('create', this.afterCreate, this);
  102. this.collection.on('clear', this.afterClear, this);
  103. },
  104. maybe_make_sortable: function() {
  105. if (this.$('th.p2p-col-order').length) {
  106. this.$('tbody').sortable({
  107. handle: 'td.p2p-col-order',
  108. helper: function(e, ui) {
  109. ui.children().each(function() {
  110. var $this;
  111. $this = jQuery(this);
  112. $this.width($this.width());
  113. });
  114. return ui;
  115. }
  116. });
  117. }
  118. },
  119. clear: function(ev) {
  120. var $td;
  121. ev.preventDefault();
  122. if (!confirm(P2PAdminL10n.deleteConfirmMessage)) {
  123. return;
  124. }
  125. $td = jQuery(ev.target).closest('td');
  126. row_wait($td);
  127. this.collection.clear();
  128. },
  129. afterClear: function() {
  130. this.$el.hide().find('tbody').html('');
  131. },
  132. "delete": function(ev) {
  133. var $td, req;
  134. ev.preventDefault();
  135. $td = jQuery(ev.target).closest('td');
  136. row_wait($td);
  137. req = this.collection["delete"](new Connection({
  138. id: $td.find('input').val()
  139. }));
  140. req.done(function() {
  141. remove_row($td);
  142. });
  143. },
  144. afterCreate: function(response) {
  145. this.$el.show().find('tbody').append(response.row);
  146. this.collection.trigger('append', response);
  147. }
  148. });
  149. // View responsible for the candidate list
  150. CandidatesView = Backbone.View.extend({
  151. template: Mustache.compile(get_mustache_template('tab-list')),
  152. events: {
  153. 'keypress :text': 'handleReturn',
  154. 'keyup :text': 'handleSearch',
  155. 'click .p2p-prev, .p2p-next': 'changePage',
  156. 'click td.p2p-col-create div': 'promote'
  157. },
  158. initialize: function(options) {
  159. this.options = options;
  160. this.spinner = options.spinner;
  161. options.connections.on('delete', this.afterCandidatesRefreshed, this);
  162. options.connections.on('clear', this.afterCandidatesRefreshed, this);
  163. this.collection.on('sync', this.afterCandidatesRefreshed, this);
  164. this.collection.on('error', this.afterInvalid, this);
  165. this.collection.on('invalid', this.afterInvalid, this);
  166. },
  167. promote: function(ev) {
  168. var $td, req, _this = this;
  169. ev.preventDefault();
  170. $td = jQuery(ev.target).closest('td');
  171. row_wait($td);
  172. var candidate = new Candidate({
  173. id: $td.find('div').data('item-id')
  174. });
  175. req = this.options.connections.create(candidate);
  176. req.done(function() {
  177. if (_this.options.duplicate_connections) {
  178. $td.find('.p2p-icon').css('background-image', '');
  179. } else {
  180. remove_row($td);
  181. }
  182. });
  183. },
  184. handleReturn: function(ev) {
  185. if (ev.keyCode === ENTER_KEY) {
  186. ev.preventDefault();
  187. }
  188. },
  189. handleSearch: function(ev) {
  190. var $searchInput, delayed,
  191. _this = this;
  192. if (delayed !== void 0) {
  193. clearTimeout(delayed);
  194. }
  195. $searchInput = jQuery(ev.target);
  196. delayed = setTimeout(function() {
  197. var searchStr;
  198. searchStr = $searchInput.val();
  199. if (searchStr === _this.collection.get('s')) {
  200. return;
  201. }
  202. _this.spinner.insertAfter($searchInput).show();
  203. _this.collection.save({
  204. 's': searchStr,
  205. 'paged': 1
  206. });
  207. }, 400);
  208. },
  209. changePage: function(ev) {
  210. var $navButton, new_page;
  211. $navButton = jQuery(ev.currentTarget);
  212. new_page = this.collection.get('paged');
  213. if ($navButton.hasClass('p2p-prev')) {
  214. new_page--;
  215. } else {
  216. new_page++;
  217. }
  218. this.spinner.appendTo(this.$('.p2p-navigation'));
  219. this.collection.save('paged', new_page);
  220. },
  221. afterCandidatesRefreshed: function(response) {
  222. this.spinner.remove();
  223. this.$('button, .p2p-results, .p2p-navigation, .p2p-notice').remove();
  224. if ('string' !== typeof response) {
  225. response = this.template(response);
  226. }
  227. this.$el.append(response);
  228. },
  229. afterInvalid: function() {
  230. this.spinner.remove();
  231. }
  232. });
  233. // View responsible for the post creation UI
  234. CreatePostView = Backbone.View.extend({
  235. events: {
  236. 'click button': 'createItem',
  237. 'keypress :text': 'handleReturn'
  238. },
  239. initialize: function(options) {
  240. this.options = options;
  241. this.createButton = this.$('button');
  242. this.createInput = this.$(':text');
  243. },
  244. handleReturn: function(ev) {
  245. if (ev.keyCode === ENTER_KEY) {
  246. this.createButton.click();
  247. ev.preventDefault();
  248. }
  249. },
  250. createItem: function(ev) {
  251. var req, title, _this = this;
  252. ev.preventDefault();
  253. if (this.createButton.hasClass('inactive')) {
  254. return false;
  255. }
  256. title = this.createInput.val();
  257. if (title === '') {
  258. this.createInput.focus();
  259. return;
  260. }
  261. this.createButton.addClass('inactive');
  262. req = this.collection.createItemAndConnect(title);
  263. req.done(function() {
  264. _this.createInput.val('');
  265. _this.createButton.removeClass('inactive');
  266. });
  267. }
  268. });
  269. // View responsible for the entire metabox
  270. MetaboxView = Backbone.View.extend({
  271. events: {
  272. 'click .p2p-toggle-tabs': 'toggleTabs',
  273. 'click .wp-tab-bar li': 'setActiveTab'
  274. },
  275. initialize: function(options) {
  276. this.options = options;
  277. this.spinner = options.spinner;
  278. this.initializedCandidates = false;
  279. options.connections.on('append', this.afterConnectionAppended, this);
  280. options.connections.on('clear', this.afterConnectionDeleted, this);
  281. options.connections.on('delete', this.afterConnectionDeleted, this);
  282. },
  283. toggleTabs: function(ev) {
  284. var $tabs;
  285. ev.preventDefault();
  286. $tabs = this.$('.p2p-create-connections-tabs');
  287. $tabs.toggle();
  288. if (!this.initializedCandidates && $tabs.is(':visible')) {
  289. this.options.candidates.sync();
  290. this.initializedCandidates = true;
  291. }
  292. },
  293. setActiveTab: function(ev) {
  294. var $tab;
  295. ev.preventDefault();
  296. $tab = jQuery(ev.currentTarget);
  297. this.$('.wp-tab-bar li').removeClass('wp-tab-active');
  298. $tab.addClass('wp-tab-active');
  299. this.$el.find('.tabs-panel').hide().end().find($tab.data('ref')).show().find(':text').focus();
  300. },
  301. afterConnectionAppended: function(response) {
  302. if ('one' === this.options.cardinality) {
  303. this.$('.p2p-create-connections').hide();
  304. }
  305. },
  306. afterConnectionDeleted: function(response) {
  307. if ('one' === this.options.cardinality) {
  308. this.$('.p2p-create-connections').show();
  309. }
  310. }
  311. });
  312. window.P2PAdmin = {
  313. Candidate: Candidate,
  314. Connection: Connection,
  315. boxes: {}
  316. };
  317. jQuery(function() {
  318. // Polyfill for browsers that don't support the placeholder attribute
  319. if (!jQuery('<input placeholder="1" />')[0].placeholder) {
  320. function setVal() {
  321. var $this;
  322. $this = jQuery(this);
  323. if (!$this.val()) {
  324. $this.val($this.attr('placeholder'));
  325. $this.addClass('p2p-placeholder');
  326. }
  327. };
  328. function clearVal() {
  329. var $this;
  330. $this = jQuery(this);
  331. if ($this.hasClass('p2p-placeholder')) {
  332. $this.val('');
  333. $this.removeClass('p2p-placeholder');
  334. }
  335. };
  336. jQuery('.p2p-search input[placeholder]').each(setVal).focus(clearVal).blur(setVal);
  337. }
  338. Mustache.compilePartial('table-row', get_mustache_template('table-row'));
  339. jQuery('.p2p-box').each(function() {
  340. var $metabox, $spinner, candidates, candidatesView, connections, connectionsView, createPostView, ctype, metaboxView;
  341. $metabox = jQuery(this);
  342. $spinner = jQuery('<img>', {
  343. 'src': P2PAdminL10n.spinner,
  344. 'class': 'p2p-spinner'
  345. });
  346. candidates = new Candidates({
  347. 's': '',
  348. 'paged': 1
  349. });
  350. candidates.total_pages = $metabox.find('.p2p-total').data('num') || 1;
  351. ctype = {
  352. p2p_type: $metabox.data('p2p_type'),
  353. direction: $metabox.data('direction'),
  354. from: jQuery('#post_ID').val()
  355. };
  356. // All ajax requests should be done through this function
  357. function ajax_request(options, callback) {
  358. var params = _.extend({}, options, candidates.attributes, ctype, {
  359. action: 'p2p_box',
  360. nonce: P2PAdminL10n.nonce
  361. });
  362. return jQuery.post(ajaxurl, params, function(response) {
  363. var e;
  364. try {
  365. response = jQuery.parseJSON(response);
  366. } catch (_error) {
  367. e = _error;
  368. if (typeof console !== "undefined" && console !== null) {
  369. console.error('Malformed response', response);
  370. }
  371. return;
  372. }
  373. if (response.error) {
  374. return alert(response.error);
  375. } else {
  376. return callback(response);
  377. }
  378. });
  379. }
  380. candidates.ajax_request = ajax_request;
  381. connections = new Connections();
  382. connections.ajax_request = ajax_request;
  383. connectionsView = new ConnectionsView({
  384. el: $metabox.find('.p2p-connections'),
  385. collection: connections,
  386. candidates: candidates
  387. });
  388. candidatesView = new CandidatesView({
  389. el: $metabox.find('.p2p-tab-search'),
  390. collection: candidates,
  391. connections: connections,
  392. spinner: $spinner,
  393. duplicate_connections: $metabox.data('duplicate_connections')
  394. });
  395. createPostView = new CreatePostView({
  396. el: $metabox.find('.p2p-tab-create-post'),
  397. collection: connections
  398. });
  399. metaboxView = new MetaboxView({
  400. el: $metabox,
  401. spinner: $spinner,
  402. cardinality: $metabox.data('cardinality'),
  403. candidates: candidates,
  404. connections: connections
  405. });
  406. P2PAdmin.boxes[ctype.p2p_type] = {
  407. candidates: candidates,
  408. connections: connections
  409. };
  410. });
  411. });
  412. }());