diff --git a/src/coffee/controllers/item_page_controller.coffee b/src/coffee/controllers/item_page_controller.coffee index 2426c5af8..f161be91d 100644 --- a/src/coffee/controllers/item_page_controller.coffee +++ b/src/coffee/controllers/item_page_controller.coffee @@ -145,14 +145,26 @@ module.exports = class ItemPageController extends PageController if not @model.item? return w.reject new Error 'must have an item' - @client.fetchFile file:GitHub.file.itemDescription modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item - .then (fileRecord)=> - @_editingFile = fileRecord - @model.item.parse fileRecord.content + @client.fetchFile path:GitHub.file.itemDescription modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item + .then (response)=> + @_editingFile = response.json.data + @model.item.parse @_editingFile.content @_descriptionController.model = @model.item.description _endEditingDescription: -> - return w(true).delay(1000) + oldDescription = @model.item.description + @model.item.description = @_descriptionController.model + + args = + content: @model.item.unparse() + message: "User-submitted text for #{@model.item.name}" + path: GitHub.file.itemDescription modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item + sha: @_editingFile.sha + + @client.updateFile args + .catch (e)=> + @model.item.description = oldDescription + throw e _refreshByline: -> mod = @model.item?.modVersion?.mod diff --git a/src/coffee/controllers/markdown_section_controller.coffee b/src/coffee/controllers/markdown_section_controller.coffee index 7dd2a59d6..570b24959 100644 --- a/src/coffee/controllers/markdown_section_controller.coffee +++ b/src/coffee/controllers/markdown_section_controller.coffee @@ -79,7 +79,6 @@ module.exports = class MarkdownSectionController extends BaseController onSaveClicked: (event)-> event.preventDefault() - nextState = State.viewing @state = State.waiting @_endEditing() .then => @@ -87,10 +86,9 @@ module.exports = class MarkdownSectionController extends BaseController .catch (e)=> logger.error "failed to end editing: #{e}" @state = State.appologizing - nextState = State.editing .delay @confirmDuration .then => - @state = nextState + @state = State.viewing onTextChanged: (event)-> event.preventDefault() diff --git a/src/coffee/models/item.coffee b/src/coffee/models/item.coffee index 444962f77..590adb456 100644 --- a/src/coffee/models/item.coffee +++ b/src/coffee/models/item.coffee @@ -45,6 +45,11 @@ module.exports = class Item extends BaseModel return if this.name < that.name then -1 else +1 return 0 + unparse: -> + ItemParser = require './item_parser' # to avoid require cycles + @_parser ?= new ItemParser model:this + return @_parser.unparse() + # Property Methods ############################################################################# getIsCraftable: -> diff --git a/src/coffee/models/parser_versions/item_parser_v1.coffee b/src/coffee/models/parser_versions/item_parser_v1.coffee index 251bce482..6cc05e8c2 100644 --- a/src/coffee/models/parser_versions/item_parser_v1.coffee +++ b/src/coffee/models/parser_versions/item_parser_v1.coffee @@ -17,17 +17,23 @@ module.exports = class ItemParserV1 extends CommandParserVersionBase @_buildItem rawData, model _unparseModel: (builder, model)-> + builder.line 'schema: ', 1 + builder.line() + @_unparseItem builder, model # Command Methods ############################################################################## _command_description: (textParts...)-> - @_rawData.description ?= '' + if not @_rawData.description? + @_rawData.description = '' + else + @_rawData.description += '\n' @_rawData.description += textParts.join ', ' _command_officialUrl: (officialUrl)-> if @_rawData.officialUrl? then throw new Error 'duplicate declaration of "officialUrl"' - if officialUrl.length is 0 then throw new Error 'officialUrl cannot be empty' + if not officialUrl? or (officialUrl.length is 0) then throw new Error 'officialUrl cannot be empty' @_rawData.officialUrl = officialUrl _command_video: (youTubeId, nameParts...)-> @@ -41,6 +47,26 @@ module.exports = class ItemParserV1 extends CommandParserVersionBase # Object Building Methods ###################################################################### _buildItem: (rawData, model)-> - model.description = rawData.description if rawData.description - model.officialUrl = rawData.officialUrl if rawData.officialUrl - model.videos = rawData.videos if rawData.videos + model.description = rawData.description if rawData.description? + model.officialUrl = rawData.officialUrl if rawData.officialUrl? + model.videos = rawData.videos if rawData.videos? + + # Un-parsing Methods ########################################################################### + + _unparseItem: (builder, model)-> + if model.officialUrl? + builder.line 'officialUrl: ', model.officialUrl + builder.line() + + if model.description? + if model.description.indexOf('\n') isnt -1 + builder.line 'description: <<-END' + builder.line model.description + builder.line 'END' + else + builder.line 'description: ', model.description + builder.line() + + for video in model.videos + builder.line 'video: ', video.youTubeId, ', ', video.name + builder.line() diff --git a/test/parser_versions/item_version_parser_v1.test.coffee b/test/parser_versions/item_version_parser_v1.test.coffee new file mode 100644 index 000000000..386aaf272 --- /dev/null +++ b/test/parser_versions/item_version_parser_v1.test.coffee @@ -0,0 +1,100 @@ +### +Crafting Guide - item_parser_v1.test.coffee + +Copyright (c) 2015 by Redwood Labs +All rights reserved. +### + +Item = require '../../src/coffee/models/item' +ItemParserV1 = require '../../src/coffee/models/parser_versions/item_parser_v1' +_ = require 'underscore' + +######################################################################################################################## + +baseText = item = parser = null + +######################################################################################################################## + +describe 'item_parser_v1.coffee', -> + + beforeEach -> + item = new Item name:'alpha' + parser = new ItemParserV1 model:item + + describe 'officialUrl', -> + + it 'may be omitted', -> + parser.parse 'schema: 1\nvideo: youtubeid, Video Alpha\ndescription: Bravo, Charlie' + expect(item.officialUrl).to.be.null + + it 'is assigned properly when given', -> + parser.parse 'schema: 1\nofficialUrl: http://testurl.com' + item.officialUrl.should.equal 'http://testurl.com' + + it 'does not allow duplicate declarations', -> + func = -> parser.parse 'schema: 1\nofficialUrl: http://testurl.com\nofficialUrl: http://testurl2.com' + expect(func).to.throw Error, 'duplicate' + + it 'does not allow an empty value if given', -> + func = -> parser.parse 'schema: 1\nofficialUrl:' + expect(func).to.throw Error, 'empty' + + describe 'description', -> + + it 'may be omitted', -> + parser.parse 'schema: 1\nvideo: youTubeId, Video Alpha\nofficialUrl: http://testurl.com' + expect(item.description).to.be.null + + it 'is assigned properly when given', -> + parser.parse 'schema: 1\ndescription: Alpha Bravo Charlie' + item.description.should.equal 'Alpha Bravo Charlie' + + it 'can be a heredoc', -> + parser.parse 'schema: 1\ndescription: <<-END\nAlpha\nBravo\nCharlie\nEND' + item.description.should.equal 'Alpha\nBravo\nCharlie' + + it 'concatenates multiple declarations', -> + parser.parse 'schema: 1\ndescription: Alpha\ndescription: Bravo' + item.description.should.equal 'Alpha\nBravo' + + describe 'video', -> + + it 'may be omitted', -> + parser.parse 'schema: 1\nofficialUrl: http://testurl.com\ndescription: Alpha Bravo Charlie' + item.videos.should.eql [] + + it 'is assigned properly when given', -> + parser.parse 'schema: 1\nvideo: youtubeid, Alpha Bravo' + item.videos[0].should.eql youTubeId:'youtubeid', name:'Alpha Bravo' + item.videos.length.should.equal 1 + + it 'may be included multiple times', -> + parser.parse 'schema: 1\nvideo: youtubeid1, Alpha\nvideo: youtubeid2, Bravo' + item.videos[0].should.eql youTubeId:'youtubeid1', name:'Alpha' + item.videos[1].should.eql youTubeId:'youtubeid2', name:'Bravo' + item.videos.length.should.equal 2 + + it 'requires a YouTubeId and name', -> + func = -> parser.parse 'schema: 1\nvideo: alpha' + expect(func).to.throw Error, 'requires a name' + + describe 'unparsing', -> + + it 'can round-trip a fully described item', -> + text = """ + schema: 1 + + officialUrl: http://testurl.com + + description: <<-END + Alpha + Bravo + END + + video: youtubeid1, Alpha Bravo + video: youtubeid2, Charlie Delta + + + """ + parser.parse text + parser.unparse().should.equal text