Add UI/models to allow uploading images
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
###
|
||||
Crafting Guide - markdown_image_controller.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseController = require './base_controller'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class MarkdownImageController extends BaseController
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.model? then throw new Error 'options.model is required'
|
||||
options.templateName = 'markdown_image'
|
||||
super
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@$image = @$('img')
|
||||
@$fileName = @$('.fileName p')
|
||||
@$button = @$('button')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
if @model.mimeType? and @model.encodedData?
|
||||
@$image.attr 'src', "data:#{@model.mimeType};base64,#{@model.encodedData}"
|
||||
else
|
||||
@$image.attr 'src', '/images/unknown.png'
|
||||
|
||||
@$fileName.html @model.fileName
|
||||
|
||||
if @model.encodedData?
|
||||
@$button.html 'Update'
|
||||
else
|
||||
@$button.html 'Choose'
|
||||
|
||||
super
|
||||
@@ -0,0 +1,55 @@
|
||||
###
|
||||
Crafting Guide - markdown_image_list_controller.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseController = require './base_controller'
|
||||
MarkdownImageController = require './markdown_image_controller'
|
||||
MarkdownImageList = require '../models/markdown_image_list'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class MarkdownImageListController extends BaseController
|
||||
|
||||
constructor: (options={})->
|
||||
options.model ?= new MarkdownImageList
|
||||
options.templateName = 'markdown_image_list'
|
||||
super options
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
getMarkdownText: ->
|
||||
return @model.markdownText
|
||||
|
||||
setMarkdownText: (markdownText)->
|
||||
@model.markdownText = markdownText
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
markdownText: {get:@prototype.getMarkdownText, set:@prototype.setMarkdownText}
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@$imageContainer = @$('.image_container')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
@_controllers ?= []
|
||||
index = 0
|
||||
|
||||
for image in @model.all
|
||||
controller = @_controllers[index]
|
||||
if not controller?
|
||||
controller = new MarkdownImageController model:image
|
||||
@_controllers.push controller
|
||||
@$imageContainer.append controller.$el
|
||||
controller.render()
|
||||
else
|
||||
controller.model = image
|
||||
|
||||
index += 1
|
||||
|
||||
while @_controllers.length > index
|
||||
@_controllers.pop().remove()
|
||||
@@ -5,12 +5,13 @@ Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseController = require './base_controller'
|
||||
convertMarkdown = require 'marked'
|
||||
_ = require 'underscore'
|
||||
{Event} = require '../constants'
|
||||
{Url} = require '../constants'
|
||||
w = require 'when'
|
||||
_ = require 'underscore'
|
||||
BaseController = require './base_controller'
|
||||
convertMarkdown = require 'marked'
|
||||
{Event} = require '../constants'
|
||||
MarkdownImageListController = require './markdown_image_list_controller'
|
||||
{Url} = require '../constants'
|
||||
w = require 'when'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
@@ -132,6 +133,8 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@_imageListController = @addChild MarkdownImageListController, '.image_list'
|
||||
|
||||
@$errorText = @$('.error p')
|
||||
@$markdownPanel = @$('.markdown')
|
||||
@$sizer = @$('.sizer')
|
||||
@@ -144,6 +147,7 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
|
||||
refresh: ->
|
||||
@$title.html @title
|
||||
@_imageListController.markdownText = @model
|
||||
|
||||
@_updateSizer()
|
||||
@_updatePreview()
|
||||
@@ -210,6 +214,7 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
editButton: @$('button.edit')
|
||||
editorPanel: @$('.editor')
|
||||
errorPanel: @$('.error')
|
||||
imageList: @$('.image_list')
|
||||
markdownPanel: @$markdownPanel
|
||||
previewButton: @$('button.preview')
|
||||
returnButton: @$('button.return')
|
||||
@@ -226,7 +231,7 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
else if @state is State.creating
|
||||
visible = buttonPanel:true, creatingPanel:true, editButton:true
|
||||
else if @state is State.editing
|
||||
visible = buttonPanel:true, cancelButton:true, editorPanel:true, previewButton:true
|
||||
visible = buttonPanel:true, cancelButton:true, editorPanel:true, previewButton:true, imageList:true
|
||||
else if @state is State.previewing
|
||||
visible = buttonPanel:true, errorPanel:true, markdownPanel:true, returnButton:true, saveButton:true
|
||||
errorText = "remember: your changes aren't saved yet!"
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
###
|
||||
Crafting Guide - markdown_image.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseModel = require './base_model'
|
||||
{Event} = require '../constants'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class MarkdownImage extends BaseModel
|
||||
|
||||
@MIMETYPES = [
|
||||
{patern:/\.png$/i, text:'image/png'}
|
||||
{patern:/\.gif$/i, text:'image/gif'}
|
||||
{patern:/\.jpg$/i, text:'image/jpeg'}
|
||||
{patern:/\.jpeg$/i, text:'image/jpeg'}
|
||||
]
|
||||
|
||||
constructor: (attributes={}, options={})->
|
||||
attributes.encodedData ?= null
|
||||
attributes.fileName ?= ''
|
||||
attributes.path ?= ''
|
||||
attributes.sha ?= null
|
||||
super
|
||||
|
||||
@on Event.change + ':fileName', => @_mimeType = null
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
getFullPath: ->
|
||||
return "#{@path}/#{@fileName}"
|
||||
|
||||
getMimeType: ->
|
||||
if not @_mimeType?
|
||||
for mimeType in MarkdownImage.MIMETYPES
|
||||
if mimeType.pattern.test @fileName
|
||||
@_mimeType = mimeType.text
|
||||
break
|
||||
|
||||
return @_mimeType
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
fullPath: {get:@prototype.getFullPath}
|
||||
@@ -0,0 +1,66 @@
|
||||
###
|
||||
Crafting Guide - markdown_image_list.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseModel = require './base_model'
|
||||
{Event} = require '../constants'
|
||||
MarkdownImage = require './markdown_image'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class MarkdownImageList extends BaseModel
|
||||
|
||||
constructor: (attributes={}, options={})->
|
||||
attributes.markdownText ?= null
|
||||
super attributes, options
|
||||
|
||||
@_images = {}
|
||||
|
||||
@on Event.change + ':markdownText', => @_analyzeMarkdownText()
|
||||
@_analyzeMarkdownText()
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
getAll: ->
|
||||
fileNames = (fileName for fileName, image of @_images).sort()
|
||||
result = []
|
||||
for fileName in fileNames
|
||||
result.push @_images[fileName]
|
||||
|
||||
return result
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
all: {get:@prototype.getAll}
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_analyzeMarkdownText: ->
|
||||
regex = /\!\[([^\]]*)\]\(([^\)]*)\)/g
|
||||
newImages = {}
|
||||
changed = false
|
||||
|
||||
if @markdownText?
|
||||
while true
|
||||
match = regex.exec @markdownText
|
||||
break unless match?
|
||||
|
||||
fileName = match[2]
|
||||
image = @_images[fileName]
|
||||
if not image?
|
||||
image = new MarkdownImage fileName:fileName
|
||||
@trigger Event.add, this, image
|
||||
changed = true
|
||||
|
||||
newImages[fileName] = image
|
||||
|
||||
for fileName, image of @_images
|
||||
if not newImages[fileName]?
|
||||
@trigger Event.remove, this, image
|
||||
changed = true
|
||||
|
||||
if changed
|
||||
@_images = newImages
|
||||
@trigger Event.change, this
|
||||
@@ -0,0 +1,11 @@
|
||||
//-
|
||||
//- Crafting Guide - markdown_image.jade
|
||||
//-
|
||||
//- Copyright (c) 2015 by Redwood Labs
|
||||
//- All rights reserved.
|
||||
//-
|
||||
|
||||
.view__markdown_image
|
||||
img
|
||||
.fileName: p
|
||||
button
|
||||
@@ -0,0 +1,10 @@
|
||||
//-
|
||||
//- Crafting Guide - markdown_image_list.jade
|
||||
//-
|
||||
//- Copyright (c) 2015 by Redwood Labs
|
||||
//- All rights reserved.
|
||||
//-
|
||||
|
||||
.view__markdown_image_list
|
||||
h3 Images Referenced
|
||||
.image_container
|
||||
@@ -10,6 +10,8 @@
|
||||
.panel
|
||||
.waiting.hideable: img(src='/images/wait.gif')
|
||||
.markdown.hideable.hidden
|
||||
.creating.hideable.hidden
|
||||
p Please help by adding a description!
|
||||
.editor.hideable.hidden
|
||||
.instructions
|
||||
p.
|
||||
@@ -17,8 +19,7 @@
|
||||
Flavored Markdown</a>. Use <tt>[[Item Name]]</tt> to link to another item.
|
||||
textarea
|
||||
.sizer
|
||||
.creating.hideable.hidden
|
||||
p Please help by adding a description!
|
||||
.image_list
|
||||
.buttons.hideable.hidden
|
||||
.error.hideable.hidden: p
|
||||
button.return.hideable.hidden return
|
||||
@@ -31,4 +32,4 @@
|
||||
p Your changes will appear on the site in a few minutes.
|
||||
.appologizing.hideable.hidden
|
||||
p Sorry, but something went wrong.
|
||||
p Please try again after a few moments.
|
||||
p Please try again after a few moments.
|
||||
@@ -19,6 +19,8 @@ All rights reserved.
|
||||
@import 'item_selector';
|
||||
@import 'item_selector_element';
|
||||
@import 'login_page';
|
||||
@import 'markdown_image';
|
||||
@import 'markdown_image_list';
|
||||
@import 'markdown_section';
|
||||
@import 'minimal_recipe';
|
||||
@import 'mod';
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Crafting Guide - markdown_image.scss
|
||||
|
||||
Copyright (C) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
.view__markdown_image {
|
||||
position: relative; min-width: 33em;
|
||||
|
||||
display: inline-block;
|
||||
margin-right: 2em;
|
||||
vertical-align: top;
|
||||
|
||||
img {
|
||||
position: absolute; height: 10em; width: 10em;
|
||||
}
|
||||
|
||||
.fileName {
|
||||
height: 3em;
|
||||
|
||||
margin: 1em 0 6em 11em;
|
||||
|
||||
p {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute; left: 7.33em; bottom: 0.66em;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Crafting Guide - markdown_image_list.scss
|
||||
|
||||
Copyright (C) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
.view__markdown_image_list {
|
||||
position: relative; min-width: 33em; width: 100%;
|
||||
|
||||
border-bottom: 0.1em solid $color-gray-medium;
|
||||
margin: 2em 0;
|
||||
padding: 0 0 2em 0;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
###
|
||||
Crafting Guide - markdown_image_list_test.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
MarkdownImageList = require '../src/coffee/models/markdown_image_list'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
list = null
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
describe 'markdown_image_list.coffee', ->
|
||||
|
||||
beforeEach ->
|
||||
list = new MarkdownImageList
|
||||
|
||||
describe '_analyzeMarkdownText', ->
|
||||
|
||||
it 'finds nothing in a null string', ->
|
||||
list.all.should.eql []
|
||||
|
||||
it 'finds nothing in an empty string', ->
|
||||
list.markdownText = ''
|
||||
list.all.should.eql []
|
||||
|
||||
it 'finds nothing when there are no images in the markdown', ->
|
||||
list.markdownText = 'alpha bravo charlie delta'
|
||||
list.all.should.eql []
|
||||
|
||||
it 'finds a single image alone', ->
|
||||
list.markdownText = ''
|
||||
(i.fileName for i in list.all).sort().should.eql ['alpha.png']
|
||||
|
||||
it 'finds a single image inside a markdown document', ->
|
||||
list.markdownText = '# alpha\n bravo charlie\n\n|  |\n|:----------:|\ndelta'
|
||||
(i.fileName for i in list.all).sort().should.eql ['alpha.png']
|
||||
|
||||
it 'finds multiple images inside a markdown document', ->
|
||||
list.markdownText = '| Images |\n|:------:|\n|  |\n|  |\n|  |\n'
|
||||
(i.fileName for i in list.all).sort().should.eql ['alpha.png', 'bravo.png', 'charlie.png']
|
||||
|
||||
it 'adds new images when markdown changes', ->
|
||||
list.markdownText = ''
|
||||
(i.fileName for i in list.all).sort().should.eql ['alpha.png']
|
||||
|
||||
list.markdownText = ', '
|
||||
(i.fileName for i in list.all).sort().should.eql ['alpha.png', 'bravo.png']
|
||||
|
||||
it 'removes missing images when markdown changes', ->
|
||||
list.markdownText = ', '
|
||||
(i.fileName for i in list.all).sort().should.eql ['alpha.png', 'bravo.png']
|
||||
|
||||
list.markdownText = ''
|
||||
(i.fileName for i in list.all).sort().should.eql ['alpha.png']
|
||||
|
||||
it 'does not change remaining images when still present in changed markdown', ->
|
||||
list.markdownText = ''
|
||||
list.all[0].testField = 'foo'
|
||||
|
||||
list.markdownText = ' bravo'
|
||||
list.all[0].testField.should.equal 'foo'
|
||||
Reference in New Issue
Block a user