PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/sandbox/wp-content/plugins/event-organiser-pro/admin/js/booking-form.js

https://bitbucket.org/stephenharris/stephenharris
JavaScript | 1776 lines | 1587 code | 169 blank | 20 comment | 73 complexity | 4c18e4a56d54c7df7cfce1aaace9ea1e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. if ( typeof EO_SCRIPT_DEBUG === 'undefined') { EO_SCRIPT_DEBUG = true;}
  2. (function($) {
  3. if( EO_SCRIPT_DEBUG ){
  4. console.log(eo);
  5. }
  6. var formCustomiser = eo.bfc = {
  7. Model: {},
  8. View: {},
  9. Collection: {},
  10. };
  11. eo.gettext = function( msgid ){
  12. if( this.locale[msgid] !== undefined ){
  13. return this.locale[msgid];
  14. }
  15. return msgid;
  16. };
  17. eo.error_handler = function( model, response ){
  18. if( 200 != response.status ){
  19. alert( 'Error: (' + response.status +') ' + response.statusText );
  20. }else{
  21. alert( 'Error: (' + response.status +') ' + 'Unreadable response. See console for response recieved.' );
  22. }
  23. };
  24. eo.str_replace = function( search, replace, subject, count ){
  25. var i = 0,
  26. j = 0,
  27. temp = '',
  28. repl = '',
  29. sl = 0,
  30. fl = 0,
  31. f = [].concat(search),
  32. r = [].concat(replace),
  33. s = subject,
  34. ra = Object.prototype.toString.call(r) === '[object Array]',
  35. sa = Object.prototype.toString.call(s) === '[object Array]';
  36. s = [].concat(s);
  37. if (count) {
  38. this.window[count] = 0;
  39. }
  40. for (i = 0, sl = s.length; i < sl; i++) {
  41. if (s[i] === '') {
  42. continue;
  43. }
  44. for (j = 0, fl = f.length; j < fl; j++) {
  45. temp = s[i] + '';
  46. repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0];
  47. s[i] = (temp).split(f[j]).join(repl);
  48. if (count && s[i] !== temp) {
  49. this.window[count] += (temp.length - s[i].length) / f[j].length;
  50. }
  51. }
  52. }
  53. return sa ? s : s[0];
  54. };
  55. eo.add_query_arg = function( key, value, uri ){
  56. var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
  57. var separator = uri.indexOf('?') !== -1 ? "&" : "?";
  58. if (uri.match(re)) {
  59. return uri.replace(re, '$1' + key + "=" + value + '$2');
  60. }else {
  61. return uri + separator + key + "=" + value;
  62. }
  63. };
  64. //===============================================================
  65. //Models
  66. //===============================================================
  67. formCustomiser.Model.EOFormController = Backbone.Model.extend();
  68. formCustomiser.Model.EOForm = Backbone.Model.extend({
  69. defaults: {
  70. name: eo.gettext( "Booking form"),
  71. title: eo.gettext( "Bookings"),
  72. notice_classes: 'eo-booking-notice',
  73. error_classes: 'eo-booking-error',
  74. },
  75. url: function() {
  76. var url = eo.add_query_arg( 'action', 'eo-bfc-form', eo.url );
  77. url = eo.add_query_arg( '_nonce', eo.nonce, url );
  78. if ( this.isNew() ) return url;
  79. return url + '&id=' + this.id;
  80. },
  81. parse: function(response, options) {
  82. if( response.success ){
  83. return response.data.form;
  84. }
  85. return {};
  86. },
  87. settings: [
  88. { 'id': 'name', 'label': eo.gettext( "Name" ), 'type': 'input',
  89. 'inline_help': {
  90. title: eo.gettext( "Booking Form Name" ),
  91. text: eo.gettext( "This is only used to help you identify the form on the event admin page." )
  92. } },
  93. { 'id': 'title', 'label': eo.gettext("Title" ), 'type': 'input' },
  94. { 'id': 'error_classes', 'label': eo.gettext( "Error classes" ), 'type': 'input' },
  95. { 'id': 'notice_classes', 'label': eo.gettext( "Notice classes" ), 'type': 'input' },
  96. ],
  97. elements: false,
  98. initialize: function(){
  99. this.on('change:elements', this.setUpElements, this );
  100. this.on('change', this.setUpSettings, this );
  101. this.elements = new formCustomiser.Collection.EOFormElements();
  102. this._settings = new formCustomiser.Collection.EOFormSettings( this.settings );
  103. this.setUpElements();
  104. this.setUpSettings();
  105. },
  106. setUpElements: function(){
  107. var self = this;
  108. this.elements.reset();
  109. if( this.get('elements') ){
  110. _.each( this.get('elements'), function( element ){
  111. self.add( element );
  112. });
  113. }
  114. this.elements.sort({silent:true});
  115. },
  116. setUpSettings: function( ev ){
  117. var self = this;
  118. this._settings.each(function(setting){
  119. if( setting.get('type') == 'checkbox' ){
  120. setting.set( 'checked', parseInt( self.get(setting.get('id')), 10 ) );
  121. }else{
  122. setting.set( 'value', self.get(setting.get('id')) );
  123. }
  124. });
  125. },
  126. add: function( element, settings ){
  127. settings = ( typeof settings !== 'undefined' ? settings : {} );
  128. settings.at = ( element instanceof Backbone.Model ? element.get( 'position' ) : element.position );
  129. if( !settings.at && settings.at !== '0' && settings.at !== 0 ){
  130. settings.at = this.elements.length;
  131. }
  132. this.elements.add( element, settings );
  133. },
  134. remove: function( element ){
  135. this.elements.remove( element );
  136. },
  137. toJSON: function(){
  138. var json = Backbone.Model.prototype.toJSON.call(this);
  139. json.elements = this.elements.toJSON();
  140. return json;
  141. }
  142. });
  143. formCustomiser.Model.EOFormElement = Backbone.Model.extend({
  144. settings: false,
  145. deletable: true,
  146. can_have_children: false,
  147. defaults: {
  148. label: false,
  149. placeholder: '',
  150. description: "",
  151. required: false,
  152. parent: 0,
  153. },
  154. url: function() {
  155. var url = eo.add_query_arg( 'action', 'eo-bfc-form-element', eo.url );
  156. url = eo.add_query_arg( '_nonce', eo.nonce, url );
  157. if ( this.isNew() ) return url;
  158. return url + '&id=' + this.id;
  159. },
  160. parse: function(response, options) {
  161. if( response.success ){
  162. return response.data.element;
  163. }
  164. return {};
  165. },
  166. initialize: function(){
  167. //this.unset( 'position' );
  168. //Backwards compat radiobox -> radio
  169. if( this.get('type') == 'radiobox' ){
  170. this.set( 'type', 'radio' );
  171. }
  172. if( this.settings ){
  173. var self = this;
  174. var settingsCollection = new formCustomiser.Collection.EOFormSettings();
  175. _.each( this.settings, function( setting ){
  176. setting.live_update = 1;
  177. switch( setting.type ){
  178. case 'input':
  179. case 'textarea':
  180. setting.value = self.get(setting.id);
  181. break;
  182. case 'checkbox':
  183. setting.checked = self.get(setting.id);
  184. break;
  185. case 'options':
  186. setting.options = self.get(setting.id);
  187. //Backwards compatible.
  188. if( !self.get( 'selected' ) && self.get( 'checked' ) ){
  189. setting.selected = self.get( 'checked' );
  190. }
  191. setting.selected = self.get( 'selected' );
  192. break;
  193. case 'range':
  194. setting.value_min = self.get(setting.min_id);
  195. setting.value_max = self.get(setting.max_id);
  196. break;
  197. }
  198. setting = new formCustomiser.Model.EOFormSetting( setting );
  199. settingsCollection.add( setting );
  200. });
  201. this.settings = settingsCollection;
  202. this.on( 'change', this.update_settings_value );
  203. }
  204. if( this.can_have_children ){
  205. this.elements = new formCustomiser.Collection.EOFormElements();
  206. this.listenTo( this.elements, 'add', this._set_parent );
  207. this.elements.reset();
  208. if( this.get('elements') ){
  209. _.each( this.get('elements'), function( element ){
  210. self.elements.add( element );
  211. });
  212. }
  213. this.elements.sort({silent:true});
  214. }
  215. },
  216. _set_parent: function( el ){
  217. el.set( 'parent', this.get('id') );
  218. },
  219. update_settings_value: function(){
  220. if( !this.settings ){
  221. return;
  222. }
  223. var self = this;
  224. this.settings.each(function( setting ){
  225. switch( setting.get('type') ){
  226. case 'input':
  227. case 'textarea':
  228. setting.set('value', self.get(setting.id) );
  229. break;
  230. case 'checkbox':
  231. setting.set('checked', self.get(setting.id) );
  232. break;
  233. case 'options':
  234. setting.set('options', self.get(setting.id) );
  235. setting.options = self.get(setting.id);
  236. setting.set('selected', self.get('selected') );
  237. break;
  238. case 'range':
  239. setting.set({
  240. 'value_min': self.get( setting.get('min_id') ),
  241. 'value_max': self.get( setting.get('max_id') )
  242. });
  243. break;
  244. }
  245. });
  246. },
  247. toJSON: function(){
  248. var json = Backbone.Model.prototype.toJSON.call(this);
  249. json.position = ( this.collection !== undefined ? this.collection.indexOf(this) : -1 );
  250. //Backwards compatible (checked --> selected )
  251. if ( typeof json.checked !== 'undefined' ) {
  252. if( typeof json.selected == 'undefined' ){
  253. json.selected = json.checked;
  254. }
  255. delete json.checked;
  256. }
  257. if ( this.can_have_children && typeof this.elements !== 'undefined' ) {
  258. json.elements = this.elements.toJSON();
  259. }
  260. return json;
  261. },
  262. is_deletable: function(){
  263. var deletable = this.deletable;
  264. if ( _.isFunction( deletable ) ){
  265. return deletable.apply( this );
  266. }else{
  267. return deletable;
  268. }
  269. }
  270. });
  271. var formElement = formCustomiser.Model.EOFormElement;
  272. formCustomiser.Model.EOFormElementAddress = formElement.extend({
  273. defaults: {
  274. label: eo.gettext( "Address" ),
  275. name: eo.gettext( "Address" ),
  276. components: ['street-address', '2nd-line', 'city', 'state', 'postcode', 'country'],
  277. required: false,
  278. description: "",
  279. parent: 0,
  280. },
  281. settings: [
  282. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  283. { 'id': 'components', 'label': eo.gettext( "Address includes" ), 'type': 'checkbox', 'options':
  284. {
  285. 'street-address': eo.gettext( "Street address" ),
  286. '2nd-line': eo.gettext( "Second line" ),
  287. 'city': eo.gettext( "City" ),
  288. 'state': eo.gettext( "State" ),
  289. 'postcode': eo.gettext( "Postcode" ),
  290. 'country': eo.gettext( "Country" )
  291. }
  292. },
  293. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  294. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  295. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' },
  296. ],
  297. });
  298. formCustomiser.Model.EOFormElementAntispam = formElement.extend({
  299. settings: [
  300. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  301. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' },
  302. ]
  303. });
  304. formCustomiser.Model.EOFormElementCheckbox = formElement.extend({
  305. defaults: {
  306. label: eo.gettext( "Label" ),
  307. name: eo.gettext( "Checkbox" ),
  308. options:['Option A', 'Option B', 'Option C'],
  309. required: false,
  310. selected: [],
  311. multiselect: true,
  312. description: "",
  313. parent: 0,
  314. },
  315. settings: [
  316. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  317. { 'id': 'options', 'label': eo.gettext( "Options" ), 'type': 'options', 'option_type': 'checkbox' },
  318. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  319. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  320. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  321. ],
  322. });
  323. formCustomiser.Model.EOFormElementFieldset = formElement.extend({
  324. defaults: {
  325. name: eo.gettext("Fieldset"),
  326. label:eo.gettext("Label"),
  327. parent: 0,
  328. },
  329. can_have_children: true,
  330. settings: [
  331. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  332. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  333. ]
  334. });
  335. formCustomiser.Model.EOFormElementGateway = formElement.extend({
  336. defaults: {
  337. name: eo.gettext("Gateway picker"),
  338. label: eo.gettext( "Select a payment gateway" ),
  339. parent: 0,
  340. },
  341. settings: [
  342. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  343. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }],
  344. deletable: false,
  345. });
  346. formCustomiser.Model.EOFormElementHook = formElement.extend({
  347. defaults: {
  348. name: eo.gettext("Hook"),
  349. 'wp-action': 'some_custom_action',
  350. parent: 0,
  351. },
  352. settings: [ { 'id': 'wp-action', 'label': eo.gettext("Hook" ), 'type': 'input'} ]
  353. });
  354. formCustomiser.Model.EOFormElementHtml = formElement.extend({
  355. defaults: {
  356. name: eo.gettext("HTML"),
  357. parent: 0,
  358. },
  359. settings: [{ 'id': 'html', 'label': eo.gettext("HTML"), 'type': 'textarea' }]
  360. });
  361. formCustomiser.Model.EOFormElementName = formElement.extend({
  362. defaults: {
  363. label: eo.gettext( "Name" ),
  364. name: eo.gettext( "Bookee name" ),
  365. placeholder: '',
  366. required: true,
  367. parent: 0,
  368. },
  369. settings: [
  370. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  371. { 'id': 'lname', 'label': eo.gettext( "Include second name" ), 'type': 'checkbox' },
  372. { 'id': 'lname_required', 'label': eo.gettext( "Require second name" ), 'type': 'checkbox' },
  373. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  374. ],
  375. deletable: function(){
  376. return ( this.id != 'name' );
  377. }
  378. });
  379. formCustomiser.Model.EOFormElementInput = formElement.extend({
  380. defaults: {
  381. label: eo.gettext("Label"),
  382. name: eo.gettext("Text field"),
  383. placeholder: '',
  384. description: "",
  385. required: false,
  386. field_type: 'text',
  387. parent: 0,
  388. },
  389. settings: [
  390. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  391. { 'id': 'required', 'label': eo.gettext("Required" ), 'type': 'checkbox' },
  392. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  393. { 'id': 'placeholder', 'label': eo.gettext( "Placeholder" ), 'type': 'input' },
  394. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  395. ],
  396. });
  397. formCustomiser.Model.EOFormElementAntispam = formCustomiser.Model.EOFormElementInput.extend({
  398. defaults:{
  399. name: eo.gettext("Antispam"),
  400. label: eo.gettext("What is x + y?"),
  401. placeholder: '',
  402. description: "",
  403. required: true,
  404. field_type: 'text',
  405. parent: 0,
  406. },
  407. settings: [
  408. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  409. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  410. ],
  411. });
  412. formCustomiser.Model.EOFormElementDate = formCustomiser.Model.EOFormElementInput.extend({
  413. defaults:{
  414. name: eo.gettext("Date"),
  415. label: eo.gettext("Date"),
  416. description: "",
  417. required: false,
  418. field_type: 'text',
  419. format: "Y-m-d",
  420. opening_date: "today",
  421. parent: 0,
  422. },
  423. settings: [
  424. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  425. { 'id': 'required', 'label': eo.gettext("Required" ), 'type': 'checkbox' },
  426. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  427. { 'id': 'format', 'label': eo.gettext("Date format"), 'type': 'input' },
  428. { 'id': 'opening_date', 'label': eo.gettext("Opening date"), 'type': 'input' },
  429. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  430. ],
  431. });
  432. formCustomiser.Model.EOFormElementButton = formElement.extend({
  433. defaults: {
  434. name: eo.gettext( "Button" ),
  435. label: eo.gettext( "Submit" ),
  436. button_text: eo.gettext( "Book" ),
  437. 'class': 'eo-booking-button',
  438. parent: 0,
  439. },
  440. settings: [
  441. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  442. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }],
  443. deletable: false,
  444. });
  445. formCustomiser.Model.EOFormElementEmail = formCustomiser.Model.EOFormElementInput.extend({
  446. defaults:{
  447. name: eo.gettext("E-mail"),
  448. label: eo.gettext("E-mail"),
  449. placeholder: 'john@example.com',
  450. description: "",
  451. required: false,
  452. field_type: 'text',
  453. parent: 0,
  454. },
  455. deletable: function(){
  456. return ( this.id != 'email' );
  457. }
  458. });
  459. formCustomiser.Model.EOFormElementNumber = formCustomiser.Model.EOFormElementInput.extend({
  460. defaults:{
  461. name: eo.gettext("Number"),
  462. label: eo.gettext("Number"),
  463. placeholder: '',
  464. description: "",
  465. required: false,
  466. min: false,
  467. max: false,
  468. field_type: 'number',
  469. parent: 0,
  470. },
  471. settings: [
  472. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  473. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  474. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  475. { 'id': 'placeholder', 'label': eo.gettext( "Placeholder" ), 'type': 'input' },
  476. { 'id': 'range', 'label': eo.gettext("Range"), 'min_id': 'min', 'label_min': eo.gettext("Min"), 'max_id': 'max', 'label_max': eo.gettext("Max"), 'type': 'range' },
  477. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  478. ],
  479. });
  480. formCustomiser.Model.EOFormElementPhone = formCustomiser.Model.EOFormElementInput.extend({
  481. defaults:{
  482. name: eo.gettext("Phone"),
  483. label: eo.gettext("Phone"),
  484. placeholder: '',
  485. description: "",
  486. required: false,
  487. field_type: 'text',
  488. parent: 0,
  489. },
  490. });
  491. formCustomiser.Model.EOFormElementUrl = formCustomiser.Model.EOFormElementInput.extend({
  492. defaults:{
  493. label: eo.gettext("Website"),
  494. name: eo.gettext("Website"),
  495. placeholder: 'http://',
  496. description: "",
  497. required: false,
  498. field_type: 'text',
  499. parent: 0,
  500. },
  501. });
  502. formCustomiser.Model.EOFormElementMultiselect = formElement.extend({
  503. defaults: function(){ return {
  504. label: eo.gettext( "Label" ),
  505. name: eo.gettext("Multiselect"),
  506. options:['Option A', 'Option B', 'Option C'],
  507. required: false,
  508. selected: [],
  509. multiselect: true,
  510. description: "",
  511. parent: 0,
  512. }; },
  513. settings: [
  514. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  515. { 'id': 'options', 'label': eo.gettext( "Options" ), 'type': 'options', 'option_type': 'checkbox' },
  516. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  517. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  518. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  519. ],
  520. });
  521. formCustomiser.Model.EOFormElementRadio = formElement.extend({
  522. defaults: {
  523. label: eo.gettext( "Label" ),
  524. name: eo.gettext("Radio"),
  525. options: ['Option A', 'Option B', 'Option C'],
  526. required: false,
  527. selected: false,
  528. description: "",
  529. parent: 0,
  530. },
  531. settings: [
  532. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  533. { 'id': 'options', 'label': eo.gettext( "Options" ), 'type': 'options', 'option_type': 'radio' },
  534. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  535. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  536. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  537. ],
  538. });
  539. formCustomiser.Model.EOFormElementSection = formElement.extend({
  540. defaults: {
  541. name: eo.gettext("Section"),
  542. label: eo.gettext("Section"),
  543. parent: 0,
  544. },
  545. settings: [
  546. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  547. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }]
  548. });
  549. formCustomiser.Model.EOFormElementSelect = formElement.extend({
  550. defaults:{
  551. label: eo.gettext( "Label" ),
  552. name: eo.gettext("Select"),
  553. options:['Option A', 'Option B', 'Option C'],
  554. required: false,
  555. multiselect: false,
  556. selected: [],
  557. description: "",
  558. parent: 0,
  559. },
  560. settings: [
  561. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  562. { 'id': 'options', 'label': eo.gettext( "Options" ), 'type': 'options', 'option_type': 'radio' },
  563. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  564. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  565. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  566. ],
  567. });
  568. formCustomiser.Model.EOFormElementTermsConditions = formElement.extend({
  569. defaults:{
  570. name: eo.gettext("Terms & Conditions"),
  571. label: eo.gettext("Terms & Conditions"),
  572. terms: eo.gettext("Your terms & conditions"),
  573. terms_accepted_label: eo.gettext("I have read and agree to the terms and conditions detailed above."),
  574. required: true,
  575. parent: 0,
  576. },
  577. settings: [
  578. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  579. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  580. { 'id': 'terms', 'label': eo.gettext('Terms'), 'type': 'textarea' },
  581. { 'id': 'terms_accepted_label', 'label': eo.gettext("Checkbox label"), 'type': 'input' },
  582. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  583. ]
  584. });
  585. formCustomiser.Model.EOFormElementTextarea = formElement.extend({
  586. defaults: {
  587. label: eo.gettext( "Label" ),
  588. name: eo.gettext( "Textarea" ),
  589. placeholder: '',
  590. description: "",
  591. required: false,
  592. parent: 0,
  593. },
  594. settings: [
  595. { 'id': 'label', 'label': eo.gettext( "Label" ), 'type': 'input' },
  596. { 'id': 'required', 'label': eo.gettext( "Required" ), 'type': 'checkbox' },
  597. { 'id': 'description', 'label': eo.gettext( "Description" ), 'type': 'textarea' },
  598. { 'id': 'class', 'label': eo.gettext( "CSS Class" ), 'type': 'input' }
  599. ],
  600. });
  601. formCustomiser.Model.EOFormElementTicketpicker = formElement.extend({
  602. settings: [
  603. { 'id': 'use_select', 'label': eo.gettext("Use drop-down list"), 'type': 'checkbox',
  604. 'inline_help': {
  605. title: eo.gettext("Date selection"),
  606. text: eo.gettext("If checked a drop-down select menu is used for selecting a date, rather than a datepicker.")
  607. }
  608. },
  609. { 'id': 'simple_mode', 'label': eo.gettext( "Simple Booking Mode" ), 'type': 'checkbox',
  610. 'inline_help': {
  611. title: eo.gettext( "Simple Booking Mode" ),
  612. text: eo.gettext( "Simple Booking Mode only comes into effect if:<ul><li>This option is selected.</li><li>The event has only one ticket currently on sale.</li><li>You are booking by series, or the event is non-recurring (no date needs to be selected).</li></ul>Under those conditions the date and ticket selection is hidden from the booking form, and the booking consist of only one ticket." )
  613. }
  614. },
  615. ],
  616. defaults: {
  617. use_select: 0,
  618. name: eo.gettext( "Ticket picker" ),
  619. parent: 0,
  620. },
  621. deletable: false,
  622. });
  623. formCustomiser.Model.EOFormSetting = Backbone.Model.extend({
  624. defaults:{
  625. inline_help: false,
  626. },
  627. toJSON: function() {
  628. var json = Backbone.Model.prototype.toJSON.apply(this, arguments);
  629. json.cid = this.cid;
  630. return json;
  631. },
  632. //for options setting
  633. removeOptionAt: function( index ){
  634. var options = this.get('options');
  635. var selected = _.clone( this.get('selected') );
  636. if( 'radio' == this.get('option_type') ){
  637. if( selected ){
  638. if( selected == index ){
  639. selected = false;
  640. }else if( selected > index ){
  641. selected--;
  642. }
  643. }
  644. }else{
  645. selected = _.filter( _.clone( selected ), function( n ){ return n !== index; });
  646. selected = _.map(selected, function( n ){ return ( n > index ? n-1 : n ); });
  647. }
  648. if( options ){
  649. options = _.reject(options, function( option, _index){ return _index == index; } );
  650. }
  651. this.set( {
  652. 'options': options,
  653. 'selected': selected
  654. });
  655. },
  656. insertOptionAt: function( option, index ){
  657. var options = _.clone( this.get('options') );
  658. var selected = _.clone( this.get('selected') );
  659. if( 'radio' == this.get('option_type') ){
  660. if( selected ){
  661. selected = ( selected >= index ? selected + 1 : selected );
  662. }
  663. }else{
  664. selected = _.map(selected, function( n ){ return ( n>= index ? n+1 : n ); });
  665. }
  666. if( options ){
  667. options.splice( index, 0, option );
  668. }else{
  669. options = [option];
  670. }
  671. this.set( {
  672. 'options': options,
  673. 'selected': selected
  674. });
  675. },
  676. setSelected: function( selected ){
  677. if( 'radio' == this.get('option_type') ){
  678. selected = ( selected ? _.first( selected ) : false );
  679. }
  680. this.set( 'selected', selected );
  681. },
  682. setOption: function( option, index ){
  683. var options = _.clone( this.get('options') );
  684. options[index] = option;
  685. this.set( 'options', options );
  686. },
  687. is_selected: function( index ){
  688. var selected = this.get('selected');
  689. if( 'radio' == this.get('option_type') ){
  690. return selected === index;
  691. }else{
  692. return _.indexOf( selected, index ) > -1;
  693. }
  694. }
  695. });
  696. //===============================================================
  697. //Collections
  698. //===============================================================
  699. formCustomiser.Collection.EOFormElements = Backbone.Collection.extend({
  700. model: function( attrs, options) {
  701. var className = 'EOFormElement'+('_'+attrs.type).replace(/[_|-]([a-z])/g, function (g) { return g[1].toUpperCase(); });
  702. var modelClass = formCustomiser.Model[className];
  703. if( typeof modelClass == 'undefined' ){
  704. return new formCustomiser.Model.EOFormElement( attrs, options );
  705. }else{
  706. return new modelClass( attrs, options );
  707. }
  708. },
  709. comparator: function( model ){
  710. return model.get('position');
  711. }
  712. });
  713. formCustomiser.Collection.EOFormSettings = Backbone.Collection.extend({
  714. model: formCustomiser.Model.EOFormSetting,
  715. });
  716. //===============================================================
  717. //Views
  718. //===============================================================
  719. formCustomiser.View.EOFormControllerView = Backbone.View.extend({
  720. el: '#poststuff',
  721. template: _.template( $( '#tmpl-' + 'eo-form-controller' ).html( ), null, {
  722. evaluate: /<#([\s\S]+?)#>/g,
  723. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  724. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  725. }),
  726. initialize: function() {
  727. _.bindAll(this, 'render' );
  728. this.formView = false;
  729. this.model.get('form').on('change:id', this.render, this);
  730. this.model.get('form').on('change:name', this.renderForms, this);
  731. this.model.on('change:forms', this.renderForms, this);
  732. },
  733. events: {
  734. 'click #eo-bfc-form-tabs li a': 'tabClicked',
  735. 'click #side-sortables .handlediv': 'fieldBinToggleClicked',
  736. 'click .eventorganiser-field-bin li': 'addField',
  737. // 'click #eventorganiser-save-form': 'saveForm',
  738. 'click .eo-bfc-delete-form': 'deleteFormClicked',
  739. 'click .eo-bfc-add-form-btn': 'addFormClicked',
  740. 'change .eo-bfc-edit-form': 'changeForm',
  741. 'keyup .eo-bfc-setting-name': 'editFormName',
  742. 'click .eo-bfc-export-form-btn': 'exportForm',
  743. 'click .eo-bfc-import-form-btn': 'revealUploadForm',
  744. 'click .eo-bfc-cancel-upload-form-btn': 'hideUploadForm',
  745. 'click .eo-bfc-upload-form-btn': 'uploadForm',
  746. },
  747. render: function(){
  748. //Remove automatically added (by EO) "submit" button.
  749. //TODO rework this so this isn't necessary
  750. $('.wrap .submit').remove();
  751. $( this.el ).html( this.template( this.model.toJSON() ) );
  752. this.renderForms();
  753. $( '#side-sortables', this.el ).html('');
  754. _.each( this.model.get('metaboxes'), function( metabox ){
  755. $('#side-sortables').append( _.template( $( '#tmpl-eo-form-element-bin' ).html(), metabox, {
  756. evaluate: /<#([\s\S]+?)#>/g,
  757. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  758. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  759. }) );
  760. } );
  761. $('#side-sortables .postbox:gt(0)', this.el ).addClass('closed');
  762. if( this.formView ){
  763. this.formView.close();
  764. }
  765. this.formView = new formCustomiser.View.EOFormView({ model: this.model.get('form') });
  766. this.formView.render();
  767. $('.form-toolbar-option input', this.el ).val( this.model.get('form').get('name') );
  768. $( window ).on( 'scroll click.postboxes', function( event ) {
  769. var y = parseInt( $(this).scrollTop(), 10 );
  770. var footer_top = parseInt( $( '#wpfooter' ).position().top, 10 );
  771. var fixed_offset = parseInt( $("#eo-bfc-form").offset().top, 10 );
  772. var metabox_height = parseInt( $('#eventorganiser-form-fixed-mb').height(), 10 );
  773. var bar = y + fixed_offset + metabox_height;
  774. if ( footer_top - bar > -20 ) {
  775. $('#eventorganiser-form-fixed-mb').css({
  776. position: 'fixed',
  777. top: $("#eo-bfc-form").offset().top
  778. });
  779. } else {
  780. $('#eventorganiser-form-fixed-mb').css({
  781. position: 'absolute',
  782. top: ( footer_top - metabox_height ) + 'px'
  783. });
  784. }
  785. }).trigger( 'click.postboxes' );
  786. return this;
  787. },
  788. rerender: function(){
  789. this.render();
  790. },
  791. renderForms: function(){
  792. $( '.eo-bfc-edit-form', this.el ).html('');
  793. var self = this;
  794. _.each( this.model.get('forms'), function( form ) {
  795. var selected = ( form.id == self.model.get('form').get('id') ? 'selected="selected"' : '' );
  796. $( '.eo-bfc-edit-form', this.el ).append( '<option value="' + form.id + '" ' + selected + '> ' + form.name + ' (' + form.id + ')</option>' );
  797. });
  798. },
  799. tabClicked: function( ev ){
  800. ev.preventDefault();
  801. $('#eo-bfc-form-tabs li').removeClass('active');
  802. $(this.el).find( '.eo-booking-form-tabbed-area').hide();
  803. $(ev.currentTarget).parent( 'li' ).addClass('active');
  804. $(this.el).find( '#' + $(ev.currentTarget).attr('aria-controls') ).show();
  805. },
  806. fieldBinToggleClicked: function( ev ){
  807. $( ev.target, this.el ).parent('.postbox').toggleClass('closed');
  808. },
  809. addField: function( ev ){
  810. var self = this, type = $(ev.currentTarget).data('type'), element;
  811. var className = 'EOFormElement'+('_'+type).replace(/[_|-]([a-z])/g, function (g) { return g[1].toUpperCase(); });
  812. if( typeof formCustomiser.Model[className] != 'undefined' ){
  813. element = new formCustomiser.Model[className]({type:type});
  814. }else{
  815. element = new formCustomiser.Model.EOFormElement({type:type});
  816. }
  817. element.save( null, {
  818. success: function( model, response ){
  819. if( response.success ){
  820. self.model.get('form').elements.add( model, { scroll: true, at: self.model.get('form').elements.length } );
  821. }else{
  822. alert( response.data.message );
  823. }
  824. },
  825. error: eo.error_handler,
  826. emulateHTTP: true,
  827. });
  828. },
  829. deleteFormClicked: function( ev ){
  830. ev.preventDefault();
  831. if( !confirm( 'Are you sure you want to delete the form "'+this.model.get('form').get('name')+'"?\n\n This action cannot be undone.' ) ){
  832. return;
  833. }
  834. var self = this;
  835. $( '#eo-bfc-form', this.el ).append( $('<div class="eo-bfc-ajax-overlay">') );
  836. //Delete form on server
  837. this.model.get('form').destroy({
  838. emulateHTTP: true,
  839. success:function( model, response ){
  840. if( !response.success ){
  841. alert( response.data.message );
  842. return;
  843. }
  844. var form_id = model.get('id');
  845. var forms = _.filter( self.model.get('forms'), function( form ){ return form.id != form_id; });
  846. self.model.set( 'forms', forms );
  847. var next_form = _.first( forms );
  848. if( next_form !== undefined ){
  849. var form = new formCustomiser.Model.EOForm( { id: next_form.id } );
  850. form.fetch({
  851. success:function( model, response ){
  852. if( response.success ){
  853. self.model.set('form',model);
  854. self.rerender();
  855. }else{
  856. alert( response.data.message );
  857. self.rerender();
  858. }
  859. },
  860. error: eo.error_handler,
  861. });
  862. }else{
  863. //No form available
  864. $( '#eo-bfc-form', this.el ).html( '<h3>'+ eo.gettext( 'No form found... <a href="#" title="Create a new form" class="eo-bfc-add-form-btn">create new</a>' ) + '</h3>' );
  865. }
  866. },
  867. error: eo.error_handler,
  868. });
  869. },
  870. changeForm: function( ev ){
  871. ev.preventDefault();
  872. var form_id = $( ev.target ).val();
  873. var form = new formCustomiser.Model.EOForm( { id: form_id } );
  874. $( '#eo-bfc-form', this.el ).append( $('<div class="eo-bfc-ajax-overlay">') );
  875. var self = this;
  876. form.fetch({
  877. success:function( model, response ){
  878. if( response.success ){
  879. self.model.set('form',model);
  880. self.rerender();
  881. }else{
  882. alert( response.data.message );
  883. }
  884. },
  885. error: eo.error_handler,
  886. });
  887. },
  888. addFormClicked: function( ev ){
  889. ev.preventDefault();
  890. var self = this;
  891. var newForm = new formCustomiser.Model.EOForm({});
  892. $( '#eo-bfc-form', this.el ).append( $('<div class="eo-bfc-ajax-overlay">') );
  893. newForm.save( null, {
  894. wait: true,
  895. success: function( model, response ){
  896. if( response.success ){
  897. var forms = self.model.get('forms');
  898. forms.push( model.toJSON() );
  899. self.model.set( 'forms', forms );
  900. self.model.set('form',newForm);
  901. self.rerender();
  902. }else{
  903. alert( response.data.message );
  904. self.rerender();
  905. }
  906. },
  907. error: eo.error_handler,
  908. emulateHTTP: true,
  909. });
  910. },
  911. editFormName: function( ev ){
  912. var self = this;
  913. forms = this.model.get('forms');
  914. _.map( forms, function( form ){
  915. if( form.id == self.model.get('form').get('id') ){
  916. form.name = $(ev.target).val();
  917. }
  918. });
  919. this.model.set('forms', forms );
  920. this.model.get('form').set('name', $(ev.target).val() );
  921. },
  922. exportForm: function( ev ){
  923. ev.preventDefault();
  924. var json = this.model.get('form').toJSON();
  925. var now = new Date();
  926. var year = now.getFullYear();
  927. var month = ('0' + ( now.getMonth()+1 ) ).slice(-2);
  928. var date = ('0' + now.getDate()).slice(-2);
  929. var datetime = year + '-' + month + '-' + date;
  930. //Get file name
  931. var filename = 'booking-form-' + json.name + '-'+datetime;
  932. var valid = [ " ", ".", "?", "[", "]", "/", "\\", "=", "<", ">", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}" ];
  933. filename = eo.str_replace( valid, '', filename.replace(/\s+/g, '-') );
  934. $('#eo-export-form-link').remove();
  935. $('<a></a>')
  936. .attr('id','eo-export-form-link')
  937. .attr('href','data:text/json;charset=utf8,' + encodeURIComponent( JSON.stringify( json ) ))
  938. .attr('download',filename+'.json')
  939. .appendTo('body');
  940. $('#eo-export-form-link').get(0).click();
  941. },
  942. revealUploadForm: function( ev ){
  943. ev.preventDefault();
  944. $upload_form = $('<div id="eo-bfc-upload-form-wrap" style="position: absolute;height: 52px;background: white;width: 100%;top:-52px;bottom: 0;line-height:52px;"></div>');
  945. $upload_form.append( $( '#tmpl-eo-upload-form' ).html() );
  946. $upload_form.appendTo('#eo-bfc-manage-forms');
  947. $upload_form.animate({ top: 0 }, 500 );
  948. },
  949. hideUploadForm: function( ev ){
  950. ev.preventDefault();
  951. $( '#eo-bfc-form', this.el ).find( '.eo-bfc-ajax-overlay').remove();
  952. $upload_form = $('#eo-bfc-upload-form-wrap').animate({ top: '-52px' }, 500, function(){ $(this).remove(); } );
  953. },
  954. uploadForm: function( ev ){
  955. ev.preventDefault();
  956. var $input = $( '.eo-bfc-upload-file',this.el );
  957. var formData = new FormData();
  958. formData.append( 'eo-bfc-form', $input[0].files[0] );
  959. $( '#eo-bfc-form', this.el ).append( $('<div class="eo-bfc-ajax-overlay">') );
  960. var url = eo.add_query_arg( 'action', 'eo-bfc-form-upload-form', eo.url );
  961. url = eo.add_query_arg( '_nonce', eo.nonce, url );
  962. var self = this;
  963. $.ajax({
  964. url: url,
  965. type: "POST",
  966. data: formData,
  967. processData: false,
  968. contentType: false,
  969. dataType: 'json',
  970. })
  971. .done( function( response ) {
  972. if( response && response.success ){
  973. var newForm = new formCustomiser.Model.EOForm( response.data.form );
  974. var forms = self.model.get('forms');
  975. forms.push( newForm.toJSON() );
  976. self.model.set( 'forms', forms );
  977. self.model.set( 'form', newForm );
  978. self.render();
  979. }else{
  980. var $message = $( '<span class="eo-dashicon-error eo-dashicon eo-bfc-upload-error-msg"></span>' );
  981. if( !response ){
  982. $message.text( "Unknown error" );
  983. }else{
  984. $message.text( response.data.message );
  985. }
  986. $( '.eo-bfc-upload-error' ).html( $message );
  987. }
  988. });
  989. },
  990. });
  991. formCustomiser.View.EOFormView = Backbone.View.extend({
  992. el: '#eo-bfc-form',
  993. template: _.template( $( '#tmpl-' + 'eo-form' ).html( ), null, {
  994. evaluate: /<#([\s\S]+?)#>/g,
  995. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  996. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  997. }),
  998. events: {
  999. 'update-sort': 'updatePositions',
  1000. 'click .eo-bfc-save-form-btn': 'saveForm',
  1001. },
  1002. initialize: function() {
  1003. _.bindAll(this, 'render', 'updatePositions', 'addElement' );
  1004. this.model.elements.on('add', this.addElement, this);
  1005. //this.listenTo( this.model.elements, 'add', this.addElement );
  1006. this.model.bind('request', this.ajaxStart, this);
  1007. this.model.bind('sync', this.ajaxComplete, this);
  1008. },
  1009. ajaxStart: function(){
  1010. $(this.el).find('.eo-bfc-save-form-btn').prop('disabled', true);
  1011. $(this.el).find('.spinner').show();
  1012. },
  1013. ajaxComplete: function(){
  1014. $(this.el).find('.eo-bfc-save-form-btn').prop('disabled', false);
  1015. $(this.el).find('.spinner').hide();
  1016. },
  1017. render: function(){
  1018. if( EO_SCRIPT_DEBUG ){
  1019. console.log('render form');
  1020. }
  1021. $(this.el).html( this.template( this.model.toJSON() ) );
  1022. var self = this;
  1023. this.model.elements.each(function(element) {
  1024. self.addElement( element );
  1025. });
  1026. $( 'ul.eo-bfc-element-root-list' ).nestedSortable({
  1027. listType: 'ul',
  1028. disableNesting: 'eo-bfc-element-no-children',
  1029. errorClass: 'eo-bfc-placeholder-error',
  1030. handle: 'h3',
  1031. helper: 'clone',
  1032. items: '.eo-bfc-element',
  1033. placeholder: 'eo-bfc-placeholder',
  1034. tolerance: 'pointer',
  1035. toleranceElement: '.eo-bfc-form-element',
  1036. maxLevels: 3,
  1037. update: function( ev, ui ){
  1038. ui.item.trigger('drop', ui.item.index());
  1039. },
  1040. });
  1041. this.model._settings.each(function(setting){
  1042. settingView = new formCustomiser.View.EOFormSettingView({
  1043. model: setting
  1044. });
  1045. $( '#eventorganiser-form-settings', this.el ).append( settingView.render().el );
  1046. setting.on('change', self.updateSetting, self );
  1047. //self.listenTo( setting, 'change', self.updateSetting );
  1048. });
  1049. return this;
  1050. },
  1051. addElement: function( element, t, settings ){
  1052. var views = formCustomiser.View;
  1053. var elementView;
  1054. switch( element.get('type') ){
  1055. case 'input':
  1056. case 'url':
  1057. case 'email':
  1058. case 'date':
  1059. case 'phone':
  1060. case 'number':
  1061. case 'antispam':
  1062. case 'discount-code':
  1063. elementView = new views.EOFormElementInputView({model: element});
  1064. break;
  1065. case 'multiselect':
  1066. elementView = new views.EOFormElementSelectView({model: element});
  1067. break;
  1068. default:
  1069. elementView = new views.EOFormElementView({model: element});
  1070. }
  1071. var elementEL = elementView.render().el;
  1072. $('ul#eventorganiser-form-fields',self.el).append( elementEL );
  1073. if( settings && settings.scroll ){
  1074. $("html, body").animate({ scrollTop: $(elementEL).offset().top-50 }, 400);
  1075. }
  1076. },
  1077. updatePositions: function( event, movedModel, to ){
  1078. //Added to form
  1079. var from = movedModel.collection.indexOf( movedModel );
  1080. var fromParent = movedModel.get('parent');
  1081. if( EO_SCRIPT_DEBUG ){
  1082. console.log(
  1083. movedModel.id + " moved "
  1084. + " from " + from + " under " + fromParent
  1085. + " to " + to + " under " + 0 );
  1086. }
  1087. movedModel.set( 'parent', 0, {silent:true} );
  1088. movedModel.collection.remove( movedModel, {silent:true} );
  1089. this.model.elements.add( movedModel, {at:to, silent: true } );
  1090. },
  1091. updateSetting: function( setting ){
  1092. var value = ( setting.get('type') == 'checkbox' ) ? parseInt( setting.get('selected'), 10 ) : setting.get('value');
  1093. this.model.set( setting.get('id'), value );
  1094. },
  1095. saveForm: function( ev ){
  1096. ev.preventDefault();
  1097. if( EO_SCRIPT_DEBUG ){
  1098. console.log('saving form '+this.model.id);
  1099. console.log(this.model.toJSON());
  1100. }
  1101. this.model.save( null, {
  1102. silent:true,
  1103. emulateHTTP: true,
  1104. success: function( model, response ){
  1105. if( !response.success ){
  1106. alert( response.data.message );
  1107. }
  1108. },
  1109. error: eo.error_handler,
  1110. } );
  1111. },
  1112. close: function(){
  1113. this.remove();
  1114. this.unbind();
  1115. this.model.unbind();
  1116. },
  1117. });
  1118. formCustomiser.View.EOFormElementView = Backbone.View.extend({
  1119. tagName: 'li',
  1120. className: 'eo-bfc-element',
  1121. template: _.template( $( '#tmpl-eo-form-element' ).html( ), null, {
  1122. evaluate: /<#([\s\S]+?)#>/g,
  1123. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  1124. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  1125. }),
  1126. exampleTemplate: false,
  1127. events: {
  1128. 'click .inside, .handlediv': 'toggleSettingsVisibility',
  1129. 'drop' : 'dropped',
  1130. 'click .inside .eo-bfc-settings': 'stopPropagation',
  1131. 'click a.submitdelete': 'deleteElement',
  1132. 'update-sort ul': 'updatePositions',
  1133. },
  1134. initialize: function() {
  1135. _.bindAll(this, 'render', 'toggleSettingsVisibility', 'dropped', 'rerender', 'updatePositions', 'addElement' );
  1136. if( !this.exampleTemplate ){
  1137. var type = this.model.get('type');
  1138. this.exampleTemplate = $( '#tmpl-' + 'eo-form-element-example-' + type ).html();
  1139. }
  1140. if( !this.model.can_have_children ){
  1141. this.$el.addClass('eo-bfc-element-no-children');
  1142. }else{
  1143. this.model.elements.on( 'add', this.addElement, this );
  1144. //this.listenTo( this.model.elements, 'add', this.addElement );
  1145. }
  1146. this.$el.addClass('eo-bfc-element-'+this.model.get('type'));
  1147. this.model.on( 'change', this.rerender, this );
  1148. //this.listenTo(this.model, "change", this.rerender);
  1149. },
  1150. render: function(){
  1151. if( EO_SCRIPT_DEBUG ){
  1152. console.log('render element ' + this.model.id );
  1153. }
  1154. var json = _.extend( this.model.toJSON(), {can_have_children: this.model.can_have_children } );
  1155. this.$el.append( this.template( json ) );
  1156. this.renderExample();
  1157. this.renderSettings();
  1158. if( this.model.can_have_children ) {
  1159. var self = this;
  1160. this.model.elements.each(function(element) {
  1161. self.addElement( element );
  1162. });
  1163. }
  1164. if( this.model.is_deletable() ){
  1165. $( '#eo-bfc-element-'+this.model.id+' .eo-bfc-settings', this.el ).append( '<span class="submitbox"><a href="#" class="submitdelete" title="Delete this element">Delete Element</a></span>' );
  1166. }
  1167. return this;
  1168. },
  1169. rerender: function(){
  1170. if( EO_SCRIPT_DEBUG ){
  1171. console.log('rerender element');
  1172. }
  1173. this.renderExample();
  1174. return this;
  1175. },
  1176. deleteElement: function( ev ){
  1177. ev.preventDefault();
  1178. this.model.collection.remove( this.model );
  1179. //COMPLETELY UNBIND THE VIEW
  1180. this.undelegateEvents();
  1181. this.$el.removeData().unbind();
  1182. //Remove view from DOM
  1183. this.remove();
  1184. Backbone.View.prototype.remove.call(this);
  1185. },
  1186. renderExample: function(){
  1187. var json = this.model.toJSON();
  1188. //Backwards compatible
  1189. if ( typeof json['wp-action'] !== 'undefined' ) {
  1190. json.action = json['wp-action'];
  1191. }
  1192. if( this.exampleTemplate ){
  1193. $( '#eo-bfc-element-'+this.model.id+' .eo-bfc-example', this.el ).html(
  1194. _.template( this.exampleTemplate, json, {
  1195. evaluate: /<#([\s\S]+?)#>/g,
  1196. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  1197. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  1198. })
  1199. );
  1200. }
  1201. },
  1202. renderSettings: function(){
  1203. if( this.model.settings ){
  1204. var elementView = this;
  1205. $( '.eo-bfc-settings', this.el ).html( '<table class="form-table"></table>' );
  1206. this.model.settings.each( function( setting ) {
  1207. var settingView;
  1208. switch( setting.get('type') ){
  1209. case 'input':
  1210. case 'textarea':
  1211. case 'checkbox':
  1212. case 'range':
  1213. settingView = new formCustomiser.View.EOFormSettingView({ model: setting });
  1214. break;
  1215. case 'options':
  1216. settingView = new formCustomiser.View.EOFormElementSettingOptionsView({ model: setting });
  1217. break;
  1218. }
  1219. setting.on( 'change', elementView.updateSettings, elementView );
  1220. //elementView.listenTo( setting, 'change', elementView.updateSettings );
  1221. $('.eo-bfc-settings table', elementView.el).append( settingView.render().el );
  1222. });
  1223. }
  1224. },
  1225. updatePositions: function( ev, movedModel, to ){
  1226. ev.stopPropagation();
  1227. var from = movedModel.collection.indexOf( movedModel );
  1228. var fromParent = movedModel.get('parent');
  1229. if( EO_SCRIPT_DEBUG ){
  1230. console.log(
  1231. movedModel.id + " moved "
  1232. + " from " + from + " under " + fromParent
  1233. + " to " + to + " under " + this.model.id );
  1234. }
  1235. movedModel.set( 'parent', this.model.id, {silent:true} );
  1236. movedModel.collection.remove( movedModel, {silent:true} );
  1237. this.model.elements.add( movedModel, {at:to, silent: true } );
  1238. },
  1239. addElement: function( element, t, settings ){
  1240. var views = formCustomiser.View;
  1241. var elementView;
  1242. switch( element.get('type') ){
  1243. case 'input':
  1244. case 'url':
  1245. case 'email':
  1246. case 'date':
  1247. case 'phone':
  1248. case 'number':
  1249. case 'antispam':
  1250. case 'discount-code':
  1251. elementView = new views.EOFormElementInputView({model: element});
  1252. break;
  1253. case 'multiselect':
  1254. elementView = new views.EOFormElementSelectView({model: element});
  1255. break;
  1256. default:
  1257. elementView = new views.EOFormElementView({model: element});
  1258. }
  1259. var elementEL = elementView.render().el;
  1260. $('>ul',this.el).append( elementEL );
  1261. if( settings && settings.scroll ){
  1262. $("html, body").animate({ scrollTop: $(elementEL).offset().top-50 }, 400);
  1263. }
  1264. },
  1265. toggleSettingsVisibility: function( ev ){
  1266. ev.stopPropagation();
  1267. if( $( '#eo-bfc-element-'+this.model.id + ' .eo-bfc-settings', this.el ).toggle().is( ":visible" ) ){
  1268. $( '#eo-bfc-element-'+this.model.id + ' .eo-bfc-settings-toggle-arrow', this.el ).html( '&#x25B2;' );
  1269. }else{
  1270. $( '#eo-bfc-element-'+this.model.id + ' .eo-bfc-settings-toggle-arrow', this.el ).html( '&#x25BC;' );
  1271. }
  1272. $("html, body").animate({ scrollTop: $(this.el).offset().top-50 }, 400);
  1273. },
  1274. stopPropagation: function( e ){
  1275. e.stopPropagation();
  1276. },
  1277. dropped: function( ev, index ) {
  1278. ev.stopPropagation();
  1279. this.$el.trigger('update-sort', [this.model, index]);
  1280. },
  1281. updateSettings: function( setting ){
  1282. if( EO_SCRIPT_DEBUG ){
  1283. console.log( 'update setting') ;
  1284. }
  1285. switch( setting.get('type') ){
  1286. case 'input':
  1287. case 'textarea':
  1288. this.model.set( setting.id, setting.get('value'));
  1289. break;
  1290. case 'checkbox':
  1291. this.model.set( setting.id, setting.get('checked'));
  1292. break;
  1293. case 'range':
  1294. the_min_id = setting.get('min_id');
  1295. the_max_id = setting.get('max_id');
  1296. var values = {};
  1297. values[the_min_id] = setting.get('value_min');
  1298. values[the_max_id] = setting.get('value_max');
  1299. this.model.set( values );
  1300. break;
  1301. case 'options':
  1302. this.model.set({
  1303. 'options': setting.get('options'),
  1304. 'selected': setting.get('selected')
  1305. });
  1306. break;
  1307. }
  1308. },
  1309. });
  1310. var EOFormElementView = formCustomiser.View.EOFormElementView;
  1311. formCustomiser.View.EOFormElementInputView = EOFormElementView.extend({
  1312. exampleTemplate: $( '#tmpl-' + 'eo-form-element-example-input' ).html()
  1313. });
  1314. formCustomiser.View.EOFormElementSelectView = EOFormElementView.extend({
  1315. exampleTemplate: $( '#tmpl-' + 'eo-form-element-example-select' ).html()
  1316. });
  1317. formCustomiser.View.EOFormSettingView = Backbone.View.extend({
  1318. tagName: 'tr',
  1319. events: {
  1320. 'keyup': 'triggerSettingChanged',
  1321. 'change': 'triggerSettingChanged',
  1322. 'click .eo-bfc-inline-help': 'preventDefault'
  1323. },
  1324. initialize: function(){
  1325. this.template = _.template( $( '#tmpl-eo-form-element-setting-'+this.model.get('type') ).html( ), null, {
  1326. evaluate: /<#([\s\S]+?)#>/g,
  1327. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  1328. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  1329. });
  1330. if( !this.model.get('live_update') ){
  1331. delete this.events.keyup;
  1332. }else{
  1333. this.events.keyup = "triggerSettingChanged";
  1334. }
  1335. },
  1336. render: function(){
  1337. this.$el.empty().append( this.template( this.model.toJSON() ) );
  1338. if( this.model.get('inline_help') ){
  1339. $('.eo-bfc-inline-help', this.$el ).qtip({
  1340. content: {
  1341. title: this.model.get('inline_help').title,
  1342. text: this.model.get('inline_help').text
  1343. },
  1344. show: {
  1345. solo: true
  1346. },
  1347. //hide: 'unfocus',
  1348. style: {
  1349. classes: 'qtip-wiki qtip-light qtip-shadow'
  1350. },
  1351. position : {
  1352. viewport: $(window)
  1353. }
  1354. });
  1355. }
  1356. return this;
  1357. },
  1358. triggerSettingChanged: function( ev ){
  1359. var code = ev.keyCode || ev.which;
  1360. if ( code && code == '9' ) {
  1361. return;
  1362. }
  1363. switch( this.model.get('type') ){
  1364. case 'input':
  1365. this.model.set( 'value', this.$el.find('input').val() );
  1366. break;
  1367. case 'textarea':
  1368. this.model.set( 'value', this.$el.find('textarea').val() );
  1369. break;
  1370. case 'range':
  1371. this.model.set({
  1372. 'value_min': this.$el.find('input[data-type="min"]').val(),
  1373. 'value_max': this.$el.find('input[data-type="max"]').val()
  1374. });
  1375. break;
  1376. case 'checkbox':
  1377. if( this.model.get('options') ){
  1378. var checked = this.$el.find('input[type="checkbox"]:checked').map(function(){ return $(this).val(); }).get();
  1379. this.model.set( 'checked', checked );
  1380. }else{
  1381. this.model.set( 'checked', this.$el.find('input[type="checkbox"]').prop( 'checked' ) ? 1 : 0 );
  1382. }
  1383. break;
  1384. }
  1385. },
  1386. preventDefault: function( ev ){
  1387. ev.preventDefault();
  1388. }
  1389. });
  1390. formCustomiser.View.EOFormElementSettingOptionsView = formCustomiser.View.EOFormSettingView.extend({
  1391. initialize: function(){
  1392. _.bindAll(this, 'render' );
  1393. this.template = _.template( $( '#tmpl-eo-form-element-setting-'+this.model.get('type') ).html( ), null, {
  1394. evaluate: /<#([\s\S]+?)#>/g,
  1395. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  1396. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  1397. });
  1398. },
  1399. events: {
  1400. 'keyup li input': 'optionChanged',
  1401. 'change input[type=radio]': 'optionSelected',
  1402. 'change input[type=checkbox]': 'optionSelected',
  1403. 'click .eo-bfc-option-add': 'addOptionClicked',
  1404. 'click .eo-bfc-option-remove': 'removeOptionClicked',
  1405. },
  1406. render: function(){
  1407. var self = this;
  1408. this.$el.empty();
  1409. this.$el.append( this.template( this.model.toJSON() ) );
  1410. //Hide remove button when we're down to the last option
  1411. show_remove_option = ( this.model.get('options').length > 1 );
  1412. _.each( this.model.get('options'), function( option, index ) {
  1413. var data = {
  1414. option: option,
  1415. index: index,
  1416. selected: self.model.is_selected( index ),
  1417. option_type: self.model.get('option_type'),
  1418. group: self.model.cid,
  1419. show_remove_button: show_remove_option
  1420. };
  1421. $( 'ul', self.el ).append( _.template( $( '#tmpl-eo-form-element-setting-options-option' ).html(), data, {
  1422. evaluate: /<#([\s\S]+?)#>/g,
  1423. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  1424. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  1425. }));
  1426. });
  1427. return this;
  1428. },
  1429. addOptionClicked: function( ev ){
  1430. var index = $(ev.currentTarget).parents('li').index();
  1431. this.model.insertOptionAt( "New option", index + 1 );
  1432. this.render();
  1433. },
  1434. removeOptionClicked: function( ev ){
  1435. var index = $(ev.currentTarget).parents('li').index();
  1436. this.model.removeOptionAt( index );
  1437. this.render();
  1438. },
  1439. optionSelected: function(){
  1440. var selected;
  1441. if( this.model.get('option_type') == 'checkbox' ){
  1442. selected = $('input:checkbox:checked', this.$el ).map(function(){ return $(this).parents('li').index(); }).get();
  1443. }else{
  1444. selected = $('input:radio:checked', this.$el ).map(function( index ){ return $(this).parents('li').index(); }).get();
  1445. }
  1446. this.model.setSelected( selected );
  1447. },
  1448. optionChanged: function( ev ){
  1449. var code = ev.keyCode || ev.which;
  1450. if ( code && code == '9' ) {
  1451. return;
  1452. }
  1453. var index = $(ev.currentTarget).parents('li').index();
  1454. var option = $(ev.currentTarget).val();
  1455. this.model.setOption( option, index );
  1456. },
  1457. });
  1458. //======================================
  1459. // Initialize
  1460. //======================================
  1461. $(document).ready(function(){
  1462. var form = new formCustomiser.Model.EOForm( eo.form );
  1463. var formController = new formCustomiser.Model.EOFormController({ form: form, forms: eo.forms, metaboxes: eo.element_types });
  1464. var formControllerView = new fo

Large files files are truncated, but you can click here to view the full file