Refactor composer and framer to user same layout
composer touchup; added controls to the bottom; centered input area; removed forms.Base view Fix tests
This commit is contained in:
parent
ecf77b6ab4
commit
a1d4ca9bec
24 changed files with 242 additions and 222 deletions
|
|
@ -6,7 +6,6 @@
|
|||
//= require_tree ./pages
|
||||
//= require_tree ./collections
|
||||
//= require_tree ./views
|
||||
//= require ./forms
|
||||
//= require_tree ./forms
|
||||
|
||||
var app = {
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
app.forms.Base = app.views.Base.extend({
|
||||
formSelector : "form",
|
||||
|
||||
initialize : function() {
|
||||
this.setupFormEvents()
|
||||
},
|
||||
|
||||
setupFormEvents : function(){
|
||||
this.events = {}
|
||||
this.events['submit ' + this.formSelector] = 'setModelAttributes';
|
||||
this.delegateEvents();
|
||||
},
|
||||
|
||||
})
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
app.forms.Picture = app.forms.Base.extend({
|
||||
app.forms.Picture = app.views.Base.extend({
|
||||
templateName : "picture-form",
|
||||
|
||||
events : {
|
||||
|
|
|
|||
|
|
@ -1,48 +1,13 @@
|
|||
app.forms.Post = app.forms.Base.extend({
|
||||
app.forms.Post = app.views.Base.extend({
|
||||
templateName : "post-form",
|
||||
formSelector : ".new-post",
|
||||
className : "post-form",
|
||||
|
||||
subviews : {
|
||||
".aspect_selector" : "aspectsDropdown",
|
||||
".service_selector" : "servicesSelector",
|
||||
".new_picture" : "pictureForm"
|
||||
},
|
||||
|
||||
formAttrs : {
|
||||
// "textarea#text_with_markup" : "text", //fix mentions
|
||||
"textarea.text" : "text",
|
||||
"input.aspect_ids" : "aspect_ids",
|
||||
"input.service:checked" : "services"
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.aspectsDropdown = new app.views.AspectsDropdown();
|
||||
this.servicesSelector = new app.views.ServicesSelector();
|
||||
this.pictureForm = new app.forms.Picture();
|
||||
|
||||
this.setupFormEvents();
|
||||
},
|
||||
|
||||
setModelAttributes : function(evt){
|
||||
if(evt){ evt.preventDefault(); }
|
||||
var form = this.$(this.formSelector);
|
||||
|
||||
this.model.set(_.inject(this.formAttrs, setValueFromField, {}))
|
||||
//pass collections across
|
||||
this.model.photos = this.pictureForm.photos
|
||||
this.model.set({"photos": this.model.photos.toJSON() })
|
||||
|
||||
function setValueFromField(memo, attribute, selector){
|
||||
var selectors = form.find(selector);
|
||||
if(selectors.length > 1) {
|
||||
memo[attribute] = _.map(selectors, function(selector){
|
||||
return $(selector).val()
|
||||
})
|
||||
} else {
|
||||
memo[attribute] = selectors.val();
|
||||
}
|
||||
return memo
|
||||
}
|
||||
},
|
||||
|
||||
postRenderTemplate : function() {
|
||||
|
|
|
|||
67
app/assets/javascripts/app/pages/composer.js
Normal file
67
app/assets/javascripts/app/pages/composer.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
app.pages.Composer = app.views.Base.extend({
|
||||
templateName : "flow",
|
||||
|
||||
subviews : {
|
||||
".flow-content" : "postForm",
|
||||
".flow-controls .controls" : "composerControls"
|
||||
},
|
||||
|
||||
events : {
|
||||
"click button.next" : "navigateNext"
|
||||
},
|
||||
|
||||
formAttrs : {
|
||||
// "textarea#text_with_markup" : "text", //fix mentions
|
||||
"textarea.text" : "text",
|
||||
"input.aspect_ids" : "aspect_ids",
|
||||
"input.service:checked" : "services"
|
||||
},
|
||||
|
||||
|
||||
initialize : function(){
|
||||
app.frame = this.model = new app.models.StatusMessage();
|
||||
this.postForm = new app.forms.Post({model : this.model});
|
||||
this.composerControls = new app.views.ComposerControls({model : this.model});
|
||||
},
|
||||
|
||||
navigateNext : function(){
|
||||
this.setModelAttributes();
|
||||
app.router.navigate("framer", true);
|
||||
},
|
||||
|
||||
setModelAttributes : function(evt){
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
var form = this.$el;
|
||||
|
||||
this.model.set(_.inject(this.formAttrs, setValueFromField, {}))
|
||||
this.model.photos = this.postForm.pictureForm.photos
|
||||
this.model.set({"photos": this.model.photos.toJSON() })
|
||||
|
||||
function setValueFromField(memo, attribute, selector){
|
||||
var selectors = form.find(selector);
|
||||
if(selectors.length > 1) {
|
||||
memo[attribute] = _.map(selectors, function(selector){
|
||||
return this.$(selector).val()
|
||||
})
|
||||
} else {
|
||||
memo[attribute] = selectors.val();
|
||||
}
|
||||
return memo
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.views.ComposerControls = app.views.Base.extend({
|
||||
templateName : 'composer-controls',
|
||||
|
||||
subviews : {
|
||||
".aspect-selector" : "aspectsDropdown",
|
||||
".service-selector" : "servicesSelector",
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.aspectsDropdown = new app.views.AspectsDropdown();
|
||||
this.servicesSelector = new app.views.ServicesSelector();
|
||||
}
|
||||
})
|
||||
|
|
@ -1,15 +1,11 @@
|
|||
app.pages.Framer = app.views.Base.extend({
|
||||
templateName : "framer",
|
||||
templateName : "flow",
|
||||
|
||||
id : "post-content",
|
||||
|
||||
events : {
|
||||
"click button.done" : "saveFrame"
|
||||
},
|
||||
|
||||
subviews : {
|
||||
".post-view" : "postView",
|
||||
".template-picker" : "templatePicker"
|
||||
".flow-content" : "postView",
|
||||
".flow-controls .controls" : "framerControls"
|
||||
},
|
||||
|
||||
initialize : function(){
|
||||
|
|
@ -18,7 +14,8 @@ app.pages.Framer = app.views.Base.extend({
|
|||
|
||||
this.model.bind("change", this.render, this)
|
||||
this.model.bind("sync", this.navigateToShow, this)
|
||||
this.templatePicker = new app.views.TemplatePicker({ model: this.model })
|
||||
|
||||
this.framerControls = new app.views.framerControls({model : this.model})
|
||||
},
|
||||
|
||||
postView : function(){
|
||||
|
|
@ -27,6 +24,22 @@ app.pages.Framer = app.views.Base.extend({
|
|||
|
||||
navigateToShow : function(){
|
||||
app.router.navigate(this.model.url(), {trigger: true, replace: true})
|
||||
}
|
||||
})
|
||||
|
||||
app.views.framerControls = app.views.Base.extend({
|
||||
templateName : 'framer-controls',
|
||||
|
||||
events : {
|
||||
"click button.done" : "saveFrame"
|
||||
},
|
||||
|
||||
subviews : {
|
||||
".template-picker" : 'templatePicker'
|
||||
},
|
||||
|
||||
initialize : function(){
|
||||
this.templatePicker = new app.views.TemplatePicker({ model: this.model })
|
||||
},
|
||||
|
||||
saveFrame : function(){
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
app.pages.PostNew = app.views.Base.extend({
|
||||
templateName : "post-new",
|
||||
|
||||
subviews : { "#new-post" : "postForm"},
|
||||
|
||||
events : {
|
||||
"click button.next" : "navigateNext"
|
||||
},
|
||||
|
||||
initialize : function(){
|
||||
this.model = new app.models.StatusMessage()
|
||||
this.postForm = new app.forms.Post({model : this.model})
|
||||
},
|
||||
|
||||
navigateNext : function(){
|
||||
this.postForm.setModelAttributes()
|
||||
app.frame = this.model;
|
||||
app.router.navigate("framer", true)
|
||||
}
|
||||
});
|
||||
|
|
@ -18,7 +18,7 @@ app.Router = Backbone.Router.extend({
|
|||
"followed_tags": "stream",
|
||||
"tags/:name": "stream",
|
||||
|
||||
"posts/new" : "newPost",
|
||||
"posts/new" : "composer",
|
||||
"posts/:id": "singlePost",
|
||||
"p/:id": "singlePost",
|
||||
"framer": "framer"
|
||||
|
|
@ -41,8 +41,8 @@ app.Router = Backbone.Router.extend({
|
|||
$("#main_stream").html(app.page.render().el);
|
||||
},
|
||||
|
||||
newPost : function(){
|
||||
var page = new app.pages.PostNew();
|
||||
composer : function(){
|
||||
var page = new app.pages.Composer();
|
||||
$("#container").html(page.render().el)
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// licensed under the Affero General Public License version 3 or later. See
|
||||
// the COPYRIGHT file.
|
||||
|
||||
@import "_mixins.css.scss";
|
||||
@import "mixins";
|
||||
|
||||
#login {
|
||||
width: 400px;
|
||||
|
|
|
|||
|
|
@ -304,7 +304,27 @@ article { //mood posts
|
|||
|
||||
$bring-dark-accent-forward-color: #DDD;
|
||||
|
||||
.framer-controls {
|
||||
|
||||
|
||||
div[data-template=flow] {
|
||||
display : table;
|
||||
width : 100%;
|
||||
height : 100%;
|
||||
position : absolute;
|
||||
}
|
||||
|
||||
.flow-content {
|
||||
display : table;
|
||||
width : 100%;
|
||||
height : 100%;
|
||||
}
|
||||
|
||||
.post-form {
|
||||
display : table-cell;
|
||||
vertical-align : middle;
|
||||
}
|
||||
|
||||
.flow-controls {
|
||||
@include info-container-base();
|
||||
z-index: 999;
|
||||
|
||||
|
|
@ -312,8 +332,14 @@ $bring-dark-accent-forward-color: #DDD;
|
|||
width: 100%;
|
||||
bottom: 0;
|
||||
|
||||
padding: 20px 0;
|
||||
max-height: 68px;
|
||||
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
||||
.controls {
|
||||
margin: 20px auto;
|
||||
margin: 0 auto;
|
||||
max-width: 960px;
|
||||
|
||||
text-align: center;
|
||||
|
|
@ -323,6 +349,33 @@ $bring-dark-accent-forward-color: #DDD;
|
|||
}
|
||||
}
|
||||
|
||||
.aspect-selector {
|
||||
float: left;
|
||||
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selected i {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
display : inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.service-selector {
|
||||
float: left;
|
||||
margin-left: 100px;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
bottom : 0;
|
||||
top: auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
a.mood {
|
||||
@include border-radius();
|
||||
margin-right: 20px;
|
||||
|
|
|
|||
|
|
@ -1,27 +1,5 @@
|
|||
.aspects_dropdown {
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selected i {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
display : inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.new_photo .photo{
|
||||
display: inline;
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.new-post-section {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
.aspect_selector {
|
||||
float: right;
|
||||
}
|
||||
3
app/assets/templates/composer-controls.jst.hbs
Normal file
3
app/assets/templates/composer-controls.jst.hbs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<button class="done btn-primary next">Next</button>
|
||||
<div class="aspect-selector"/>
|
||||
<div class="service-selector"/>
|
||||
5
app/assets/templates/flow.jst.hbs
Normal file
5
app/assets/templates/flow.jst.hbs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<div class="flow-content"/>
|
||||
|
||||
<div class="flow-controls">
|
||||
<div class="controls"/>
|
||||
</div>
|
||||
2
app/assets/templates/framer-controls.jst.hbs
Normal file
2
app/assets/templates/framer-controls.jst.hbs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<button class="done btn-primary">done</button>
|
||||
<div class='template-picker'></div>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<div class="framer-controls">
|
||||
<div class="controls">
|
||||
<button class="done btn-primary">done</button>
|
||||
<div class='template-picker'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-view"></div>
|
||||
|
|
@ -1,21 +1,20 @@
|
|||
<div class='row'>
|
||||
<div class='span8 offset2 new-post-section'>
|
||||
<div class="new_picture"/>
|
||||
<div class="container">
|
||||
<div id="new-post" class="row">
|
||||
<div class='span8 offset2 new-post-section'>
|
||||
<form class="new-post">
|
||||
<fieldset>
|
||||
<legend>
|
||||
New Post
|
||||
</legend>
|
||||
<label>
|
||||
text
|
||||
<textarea class="text span8"/>
|
||||
</label>
|
||||
<textarea id="text_with_markup" style="display:none;"/>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<form class="new-post">
|
||||
<fieldset>
|
||||
<legend>
|
||||
New Post
|
||||
</legend>
|
||||
<label>
|
||||
text
|
||||
<textarea class="text span8"/>
|
||||
</label>
|
||||
<textarea id="text_with_markup" style="display:none;"/>
|
||||
|
||||
<div class="aspect_selector"></div>
|
||||
<div class="service_selector"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div class="new_picture"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,3 @@
|
|||
<button class="btn-primary next">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div id="new-post"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ Then /I mention "([^"]*)"$/ do |text|
|
|||
end
|
||||
|
||||
When /^I select "([^"]*)" in my aspects dropdown$/ do |title|
|
||||
within ".aspect_selector" do
|
||||
within ".aspect-selector" do
|
||||
select_from_dropdown(title, aspects_dropdown)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
describe("app.forms.Post", function(){
|
||||
beforeEach(function(){
|
||||
this.post = new app.models.Post();
|
||||
this.view = new app.forms.Post({model : this.post})
|
||||
})
|
||||
|
||||
describe("rendering", function(){
|
||||
beforeEach(function(){
|
||||
this.view.render()
|
||||
})
|
||||
|
||||
|
||||
describe("submitting a valid form", function(){
|
||||
beforeEach(function(){
|
||||
this.view.$("form .text").val("Oh My")
|
||||
this.view.$("form .aspect_ids").val("public")
|
||||
|
||||
/* appending checkboxes */
|
||||
this.view.$(".new-post").append($("<input/>", {
|
||||
value : "fakeBook",
|
||||
checked : "checked",
|
||||
"class" : "service",
|
||||
"type" : "checkbox"
|
||||
}))
|
||||
|
||||
this.view.$(".new-post").append($("<input/>", {
|
||||
value : "twitter",
|
||||
checked : "checked",
|
||||
"class" : "service",
|
||||
"type" : "checkbox"
|
||||
}))
|
||||
})
|
||||
|
||||
it("instantiates a post on form submit", function(){
|
||||
this.view.$(".new-post").submit()
|
||||
expect(this.view.model.get("text")).toBe("Oh My")
|
||||
expect(this.view.model.get("aspect_ids")).toBe("public")
|
||||
expect(this.view.model.get("services").length).toBe(2)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -23,5 +23,4 @@ describe("app.models.Photo", function() {
|
|||
expect(this.photo.createdAt()).toEqual(+date);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
56
spec/javascripts/app/pages/composer_spec.js
Normal file
56
spec/javascripts/app/pages/composer_spec.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
describe("app.pages.Composer", function(){
|
||||
beforeEach(function(){
|
||||
this.page = new app.pages.Composer()
|
||||
})
|
||||
|
||||
it("stores a reference to the form as app.composer" , function(){
|
||||
expect(this.page.model).toBeDefined()
|
||||
expect(app.frame).toBe(this.page.model)
|
||||
});
|
||||
|
||||
describe("rendering", function(){
|
||||
beforeEach(function(){
|
||||
this.page.render();
|
||||
})
|
||||
|
||||
describe("clicking next", function(){
|
||||
beforeEach(function(){
|
||||
spyOn(app.router, "navigate")
|
||||
})
|
||||
|
||||
it("navigates to the framer", function(){
|
||||
this.page.$("button.next").click()
|
||||
expect(app.router.navigate).toHaveBeenCalledWith("framer", true)
|
||||
});
|
||||
|
||||
describe(" setting the model's attributes from the various form fields", function(){
|
||||
beforeEach(function(){
|
||||
this.page.$("form .text").val("Oh My")
|
||||
this.page.$("input.aspect_ids").val("public")
|
||||
|
||||
/* appending checkboxes */
|
||||
this.page.$(".service-selector").append($("<input/>", {
|
||||
value : "fakeBook",
|
||||
checked : "checked",
|
||||
"class" : "service",
|
||||
"type" : "checkbox"
|
||||
}))
|
||||
|
||||
this.page.$(".service-selector").append($("<input/>", {
|
||||
value : "twitter",
|
||||
checked : "checked",
|
||||
"class" : "service",
|
||||
"type" : "checkbox"
|
||||
}))
|
||||
})
|
||||
|
||||
it("instantiates a post on form submit", function(){
|
||||
this.page.$("button.next").click()
|
||||
expect(this.page.model.get("text")).toBe("Oh My")
|
||||
expect(this.page.model.get("aspect_ids")).toBe("public")
|
||||
expect(this.page.model.get("services").length).toBe(2)
|
||||
})
|
||||
});
|
||||
})
|
||||
})
|
||||
});
|
||||
|
|
@ -5,10 +5,6 @@ describe("app.pages.Framer", function(){
|
|||
this.page = new app.pages.Framer();
|
||||
});
|
||||
|
||||
it("passes the model down to the template picker", function(){
|
||||
expect(this.page.templatePicker.model).toBe(app.frame)
|
||||
});
|
||||
|
||||
it("passes the model down to the post view", function(){
|
||||
expect(this.page.postView().model).toBe(app.frame)
|
||||
});
|
||||
|
|
@ -29,5 +25,12 @@ describe("app.pages.Framer", function(){
|
|||
this.page.model.trigger("sync")
|
||||
expect(app.router.navigate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("makes and renders a new post view when the template is changed", function(){
|
||||
expect(app.frame.get("frame_name")).not.toBe("Night") //pre conditions, yo
|
||||
this.page.$("a.mood[data-mood=Night]").click()
|
||||
expect(app.frame.get("frame_name")).toBe("Night")
|
||||
expect(this.page.$("article")).toHaveClass("night")
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
describe("app.pages.PostNew", function(){
|
||||
beforeEach(function(){
|
||||
this.page = new app.pages.PostNew()
|
||||
})
|
||||
|
||||
describe("rendering", function(){
|
||||
beforeEach(function(){
|
||||
this.page.render();
|
||||
})
|
||||
|
||||
describe("clicking next", function(){
|
||||
beforeEach(function(){
|
||||
spyOn(app.router, "navigate")
|
||||
spyOn(this.page.postForm, "setModelAttributes")
|
||||
this.page.$("button.next").click()
|
||||
})
|
||||
|
||||
it("calls tells the form to set the models attributes", function(){
|
||||
expect(this.page.postForm.setModelAttributes).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("stores a reference to the form as app.composer" , function(){
|
||||
expect(this.page.model).toBeDefined()
|
||||
expect(app.frame).toBe(this.page.model)
|
||||
});
|
||||
|
||||
it("navigates to the framer", function(){
|
||||
expect(app.router.navigate).toHaveBeenCalledWith("framer", true)
|
||||
});
|
||||
})
|
||||
})
|
||||
});
|
||||
|
|
@ -11,9 +11,6 @@
|
|||
|
||||
beforeEach(function() {
|
||||
$('#jasmine_content').html(spec.readFixture("underscore_templates"));
|
||||
|
||||
// NOTE Commented (as well as in afterEach) to keep the listeners from rails.js alive.
|
||||
//spec.clearLiveEventBindings();
|
||||
jasmine.Clock.useMock();
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue