API Docs for: 1.0.0
Show:

File: Resources/public/js/views/services/ez-serversideviewservice.js

  1. /*
  2. * Copyright (C) eZ Systems AS. All rights reserved.
  3. * For full copyright and license information view LICENSE file distributed with this source code.
  4. */
  5. YUI.add('ez-serversideviewservice', function (Y) {
  6. "use strict";
  7. /**
  8. * Provides the server side view service class
  9. *
  10. * @method ez-serversideviewservice
  11. */
  12. Y.namespace('eZ');
  13.  
  14. var PJAX_DONE_REDIRECT = 205,
  15. PJAX_LOCATION_HEADER = 'PJAX-Location',
  16. DEFAULT_HEADERS = {'X-PJAX': 'true'};
  17.  
  18. /**
  19. * The Server Side View Service class. It is meant to be used to load the
  20. * content of a server side view.
  21. *
  22. * @namespace eZ
  23. * @class ServerSideViewService
  24. * @constructor
  25. * @extends eZ.ViewService
  26. */
  27. Y.eZ.ServerSideViewService = Y.Base.create('serverSideViewService', Y.eZ.ViewService, [], {
  28. initializer: function () {
  29. this.on('*:submitForm', this._handleFormSubmit);
  30. },
  31.  
  32. /**
  33. * Handles the `submitForm` event by preventing the original form to be
  34. * submitted by the browser and by submitting the form with an AJAX
  35. * request.
  36. *
  37. * @method _handleFormSubmit
  38. * @protected
  39. * @param {EventFacade} e
  40. */
  41. _handleFormSubmit: function (e) {
  42. var form = e.form,
  43. app = this.get('app');
  44.  
  45. app.set('loading', true);
  46. e.originalEvent.preventDefault();
  47. Y.io(form.getAttribute('action'), {
  48. method: form.getAttribute('method'),
  49. headers: Y.merge(DEFAULT_HEADERS, {'Content-Type': form.get('encoding')}),
  50. data: e.formData,
  51. on: {
  52. success: Y.bind(this._handleFormSubmitResponse, this, e.target),
  53. failure: this._handleLoadFailure,
  54. },
  55. context: this,
  56. });
  57. },
  58.  
  59. /**
  60. * Handles the response of a form submission. It detects if a
  61. * redirection needs to happen in the application.
  62. *
  63. * @method _handleFormSubmitResponse
  64. * @protected
  65. * @param {Y.View} view
  66. * @param {String} tId the transaction id
  67. * @param {XMLHttpRequest} response
  68. */
  69. _handleFormSubmitResponse: function (view, tId, response) {
  70. var app = this.get('app'),
  71. pjaxLocation = response.getResponseHeader(PJAX_LOCATION_HEADER);
  72.  
  73. if ( response.status === PJAX_DONE_REDIRECT && pjaxLocation ) {
  74. app.navigate(this._getAdminRouteUri(pjaxLocation));
  75. } else {
  76. app.set('loading', false);
  77. this._updateView(view, response);
  78. }
  79. },
  80.  
  81. /**
  82. * Handles the loading error.
  83. *
  84. * @method _handleLoadFailure
  85. * @param {String} tId
  86. * @param {XMLHttpRequest} response
  87. * @protected
  88. */
  89. _handleLoadFailure: function (tId, response) {
  90. var frag = Y.Node.create(response.responseText),
  91. notificationCount,
  92. errorMsg = '';
  93.  
  94. this.get('app').set('loading', false);
  95. notificationCount = this._parseNotifications(frag);
  96. if ( notificationCount === 0 ) {
  97. errorMsg = "Failed to load '" + response.responseURL + "'";
  98. }
  99. this._error(errorMsg);
  100. },
  101.  
  102. /**
  103. * Parses the notification node(s) in the PJAX response and sends the
  104. * corresponding notify events.
  105. *
  106. * @method _parseNotifications
  107. * @param {Y.Node} docFragment
  108. * @return {Number} the number of notifications
  109. * @protected
  110. */
  111. _parseNotifications: function (docFragment) {
  112. var notifications = docFragment.all('[data-name="notification"] li');
  113.  
  114. notifications.each(this._notifyUser, this);
  115. return notifications.size();
  116. },
  117.  
  118. /**
  119. * Updates the view attributes with the provided HTTP response
  120. *
  121. * @method _updateView
  122. * @private
  123. * @param {eZ.ServerSideView} view
  124. * @param {Response} response
  125. */
  126. _updateView: function (view, response) {
  127. this._parseResponse(response);
  128. view.setAttrs({
  129. 'title': this.get('title'),
  130. 'html': this.get('html'),
  131. });
  132. },
  133.  
  134. /**
  135. * Load the content and the title of the server side view using a PJAX
  136. * like strategy, ie the server is supposed to response with an HTML
  137. * like document containing a title and the html code to use. The
  138. * loading is done, the next callback is called with the service itself
  139. * in parameter. If an error occurs, an error event is triggered.
  140. *
  141. * @method _load
  142. * @protected
  143. * @param {Function} next
  144. */
  145. _load: function (next) {
  146. var uri = this.get('app').get('apiRoot') + this.get('request').params.uri;
  147.  
  148. Y.io(uri, {
  149. method: 'GET',
  150. headers: DEFAULT_HEADERS,
  151. on: {
  152. success: function (tId, response) {
  153. this._parseResponse(response);
  154. next(this);
  155. },
  156. failure: this._handleLoadFailure,
  157. },
  158. context: this,
  159. });
  160. },
  161.  
  162. /**
  163. * Parses the server response
  164. *
  165. * @method _parseResponse
  166. * @protected
  167. * @param {Object} response
  168. */
  169. _parseResponse: function (response) {
  170. var frag = Y.Node.create(response.responseText),
  171. html, title;
  172.  
  173. html = frag.one('[data-name="html"]');
  174. title = frag.one('[data-name="title"]');
  175.  
  176. if ( html ) {
  177. this.set('html', this._rewrite(html).getContent());
  178. }
  179. if ( title ) {
  180. this.set('title', title.get('text'));
  181. }
  182.  
  183. this._parseNotifications(frag);
  184. },
  185.  
  186. /**
  187. * Rewrites the server side generated HTML so that it's browseable in
  188. * the PlatformUI application
  189. *
  190. * @method _rewrite
  191. * @protected
  192. * @param {Node} node
  193. * @return {Node}
  194. */
  195. _rewrite: function (node) {
  196. node.all('a[href]').each(function (link) {
  197. if ( !this._isPjaxLink(link) ) {
  198. return;
  199. }
  200. link.setAttribute('href', this._getAdminRouteUri(link.getAttribute('href')));
  201. }, this);
  202. return node;
  203. },
  204.  
  205. /**
  206. * Returns the URI in PlatformUI App from the PJAX URI
  207. *
  208. * @method _getAdminRouteUri
  209. * @protected
  210. * @param {String} uri
  211. * @return {String}
  212. */
  213. _getAdminRouteUri: function (uri) {
  214. var app = this.get('app'),
  215. regexp = new RegExp('^' + app.get('apiRoot'));
  216.  
  217. return app.routeUri('adminGenericRoute', {uri: uri.replace(regexp, '')});
  218. },
  219.  
  220. /**
  221. * Checks whether the link can be transformed in a PJAX link.
  222. *
  223. * @method _isPjaxLink
  224. * @protected
  225. * @param {Y.Node} link
  226. * @return {Boolean}
  227. */
  228. _isPjaxLink: function (link) {
  229. var href = link.getAttribute('href');
  230.  
  231. return (
  232. href.charAt(0) !== '#'
  233. && ( !link.hasAttribute('target') || link.getAttribute('target') === '_self' )
  234. && !href.match(/^http(s)?:\/\//)
  235. );
  236. },
  237.  
  238. /**
  239. * Fires notify event based on a notification node in the PJAX response.
  240. *
  241. * @method _notifyUser
  242. * @protected
  243. * @param {Node} node
  244. */
  245. _notifyUser: function (node) {
  246. var app = this.get('app'),
  247. timeout = 5;
  248.  
  249. if (node.getAttribute('data-state') === 'error') {
  250. timeout = 0;
  251. }
  252.  
  253. // the app is not yet a bubble target of the view service,
  254. // so we are using the app to fire the event
  255. // see https://jira.ez.no/browse/EZP-23013
  256. app.fire('notify', {
  257. notification: {
  258. text: node.getContent(),
  259. state: node.getAttribute('data-state'),
  260. timeout: timeout
  261. }
  262. });
  263. },
  264.  
  265. /**
  266. * Returns the title and the html code as an object
  267. *
  268. * @method _getViewParameters
  269. * @protected
  270. * @return {Object}
  271. */
  272. _getViewParameters: function () {
  273. return {
  274. title: this.get('title'),
  275. html: this.get('html'),
  276. };
  277. }
  278. }, {
  279. ATTRS: {
  280. /**
  281. * The title parsed from the pjax response.
  282. *
  283. * @attribute title
  284. * @default ""
  285. * @type String
  286. */
  287. title: {
  288. value: "",
  289. },
  290.  
  291. /**
  292. * The html code parsed from the pjax response.
  293. *
  294. * @attribute html
  295. * @default ""
  296. * @type String
  297. */
  298. html: {
  299. value: ""
  300. },
  301. }
  302. });
  303. });
  304.