# # Marionette.js Item View Documentation # https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.itemview.md # @Character.Generic.DetailsHeaderView = Backbone.Marionette.ItemView.extend template: -> "<button id=save class='save invert' title='Save changes'>Save</button> <button id=cancel class=cancel title='Cancel changes'>Cancel</button> <span id=published class=published><i class='fa fa-eye'></i><i class='fa fa-eye-slash'></i></span> <div id=details_title class=title></div> <a id=delete class=delete href='#' title='Delete this item'> <i class='fa fa-trash-o'></i> </a> <span id=details_meta class=meta></span>" ui: title: '#details_title' meta: '#details_meta' actionSave: '#save' actionCancel: '#cancel' actionPublished: '#published' actionDelete: '#delete' initialize: -> if @model @listenTo(@model, 'change', @render, @) togglePublished: ($input) -> @ui.actionPublished.toggleClass 'off' $input.val @ui.actionPublished.hasClass('off') onRender: -> if @model title = @model.getTitle() updatedFromNow = moment(@model.get('updated_at')).fromNow() @ui.meta.html("updated #{ updatedFromNow }") if @model.has('hidden') @ui.actionPublished.show() @ui.actionPublished.addClass 'off' if @model.get('hidden') else title = @options.title @ui.title.html(title) if not @options.deletable @ui.actionDelete.hide() updateState: (state) -> if @ui if state == 'saving' @ui.actionSave.addClass('disabled') @ui.actionSave.html 'Saving...' else setTimeout ( => # need these checks when create new object, view is recreated @ui.actionSave.removeClass?('disabled') @ui.actionSave.html?('Save') ), 500 # # Marionette.js Layout Documentation # https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.layout.md # @Character.Generic.DetailsLayout = Backbone.Marionette.LayoutView.extend className: 'chr-details' template: -> "<header id=details_header class='chr-details-header'></header> <section id=details_content class='chr-details-content'></section>" regions: header: '#details_header' ui: content: '#details_content' events: 'click #cancel': '_cancel' 'click #save': '_save' 'click #delete': '_delete' 'click #published': '_togglePublished' initialize: -> @module = @options.module @DetailsHeaderView = @module.DetailsHeaderView _togglePublished: -> hiddenInput = _.find @ui.form.find('input[type=hidden]'), (input) -> _( $(input).attr('name') ).endsWith '[hidden]' if hiddenInput @headerView.togglePublished($(hiddenInput)) _save: -> @beforeSave?() if @ui.form.length Character.Generic.Helpers.serializeDataInputs(@ui.content, @ui.form) if @collection # include fields to properly update item in a list and sort params = _.clone(@collection.options.constantParams) if @collection.sortField params.f = _([ params.f, @collection.sortField ]).uniq().join(',') @ui.form.ajaxSubmit data: params beforeSubmit: (arr, $form, options) => @beforeFormSubmit?(arr, $form, options) @headerView.updateState('saving') return true error: (xhr) => chr.execute('showError', xhr) @headerView.updateState() success: (responseText, statusText, xhr, $form) => @headerView.updateState() @_updateModel(responseText) @afterFormSubmitSuccess?(responseText, statusText, xhr, $form) return false _updateModel: (resp) -> # string means form errors returned if typeof(resp) == 'string' return @_renderContent(resp) # assuming response is json if @model @model.set(resp) @collection.sort() else @collection.fetchPage 1, -> Backbone.history.navigate("#/#{chr.currentPath}/edit/#{resp._id}", { trigger: true }) _delete: -> if confirm("""Delete "#{ @model.getTitle() }"?""") # @close() #@destroy() @model.destroy success: -> Backbone.history.navigate("#/#{chr.currentPath}", { trigger: true }) error: (model, response, options) -> chr.execute('error', response) return false _cancel: -> Backbone.history.navigate("#/#{chr.currentPath}", { trigger: true }) _toggleFullscreen: -> @$el.parent().toggleClass('fullscreen') _bindReorderableItems: -> @ui.reorderableItems = @ui.form.find('.sortable') options = delay: 150 items: '> .fields' update: (e, ui) => # # TODO: seems like this could be done much simpler with regex positionFields = _.select @ui.reorderableItems.find("input[type=hidden]"), (f) -> _( $(f).attr('name') ).endsWith('[_position]') _.each positionFields, (el, index, list) -> $(el).val(positionFields.length - index) @ui.reorderableItems.sortable(options).disableSelection() _renderContent: (html) -> if @ui @beforeRenderContent?() @ui.content.html(html) @ui.form = @ui.content.find('form.simple_form') beforeFormHelpersStart?() if @ui.form.length # form related helpers Character.Generic.Helpers.startDateSelect(@ui.form) Character.Generic.Helpers.startEditor(@ui.content, @options.editorOptions) Character.Generic.Helpers.startRedactor(@ui.content, @options.redactorOptions) @_bindReorderableItems() $(document).trigger("chr-details-content.rendered", [ @ui.content ]) $(document).trigger("chr-#{ @module.moduleName }-details-content.rendered", [ @ui.content ]) @afterRenderContent?() onRender: -> window.shortcuts.register_combo { keys: 'meta s', is_exclusive: true, on_keyup: (event) => @_save() } if @options.fullscreen window.shortcuts.register_combo { keys: 'meta e', is_exclusive: true, on_keyup: (event) => @_toggleFullscreen() } @headerView = new @DetailsHeaderView model: @model title: "New #{ @options.objectName }" deletable: @options.deletable @header.show(@headerView) if @model then @$el.addClass('update') @beforeContentRequest?() $.ajax type: 'get' url: @options.formUrl success: (data) => @_renderContent(data) error: (xhr, ajaxOptions, thrownError) => chr.execute('showError', xhr) onDestroy: -> window.closeDetailsView = null if @ui @beforeOnClose?() # unbind save window.shortcuts.unregister_combo 'meta s' # unbind fullscreen @$el.parent().removeClass('fullscreen') window.shortcuts.unregister_combo 'meta e' if @ui.form # form related helpers Character.Generic.Helpers.stopDateSelect(@ui.form) Character.Generic.Helpers.stopEditor(@ui.content) Character.Generic.Helpers.stopRedactor(@ui.content) @ui.reorderableItems.sortable('destroy') if @ui.reorderableItems $(document).trigger("chr-details-content.closed", [ @ui.content ]) $(document).trigger("chr-#{ @module.moduleName }-details-content.closed", [ @ui.content ]) @afterOnClose?()