From 2df699e1373831d3b65b0ee5d9567455e2da34f5 Mon Sep 17 00:00:00 2001 From: Jason Madsen Date: Tue, 19 Aug 2014 14:53:18 -0600 Subject: [PATCH] dialog adapter accepts content and buttons closes CNVS-14912 test plan: - vist new files - verify that restriction modal still displays correctly - verify that name conflict modal (when adding files) continues to work Conflicts: app/coffeescripts/react_files/components/DialogAdapter.coffee Change-Id: Iedfde2bc15733b3bb90639f2f8bf5582d0f5d139 Reviewed-on: https://gerrit.instructure.com/39640 Reviewed-by: Sterling Cobb Tested-by: Jenkins Product-Review: Jason Madsen QA-Review: Jason Madsen --- .../components/DialogAdapter.coffee | 45 ++++++++++-- .../components/DialogButtons.coffee | 9 +++ .../components/DialogContent.coffee | 9 +++ .../components/FileRenameForm.coffee | 68 +++++++++++++------ .../react_files/components/ItemCog.coffee | 10 ++- .../components/RestrictedDialogForm.coffee | 9 +-- .../components/UploadButton.coffee | 3 +- app/stylesheets/pages/ember_files.scss | 5 ++ .../components/FileRenameFormSpec.coffee | 4 +- 9 files changed, 123 insertions(+), 39 deletions(-) create mode 100644 app/coffeescripts/react_files/components/DialogButtons.coffee create mode 100644 app/coffeescripts/react_files/components/DialogContent.coffee diff --git a/app/coffeescripts/react_files/components/DialogAdapter.coffee b/app/coffeescripts/react_files/components/DialogAdapter.coffee index 6d2a9e7d280..34e4c798fab 100644 --- a/app/coffeescripts/react_files/components/DialogAdapter.coffee +++ b/app/coffeescripts/react_files/components/DialogAdapter.coffee @@ -3,9 +3,11 @@ define [ 'react' 'compiled/react/shared/utils/withReactDOM' 'i18n!restrict_student_access' + './DialogContent' + './DialogButtons' 'jqueryui/dialog' -], ($, React, withReactDOM, I18n) -> - +], ($, React, withReactDOM, I18n, DialogContent, DialogButtons) -> + DialogAdapter = React.createClass propTypes: open: React.PropTypes.bool.isRequired @@ -23,17 +25,45 @@ define [ handlePropsChanged: (props) -> props ?= @props - - React.renderComponent( - React.Children.only(props.children), - @node - ) + @forceBuildDialog(props) if props.open @dialog.open() else @dialog.close() + forceBuildDialog: (props) -> + content = null + buttons = null + if React.Children.count(props.children) == 1 + content = props.children + else + {content, buttons} = @processMultipleChildren(props) + + @addContent(content) + @addButtons(buttons) + + processMultipleChildren: (props) -> + content = null + buttons = null + React.Children.forEach props.children, (child) -> + if child.type == DialogContent.type + content = child + if child.type == DialogButtons.type + buttons = child + {content: content, buttons: buttons} + + addContent: (content) -> + React.renderComponent(content, @node) + + addButtons: (buttons) -> + # hack to get buttons to render to buttonset ui + if buttons? + buttonSet = $(@node).parent().find('.ui-dialog-buttonset').html('').get(0) + React.renderComponent(buttons, buttonSet) + else + $(@node).parent().find('.ui-dialog-buttonpane').hide() + componentWillUnmount: -> @dialog.destroy() @@ -46,6 +76,7 @@ define [ open: @props.onOpen title: @props.title autoOpen: false + buttons: [{text: ''}] # force buttonset ui to be created @dialog = $(@node).dialog(options).data('dialog') @handlePropsChanged() diff --git a/app/coffeescripts/react_files/components/DialogButtons.coffee b/app/coffeescripts/react_files/components/DialogButtons.coffee new file mode 100644 index 00000000000..c7224efa9fd --- /dev/null +++ b/app/coffeescripts/react_files/components/DialogButtons.coffee @@ -0,0 +1,9 @@ +define [ + 'react' + 'compiled/react/shared/utils/withReactDOM' +], (React, withReactDOM) -> + + DialogButtons = React.createClass + + render: withReactDOM -> + div {}, @props.children diff --git a/app/coffeescripts/react_files/components/DialogContent.coffee b/app/coffeescripts/react_files/components/DialogContent.coffee new file mode 100644 index 00000000000..2f95367d105 --- /dev/null +++ b/app/coffeescripts/react_files/components/DialogContent.coffee @@ -0,0 +1,9 @@ +define [ + 'react' + 'compiled/react/shared/utils/withReactDOM' +], (React, withReactDOM) -> + + DialogContent = React.createClass + + render: withReactDOM -> + div {}, @props.children diff --git a/app/coffeescripts/react_files/components/FileRenameForm.coffee b/app/coffeescripts/react_files/components/FileRenameForm.coffee index 8b29e3d7b34..5f036e95c2c 100644 --- a/app/coffeescripts/react_files/components/FileRenameForm.coffee +++ b/app/coffeescripts/react_files/components/FileRenameForm.coffee @@ -2,7 +2,10 @@ define [ 'i18n!file_rename_form' 'react' 'compiled/react/shared/utils/withReactDOM' -], (I18n, React, withReactDOM) -> + './DialogAdapter' + './DialogContent' + './DialogButtons' +], (I18n, React, withReactDOM, DialogAdapter, DialogContent, DialogButtons) -> FileRenameForm = React.createClass @@ -31,27 +34,54 @@ define [ handleChangeClick: -> @props.onNameConflictResolved({file: @state.fileOptions.file, dup: 'rename', name: @refs.newName.getDOMNode().value}) + handleFormSubmit: (e) -> + e.preventDefault() + @handleChangeClick() - getPrompt: withReactDOM -> + buildContent: withReactDOM -> nameToUse = @state.fileOptions?.name || @state.fileOptions?.file.name - div {}, - p {}, I18n.t('message','An item named "%{name}" already existings in this location. Do you want to replace the existing file?', {name: nameToUse}) - button ref: 'renameBtn' ,onClick: @handleRenameClick, (I18n.t('change_name', 'Change Name')) - button ref: 'replaceBtn', onClick: @handleReplaceClick, (I18n.t('replace', 'Replace')) + if !@state.isEditing + div {}, + p {}, I18n.t('message','An item named "%{name}" already existings in this location. Do you want to replace the existing file?', {name: nameToUse}) + else + div {}, + p {}, I18n.t('prompt', 'Changee "%{name}" to', {name: nameToUse}) + form onSubmit: @handleFormSubmit, + label className: 'file-rename-form__form-label', + I18n.t('name', 'Name') + input type: 'text', defaultValue: nameToUse, ref: 'newName' + + buildButtons: withReactDOM -> + if !@state.isEditing + div {}, + button + ref: 'renameBtn' + className: 'btn' + onClick: @handleRenameClick, + (I18n.t('change_name', 'Change Name')) + button + ref: 'replaceBtn' + className: 'btn btn-primary' + onClick: @handleReplaceClick, + (I18n.t('replace', 'Replace')) + else + div {}, + button + ref: 'backBtn' + className: 'btn' + onClick: @handleBackClick, + I18n.t('back', 'Back') + button + ref: 'commitChangeBtn' + className: 'btn btn-primary' + onClick: @handleChangeClick, + I18n.t('change', 'Change') - getForm: withReactDOM -> - nameToUse = @state.fileOptions?.name || @state.fileOptions?.file.name - div {}, - p {}, I18n.t('prompt', 'Changee "%{name}" to', {name: nameToUse}) - label {}, I18n.t('name', 'Name') - input type: 'text', defaultValue: nameToUse, ref: 'newName' - button ref: 'backBtn', onClick: @handleBackClick, I18n.t('back', 'Back') - button ref: 'commitChangeBtn', onClick: @handleChangeClick, I18n.t('change', 'Change') render: withReactDOM -> - div {}, - if !@state.isEditing - @getPrompt() - else - @getForm() + DialogAdapter open: @props.fileOptions?, title: I18n.t('rename_title', 'Copy'), onClose: @props.onClose, + DialogContent {}, + @buildContent() + DialogButtons {}, + @buildButtons() diff --git a/app/coffeescripts/react_files/components/ItemCog.coffee b/app/coffeescripts/react_files/components/ItemCog.coffee index b1a52141060..aa09166ab24 100644 --- a/app/coffeescripts/react_files/components/ItemCog.coffee +++ b/app/coffeescripts/react_files/components/ItemCog.coffee @@ -7,7 +7,9 @@ define [ './RestrictedDialogForm' './DialogAdapter' 'i18n!react_files' -], (React, withReactDOM, preventDefault, Folder, File, RestrictedDialogForm, $DialogAdapter, I18n) -> + './DialogContent' + './DialogButtons' +], (React, withReactDOM, preventDefault, Folder, File, RestrictedDialogForm, $DialogAdapter, I18n, DialogContent, DialogButtons) -> # Expects @props.model to be either a folder or a file collection/backbone model ItemCog = React.createClass @@ -40,7 +42,11 @@ define [ div null, $DialogAdapter open: @state.restrictedDialogOpen, title: I18n.t("title.limit_student_access", "Limit student access"), - RestrictedDialogForm closeDialog: @closeRestrictedDialog + DialogContent {}, + RestrictedDialogForm {} + DialogButtons {}, + input type: 'button', onClick: @closeRestrictedDialog, className: "btn", value: I18n.t("button_text.cancel", "Cancel") + input type: "submit", className: "btn btn-primary", value: I18n.t("button_text.update", "Update") div className:'ef-hover-options', a href:'#', className: 'adminCog-download-link', diff --git a/app/coffeescripts/react_files/components/RestrictedDialogForm.coffee b/app/coffeescripts/react_files/components/RestrictedDialogForm.coffee index 532c5177b37..d77ec6b4926 100644 --- a/app/coffeescripts/react_files/components/RestrictedDialogForm.coffee +++ b/app/coffeescripts/react_files/components/RestrictedDialogForm.coffee @@ -9,9 +9,6 @@ define [ getInitialState: -> calendarOption: false - propTypes: - closeDialog: React.PropTypes.func.isRequired - handleSubmit: (event) -> event.preventDefault() @@ -36,7 +33,7 @@ define [ render: withReactDOM -> - form onSubmit: this.handleSubmit, className: 'form-horizontal form-dialog', title: I18n.t("title.limit_student_access", "Limit student access"), + form onSubmit: this.handleSubmit, className: 'form-horizontal', title: I18n.t("title.limit_student_access", "Limit student access"), div className: "radio", label {}, input type: 'radio', name: 'restrict_access', value: 'true', onChange: @radioSelected, defaultChecked: true @@ -49,10 +46,6 @@ define [ @displayOption() - div className:"form-controls", - input type: 'button', onClick: @props.closeDialog, className: "btn", value: I18n.t("button_text.cancel", "Cancel") - input type: "submit", className: "btn btn-primary", value: I18n.t("button_text.update", "Update") - displayOption: -> if @state.calendarOption [ diff --git a/app/coffeescripts/react_files/components/UploadButton.coffee b/app/coffeescripts/react_files/components/UploadButton.coffee index 20ec3c88f21..8f8d024f480 100644 --- a/app/coffeescripts/react_files/components/UploadButton.coffee +++ b/app/coffeescripts/react_files/components/UploadButton.coffee @@ -96,5 +96,4 @@ define [ button className:'btn btn-primary', onClick: @handleAddFilesClick, i className:'icon-plus' I18n.t('files', 'Files') - DialogAdapter open: @state.nameCollisions[0]?, title: I18n.t('rename_title', 'Copy'), onClose: @onClose, - FileRenameForm fileOptions: @state.nameCollisions[0], onNameConflictResolved: @onNameConflictResolved + FileRenameForm fileOptions: @state.nameCollisions[0], onNameConflictResolved: @onNameConflictResolved, onClose: @onClose diff --git a/app/stylesheets/pages/ember_files.scss b/app/stylesheets/pages/ember_files.scss index a6e84d04bea..195841d218a 100644 --- a/app/stylesheets/pages/ember_files.scss +++ b/app/stylesheets/pages/ember_files.scss @@ -307,3 +307,8 @@ $border: #e5e4e4; top: 0; right: 0; } +.file-rename-form__form-label { + float: left; + margin-top: 5px; + padding-right: 5px; +} diff --git a/spec/coffeescripts/react_files/components/FileRenameFormSpec.coffee b/spec/coffeescripts/react_files/components/FileRenameFormSpec.coffee index 2aa5745ef33..13fbac8215a 100644 --- a/spec/coffeescripts/react_files/components/FileRenameFormSpec.coffee +++ b/spec/coffeescripts/react_files/components/FileRenameFormSpec.coffee @@ -18,7 +18,9 @@ define [ @form = React.renderComponent(FileRenameForm(props), $('
').appendTo('body')[0]) teardown: -> - React.unmountComponentAtNode(@form.getDOMNode().parentNode) + #TODO: oddness with the current modal implementation makes teardown not work + #as the DOM has been mutated. Hopefully we can ease this pain with a react modal + #React.unmountComponentAtNode(@form.getDOMNode().parentNode) test 'switches to editing file name state with button click', -> Simulate.click(@form.refs.renameBtn.getDOMNode())