change pages to account for pages set as front page

test plan:
 - with draft state enabled
 - 'Use as Front Page' should be disabled for unpublished pages
 * set a published page as the front page
   - the publish icon should be disabled
   - the delete menu item should be disabled
 * navigate to the front page
   - there should be a visual indicator to indicate the front page
   - the publish button should be disabled
   - the delete menu item should be disabled
 * all other pages should operate normally (edit, etc)

fixes CNVS-7027

Change-Id: I9ebff478c48ccadfbe8bc95f4479dd17552c82a0
Reviewed-on: https://gerrit.instructure.com/24146
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
Product-Review: Bracken Mosbacker <bracken@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: August Thornton <august@instructure.com>
This commit is contained in:
Mark Severson 2013-09-06 12:17:26 -06:00 committed by Bracken Mosbacker
parent 5783efcdb9
commit bead1c3d0b
15 changed files with 124 additions and 74 deletions

View File

@ -18,7 +18,8 @@ require [
default_editing_roles: ENV.DEFAULT_EDITING_ROLES
WIKI_RIGHTS: ENV.WIKI_RIGHTS
view.collection.fetch({data: {sort:'title',per_page:30}}).then ->
view.collection.setParams sort:'title', per_page:30
view.collection.fetch().then ->
view.fetched = true
# Re-render after fetching is complete, but only if there are no pages in the collection
view.render() if view.collection.models.length == 0

View File

@ -4,23 +4,46 @@ define [
'compiled/models/WikiPageRevision'
'compiled/backbone-ext/DefaultUrlMixin'
'compiled/str/splitAssetString'
], (_, Backbone, WikiPageRevision, DefaultUrlMixin, splitAssetString) ->
'i18n!pages'
], (_, Backbone, WikiPageRevision, DefaultUrlMixin, splitAssetString, I18n) ->
pageOptions = ['contextAssetString', 'revision']
class WikiPage extends Backbone.Model
resourceName: 'pages'
@mixin DefaultUrlMixin
url: -> "#{@_defaultUrl()}" + if @get('url') then "/#{@get('url')}" else ''
resourceName: 'pages'
initialize: (attributes, options) ->
super
_.extend(this, _.pick(options || {}, pageOptions))
[@contextName, @contextId] = splitAssetString(@contextAssetString) if @contextAssetString
@set(id: attributes.url) if attributes?.url
@on 'change:front_page', @setPublishable
@on 'change:published', @setPublishable
@setPublishable()
setPublishable: ->
front_page = @get('front_page')
published = @get('published')
publishable = !front_page || !published
deletable = !front_page
@set('publishable', publishable)
@set('deletable', deletable)
if publishable
@unset('publishableMessage')
else
@set('publishableMessage', I18n.t('cannot_unpublish_front_page', 'Cannot unpublish the front page'))
disabledMessage: ->
@get('publishableMessage')
urlRoot: ->
"/api/v1/#{@_contextPath()}/pages"
url: ->
if @get('url') then "#{@urlRoot()}/#{@get('url')}" else @urlRoot()
latestRevision: (options) ->
if !@_latestRevision && @get('url')
unless @_latestRevision
@ -40,36 +63,37 @@ define [
#
# Specifically, the id is removed as the only reason for it's presense is to make Backbone happy
toJSON: ->
_.omit super, 'id'
wiki_page:
_.omit super, 'id'
# Returns a json representation suitable for presenting
present: ->
_.extend _.omit(@toJSON(), 'id'), contextName: @contextName, contextId: @contextId, new_record: !@get('url')
_.extend _.omit(@attributes, 'id'), contextName: @contextName, contextId: @contextId, new_record: !@get('url')
# Uses the api to perform a publish on the page
publish: ->
attributes =
attrs =
wiki_page:
published: true
@save attributes, wait: true
@save attrs, attrs: attrs, wait: true
# Uses the api to perform an unpublish on the page
unpublish: ->
attributes =
attrs =
wiki_page:
published: false
@save attributes, wait: true
@save attrs, attrs: attrs, wait: true
# Uses the api to set the page as the front page
setAsFrontPage: ->
attributes =
setFrontPage: ->
attrs =
wiki_page:
front_page: true
@save attributes, wait: true
@save attrs, attrs: attrs, wait: true
# Uses the api to remove the page as the front page
removeAsFrontPage: ->
attributes =
# Uses the api to unset the page as the front page
unsetFrontPage: ->
attrs =
wiki_page:
front_page: false
@save attributes, wait: true
@save attrs, attrs: attrs, wait: true

View File

@ -21,6 +21,11 @@ define [
'.publish-text': '$text'
'.desc': '$desc'
initialize: ->
super
@model?.on 'change:publishable', =>
@disable() unless @model.get 'publishable'
setElement: ->
super
@disable() unless @model.get 'publishable'

View File

@ -15,7 +15,7 @@ define [
class WikiPageEditView extends ValidatedFormView
@mixin
els:
'[name="wiki_page[body]"]': '$wikiPageBody'
'[name="body"]': '$wikiPageBody'
'.header-bar-outer-container': '$headerBarOuterContainer'
'.page-changed-alert': '$pageChangedAlert'
@ -120,8 +120,8 @@ define [
validateFormData: (data) ->
errors = {}
if data.wiki_page?.title == ''
errors["wiki_page[title]"] = [
if data.title == ''
errors["title"] = [
{
type: 'required'
message: I18n.t("errors.require_title",'You must enter a title')
@ -133,9 +133,9 @@ define [
hasUnsavedChanges: ->
formData = @getFormData()
oldBody = @model.get('body') || ''
newBody = formData.wiki_page?.body || ''
newBody = formData.body || ''
oldTitle = @model.get('title') || ''
newTitle = formData.wiki_page?.title || ''
newTitle = formData.title || ''
return (oldBody != newBody) || (oldTitle != newTitle)
unsavedWarning: ->

View File

@ -41,4 +41,4 @@ define [
openAgain: ->
super
@.$('[name="wiki_page[title]"]').focus()
@.$('[name="title"]').focus()

View File

@ -20,8 +20,7 @@ define [
'click a.al-trigger': 'settingsMenu'
'click .edit-menu-item': 'editPage'
'click .delete-menu-item': 'deletePage'
'click .set-front-page-menu-item': 'setAsFrontPage'
'click .remove-front-page-menu-item': 'removeAsFrontPage'
'click .use-as-front-page-menu-item': 'useAsFrontPage'
@optionProperty 'indexView'
@optionProperty 'collection'
@ -31,7 +30,6 @@ define [
initialize: ->
super
@WIKI_RIGHTS ||= {}
@model.set('publishable', true)
@model.on 'change', => @render()
toJSON: ->
@ -76,14 +74,14 @@ define [
deletePage: (ev) ->
ev?.preventDefault()
return unless @model.get('deletable')
deleteDialog = new WikiPageDeleteDialog
model: @model
deleteDialog.open()
setAsFrontPage: (ev) ->
useAsFrontPage: (ev) ->
ev?.preventDefault()
@model.setAsFrontPage()
return unless @model.get('published')
removeAsFrontPage: (ev) ->
ev?.preventDefault()
@model.removeAsFrontPage()
@model.setFrontPage()

View File

@ -31,7 +31,6 @@ define [
@optionProperty 'PAGE_RIGHTS'
initialize: ->
@model.set('publishable', true)
@model.on 'change', => @render()
super
@WIKI_RIGHTS ||= {}
@ -64,6 +63,7 @@ define [
deleteWikiPage: (ev) ->
ev?.preventDefault()
return unless @model.get('deletable')
deleteDialog = new WikiPageDeleteDialog
model: @model

View File

@ -78,6 +78,14 @@ Cogs, *AKA admin links*, are generally floated to the right, make sure it's the
text-shadow: rgba(0,0,0,0.5) 1px 0 1px;
white-space: nowrap;
}
.ui-menu-item a.disabled,
.ui-menu-item a.disabled.ui-state-focus {
background-color: black;
background-color: rgba(0,0,0,0.7);
background-image: none;
cursor: default;
color: #c0c0c0;
}
.ui-menu-carat {
border-color: transparent;
}

View File

@ -7,6 +7,9 @@
{{/if}}
</div>
<div class="header-bar-right">
{{#if front_page}}
<span class="front-page label">{{#t 'labels.front_page'}}Front Page{{/t}}</span>
{{/if}}
{{#if CAN.PUBLISH}}
<span class="publish-button"></span>
{{/if}}
@ -20,7 +23,7 @@
</a>
<ul class="al-options">
{{#if CAN.DELETE}}
<li><a href="#" class="icon-trash delete_page">{{#t "delete_wiki"}}Delete{{/t}}</a></li>
<li><a href="#" class="icon-trash delete_page{{#unless deletable}} disabled{{/unless}}" {{#unless deletable}}aria-disabled="true"{{/unless}}>{{#t "delete_wiki"}}Delete{{/t}}</a></li>
{{/if}}
{{#if CAN.READ_REVISIONS}}
<li><a href="{{wiki_page_history_path}}" class="icon-clock view_page_history">{{#t "view_page_history_wiki"}}View Page History{{/t}}</a></li>

View File

@ -29,21 +29,21 @@
<div class="edit-content">
<div class="edit-header">
{{#if CAN.EDIT_TITLE}}
<label for="wiki_page[title]" class="screenreader-only">{{#t "title_label"}}Page Title{{/t}}</label>
<input id="wiki_page[title]" name="wiki_page[title]" type="text" class="span4 title" value="{{title}}" maxlength="255" autofocus>
<label for="title" class="screenreader-only">{{#t "title_label"}}Page Title{{/t}}</label>
<input id="title" name="title" type="text" class="span4 title" value="{{title}}" maxlength="255" autofocus>
{{else}}
<h2>{{title}}</h2>
{{/if}}
<a href="#" class="switch_views">{{#t "#editor.switch_views"}}Switch Views{{/t}}</a>
</div>
<textarea rows="16" cols="40" name="wiki_page[body]" class="body" aria-hidden="true"{{#unless PAGE_RIGHTS.update}} autofocus{{/unless}}>{{body}}</textarea>
<textarea rows="16" cols="40" name="body" class="body" aria-hidden="true"{{#unless PAGE_RIGHTS.update}} autofocus{{/unless}}>{{body}}</textarea>
{{#if CAN.EDIT_ROLES}}
<div class="control-group options">
<label class="control-label"><strong>{{#t "options_label"}}Options{{/t}}</strong></label>
<div class="controls">
<select name="wiki_page[editing_roles]">
<select name="editing_roles">
{{#if SHOW.COURSE_ROLES}}
<option value="teachers"{{#if IS.TEACHER_ROLE}} selected{{/if}}>{{#t "course_editing_roles.only_teachers"}}Only teachers{{/t}}</option>
<option value="teachers,students"{{#if IS.STUDENT_ROLE}} selected{{/if}}>{{#t "course_editing_roles.teachers_and_students"}}Teachers and students{{/t}}</option>
@ -62,7 +62,7 @@
<div class="form-actions clearfix">
<div style="height:30px">
<label for="notify_of_update" class="checkbox clearfix pull-left" style="margin-top:5px">
{{checkbox "notify_of_update" prefix="wiki_page"}}
{{checkbox "notify_of_update"}}
{{#t "notify_users_text"}}Notify users that this content has changed{{/t}}
</label>
<a class="btn cancel" tabindex="0" role="button">{{#t "buttons.cancel"}}Cancel{{/t}}</a>

View File

@ -1,6 +1,6 @@
<div class="edit-content">
<label class="edit-label" for="wiki_page[title]">{{#t "page_title"}}Title{{/t}}</label>
<label class="edit-label" for="title">{{#t "page_title"}}Title{{/t}}</label>
<div class="edit-controls">
<input class="edit-control-text" type="text" id="wiki_page[title]" name="wiki_page[title]" value="{{title}}">
<input class="edit-control-text" type="text" id="title" name="title" value="{{title}}">
</div>
</div>

View File

@ -15,12 +15,10 @@
</a>
<ul class="al-options">
<li><a href="#" class="icon-edit edit-menu-item" title="{{#t 'menu.edit'}}Edit{{/t}}">{{#t 'menu.edit'}}Edit{{/t}}</a></li>
<li><a href="#" class="icon-trash delete-menu-item" title="{{#t 'menu.delete'}}Delete{{/t}}">{{#t 'menu.delete'}}Delete{{/t}}</a></li>
{{#if front_page}}
<li><a href="#" class="icon-home remove-front-page-menu-item" title="{{#t 'menu.remove_front_page'}}Remove as Front Page{{/t}}">{{#t 'menu.remove_front_page'}}Remove as Front Page{{/t}}</a></li>
{{else}}
<li><a href="#" class="icon-home set-front-page-menu-item" title="{{#t 'menu.set_front_page'}}Set as Front Page{{/t}}">{{#t 'menu.set_front_page'}}Set as Front Page{{/t}}</a></li>
{{/if}}
<li><a href="#" class="icon-trash delete-menu-item{{#unless deletable}} disabled{{/unless}}" title="{{#t 'menu.delete'}}Delete{{/t}}" {{#unless deletable}}aria-disabled="true"{{/unless}}>{{#t 'menu.delete'}}Delete{{/t}}</a></li>
{{#unless front_page}}
<li><a href="#" class="icon-document use-as-front-page-menu-item{{#unless published}} disabled{{/unless}}" title="{{#t 'menu.use_front_page'}}Use as Front Page{{/t}}" {{#unless published}}aria-disabled="true"{{/unless}}>{{#t 'menu.use_front_page'}}Use as Front Page{{/t}}</a></li>
{{/unless}}
</ul>
</td>
{{/if}}

View File

@ -38,6 +38,26 @@ define [
equal wikiPage.latestRevision().summary, true, 'defaulted to summary'
module 'WikiPage:Publishable'
test 'publishable', ->
wikiPage = new WikiPage
front_page: false
published: true
strictEqual wikiPage.get('publishable'), true, 'publishable set during construction'
wikiPage.set('front_page', true)
strictEqual wikiPage.get('publishable'), false, 'publishable set when front_page changed'
test 'deletable', ->
wikiPage = new WikiPage
front_page: false
published: true
strictEqual wikiPage.get('deletable'), true, 'deletable set during construction'
wikiPage.set('front_page', true)
strictEqual wikiPage.get('deletable'), false, 'deletable set when front_page changed'
module 'WikiPage:Sync'
test 'sets the id during construction', ->
wikiPage = new WikiPage wikiPageObj()
@ -85,18 +105,18 @@ define [
strictEqual attributes.wiki_page.published, false, 'published provided correctly'
wikiPage.unpublish()
test 'setAsFrontPage convenience method', 3, ->
test 'setFrontPage convenience method', 3, ->
wikiPage = new WikiPage wikiPageObj()
sinon.stub wikiPage, 'save', (attributes, options) ->
ok attributes, 'attributes present'
ok attributes.wiki_page, 'wiki_page present'
strictEqual attributes.wiki_page.front_page, true, 'front_page provided correctly'
wikiPage.setAsFrontPage()
wikiPage.setFrontPage()
test 'removeAsFrontPage convenience method', 3, ->
test 'unsetFrontPage convenience method', 3, ->
wikiPage = new WikiPage wikiPageObj()
sinon.stub wikiPage, 'save', (attributes, options) ->
ok attributes, 'attributes present'
ok attributes.wiki_page, 'wiki_page present'
strictEqual attributes.wiki_page.front_page, false, 'front_page provided correctly'
wikiPage.removeAsFrontPage()
wikiPage.unsetFrontPage()

View File

@ -44,8 +44,8 @@ define [
@view.$el.appendTo $('#fixtures')
@view.render()
@titleInput = @view.$el.find('[name="wiki_page[title]"]')
@bodyInput = @view.$el.find('[name="wiki_page[body]"]')
@titleInput = @view.$el.find('[name="title"]')
@bodyInput = @view.$el.find('[name="body"]')
teardown: ->
@scrollSidebarStub.restore()
@initStub.restore()
@ -55,7 +55,7 @@ define [
test 'check for unsaved changes on new model', ->
@titleInput.val('blah')
ok @view.getFormData().wiki_page.title == 'blah', "blah"
ok @view.getFormData().title == 'blah', "blah"
ok @view.hasUnsavedChanges(), 'Changed title'
@titleInput.val('')
ok !@view.hasUnsavedChanges(), 'Unchanged title'
@ -112,15 +112,15 @@ define [
test 'validation of the title is only performed if the title is present', ->
view = new WikiPageEditView
errors = view.validateFormData wiki_page: {body: 'blah'}
strictEqual errors['wiki_page[title]'], undefined, 'no error when title is omitted'
errors = view.validateFormData body: 'blah'
strictEqual errors['title'], undefined, 'no error when title is omitted'
errors = view.validateFormData wiki_page: {title: 'blah', body: 'blah'}
strictEqual errors['wiki_page[title]'], undefined, 'no error when title is present'
errors = view.validateFormData title: 'blah', body: 'blah'
strictEqual errors['title'], undefined, 'no error when title is present'
errors = view.validateFormData wiki_page: {title: '', body: 'blah'}
ok errors['wiki_page[title]'], 'error when title is present, but blank'
ok errors['wiki_page[title]'][0].message, 'error message when title is present, but blank'
errors = view.validateFormData title: '', body: 'blah'
ok errors['title'], 'error when title is present, but blank'
ok errors['title'][0].message, 'error message when title is present, but blank'
module 'WikiPageEditView:JSON'

View File

@ -28,22 +28,15 @@ define [
equal $previousEl.parent().length, 0, 'previous content removed'
equal view.publishIconView.$el.data('test-data'), 'test-is-good', 'test data preserved (by detach)'
test 'delegate setAsFrontPage to the model', ->
test 'delegate useAsFrontPage to the model', ->
model = new WikiPage
front_page: false
published: true
view = new WikiPageIndexItemView
model: model
stub = sinon.stub(model, 'setAsFrontPage')
stub = sinon.stub(model, 'setFrontPage')
view.setAsFrontPage()
ok stub.calledOnce
test 'delegate removeAsFrontPage to the model', ->
model = new WikiPage
view = new WikiPageIndexItemView
model: model
stub = sinon.stub(model, 'removeAsFrontPage')
view.removeAsFrontPage()
view.useAsFrontPage()
ok stub.calledOnce