mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 11:55:03 +03:00
Creates Ember Modal infastructure
resolves #2416 This is a pretty large commit but what it's adding are pretty fundamental to the admin app. - Creates top level actions on the ApplicationRoute for opening and closing modals. This allows sending the 'openModal' action from any template to open a modal. - Every modal template lives in 'templates/modals/{{modalName}}' - Each modal can have a backing controller of the same name that can provide additional control for that modal. Those controllers reside in 'controllers/modals/{{modalName}}' - Created the ModalDialog component which is where all the logic for the component resides. It's not at 100% parity with the existing Ghost modal system but it has the foundation for further fleshing out. It currently accepts parameters for styling how the modal should appear, which previously was defined in JS files in the Backbone admin. - This creates the 'delete all posts', 'delete this post', 'markdown', and 'upload' modal. Some are in more stages of completion than others, but I wanted to just get the foundation in place as fast as possible. - This also creates the UploadModal component which is a subclass of the ModalDialog component. The reason for this subclassing is that the UploadModal component directly accesses the DOM and when that occurs in Ember it should remain in a component definition. It's ready for extending to reach parity. Note: depending on needs the base ModalDialog class may need to be modified.
This commit is contained in:
parent
4dbaf58aba
commit
00da1a43b7
59
ghost/admin/components/modal-dialog.js
Normal file
59
ghost/admin/components/modal-dialog.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
var ModalDialog = Ember.Component.extend({
|
||||||
|
didInsertElement: function () {
|
||||||
|
this.$('#modal-container').fadeIn(50);
|
||||||
|
|
||||||
|
this.$('.modal-background').show().fadeIn(10, function () {
|
||||||
|
$(this).addClass('in');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$('.js-modal').addClass('in');
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement: function () {
|
||||||
|
|
||||||
|
this.$('.js-modal').removeClass('in');
|
||||||
|
|
||||||
|
this.$('.modal-background').removeClass('in');
|
||||||
|
|
||||||
|
return this._super();
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
closeModal: function () {
|
||||||
|
this.sendAction();
|
||||||
|
},
|
||||||
|
confirm: function (type) {
|
||||||
|
var func = this.get('confirm.' + type + '.func');
|
||||||
|
if (typeof func === 'function') {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
this.sendAction();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
klass: function () {
|
||||||
|
var classNames = [];
|
||||||
|
|
||||||
|
classNames.push(this.get('type') ? 'modal-' + this.get('type') : 'modal');
|
||||||
|
|
||||||
|
if (this.get('style')) {
|
||||||
|
this.get('style').split(',').forEach(function (style) {
|
||||||
|
classNames.push('modal-style-' + style);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
classNames.push(this.get('animation'));
|
||||||
|
|
||||||
|
return classNames.join(' ');
|
||||||
|
}.property('type', 'style', 'animation'),
|
||||||
|
|
||||||
|
acceptButtonClass: function () {
|
||||||
|
return this.get('confirm.accept.buttonClass') ? this.get('confirm.accept.buttonClass') : 'button-add';
|
||||||
|
}.property('confirm.accept.buttonClass'),
|
||||||
|
|
||||||
|
rejectButtonClass: function () {
|
||||||
|
return this.get('confirm.reject.buttonClass') ? this.get('confirm.reject.buttonClass') : 'button-delete';
|
||||||
|
}.property('confirm.reject.buttonClass')
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ModalDialog;
|
32
ghost/admin/components/upload-modal.js
Normal file
32
ghost/admin/components/upload-modal.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*global console */
|
||||||
|
|
||||||
|
import ModalDialog from 'ghost/components/modal-dialog';
|
||||||
|
|
||||||
|
var UploadModal = ModalDialog.extend({
|
||||||
|
layoutName: 'components/modal-dialog',
|
||||||
|
|
||||||
|
didInsertElement: function () {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
// @TODO: get this real
|
||||||
|
console.log('UploadController:afterRender');
|
||||||
|
// var filestorage = $('#' + this.options.model.id).data('filestorage');
|
||||||
|
// this.$('.js-drop-zone').upload({fileStorage: filestorage});
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
closeModal: function () {
|
||||||
|
this.sendAction();
|
||||||
|
},
|
||||||
|
confirm: function (type) {
|
||||||
|
var func = this.get('confirm.' + type + '.func');
|
||||||
|
if (typeof func === 'function') {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
this.sendAction();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UploadModal;
|
55
ghost/admin/controllers/modals/delete-all.js
Normal file
55
ghost/admin/controllers/modals/delete-all.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*global alert */
|
||||||
|
|
||||||
|
var DeleteAllController = Ember.Controller.extend({
|
||||||
|
confirm: {
|
||||||
|
accept: {
|
||||||
|
func: function () {
|
||||||
|
// @TODO make the below real :)
|
||||||
|
alert('Deleting everything!');
|
||||||
|
// $.ajax({
|
||||||
|
// url: Ghost.paths.apiRoot + '/db/',
|
||||||
|
// type: 'DELETE',
|
||||||
|
// headers: {
|
||||||
|
// 'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')
|
||||||
|
// },
|
||||||
|
// success: function onSuccess(response) {
|
||||||
|
// if (!response) {
|
||||||
|
// throw new Error('No response received from server.');
|
||||||
|
// }
|
||||||
|
// if (!response.message) {
|
||||||
|
// throw new Error(response.detail || 'Unknown error');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Ghost.notifications.addItem({
|
||||||
|
// type: 'success',
|
||||||
|
// message: response.message,
|
||||||
|
// status: 'passive'
|
||||||
|
// });
|
||||||
|
|
||||||
|
// },
|
||||||
|
// error: function onError(response) {
|
||||||
|
// var responseText = JSON.parse(response.responseText),
|
||||||
|
// message = responseText && responseText.error ? responseText.error : 'unknown';
|
||||||
|
// Ghost.notifications.addItem({
|
||||||
|
// type: 'error',
|
||||||
|
// message: ['A problem was encountered while deleting content from your blog. Error: ', message].join(''),
|
||||||
|
// status: 'passive'
|
||||||
|
// });
|
||||||
|
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
text: "Delete",
|
||||||
|
buttonClass: "button-delete"
|
||||||
|
},
|
||||||
|
reject: {
|
||||||
|
func: function () {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
text: "Cancel",
|
||||||
|
buttonClass: "button"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default DeleteAllController;
|
42
ghost/admin/controllers/modals/delete-post.js
Normal file
42
ghost/admin/controllers/modals/delete-post.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*global alert */
|
||||||
|
|
||||||
|
var DeletePostController = Ember.Controller.extend({
|
||||||
|
confirm: {
|
||||||
|
accept: {
|
||||||
|
func: function () {
|
||||||
|
// @TODO: make this real
|
||||||
|
alert('Deleting post');
|
||||||
|
// self.model.destroy({
|
||||||
|
// wait: true
|
||||||
|
// }).then(function () {
|
||||||
|
// // Redirect to content screen if deleting post from editor.
|
||||||
|
// if (window.location.pathname.indexOf('editor') > -1) {
|
||||||
|
// window.location = Ghost.paths.subdir + '/ghost/content/';
|
||||||
|
// }
|
||||||
|
// Ghost.notifications.addItem({
|
||||||
|
// type: 'success',
|
||||||
|
// message: 'Your post has been deleted.',
|
||||||
|
// status: 'passive'
|
||||||
|
// });
|
||||||
|
// }, function () {
|
||||||
|
// Ghost.notifications.addItem({
|
||||||
|
// type: 'error',
|
||||||
|
// message: 'Your post could not be deleted. Please try again.',
|
||||||
|
// status: 'passive'
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
text: "Delete",
|
||||||
|
buttonClass: "button-delete"
|
||||||
|
},
|
||||||
|
reject: {
|
||||||
|
func: function () {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
text: "Cancel",
|
||||||
|
buttonClass: "button"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default DeletePostController;
|
14
ghost/admin/controllers/modals/upload.js
Normal file
14
ghost/admin/controllers/modals/upload.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
var UploadController = Ember.Controller.extend({
|
||||||
|
confirm: {
|
||||||
|
reject: {
|
||||||
|
func: function () { // The function called on rejection
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
buttonClass: true,
|
||||||
|
text: "Cancel" // The reject button text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UploadController;
|
@ -16,14 +16,6 @@ var SettingsUserController = Ember.Controller.extend({
|
|||||||
}.property('user.image'),
|
}.property('user.image'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
cover: function () {
|
|
||||||
alert('@TODO: Show Upload modal for cover');
|
|
||||||
},
|
|
||||||
|
|
||||||
image: function () {
|
|
||||||
alert('@TODO: Show Upload modal for image');
|
|
||||||
},
|
|
||||||
|
|
||||||
save: function () {
|
save: function () {
|
||||||
alert('@TODO: Saving user...');
|
alert('@TODO: Saving user...');
|
||||||
|
|
||||||
|
25
ghost/admin/routes/application.js
Normal file
25
ghost/admin/routes/application.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
var ApplicationRoute = Ember.Route.extend({
|
||||||
|
actions: {
|
||||||
|
openModal: function (modalName, model) {
|
||||||
|
modalName = 'modals/' + modalName;
|
||||||
|
// We don't always require a modal to have a controller
|
||||||
|
// so we're skipping asserting if one exists
|
||||||
|
if (this.controllerFor(modalName, true)) {
|
||||||
|
this.controllerFor(modalName).set('model', model);
|
||||||
|
}
|
||||||
|
return this.render(modalName, {
|
||||||
|
into: 'application',
|
||||||
|
outlet: 'modal'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
closeModal: function () {
|
||||||
|
return this.disconnectOutlet({
|
||||||
|
outlet: 'modal',
|
||||||
|
parentView: 'application'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ApplicationRoute;
|
@ -4,4 +4,6 @@
|
|||||||
|
|
||||||
<main role="main" id="main">
|
<main role="main" id="main">
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
{{outlet modal}}
|
22
ghost/admin/templates/components/modal-dialog.hbs
Normal file
22
ghost/admin/templates/components/modal-dialog.hbs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<div id="modal-container" {{action bubbles=false preventDefault=false}}>
|
||||||
|
<article {{bind-attr class="klass :js-modal"}}>
|
||||||
|
<section class="modal-content">
|
||||||
|
{{#if title}}<header class="modal-header"><h1>{{title}}</h1></header>{{/if}}
|
||||||
|
{{#if showClose}}<a class="close" href="" title="Close" {{action "closeModal"}}><span class="hidden">Close</span></a>{{/if}}
|
||||||
|
<section class="modal-body">
|
||||||
|
{{yield}}
|
||||||
|
</section>
|
||||||
|
{{#if confirm}}
|
||||||
|
<footer class="modal-footer">
|
||||||
|
<button {{bind-attr class="acceptButtonClass :js-button-accept"}} {{action "confirm" "accept"}}>
|
||||||
|
{{confirm.accept.text}}
|
||||||
|
</button>
|
||||||
|
<button {{bind-attr class="rejectButtonClass :js-button-reject"}} {{action "confirm" "reject"}}>
|
||||||
|
{{confirm.reject.text}}
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
{{/if}}
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div class="modal-background fade" {{action "closeModal"}}></div>
|
@ -8,7 +8,7 @@
|
|||||||
<section class="entry-markdown active">
|
<section class="entry-markdown active">
|
||||||
<header class="floatingheader">
|
<header class="floatingheader">
|
||||||
<small>Markdown</small>
|
<small>Markdown</small>
|
||||||
<a class="markdown-help" href="#"><span class="hidden">What is Markdown?</span></a>
|
<a class="markdown-help" href="" {{action "openModal" "markdown"}}><span class="hidden">What is Markdown?</span></a>
|
||||||
</header>
|
</header>
|
||||||
<section id="entry-markdown-content" class="entry-markdown-content">
|
<section id="entry-markdown-content" class="entry-markdown-content">
|
||||||
{{-codemirror value=markdown scrollPosition=view.scrollPosition}}
|
{{-codemirror value=markdown scrollPosition=view.scrollPosition}}
|
||||||
|
6
ghost/admin/templates/modals/delete-all.hbs
Normal file
6
ghost/admin/templates/modals/delete-all.hbs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{{#modal-dialog action="closeModal" type="action" style="wide,centered" animation="fade"
|
||||||
|
title="Would you really like to delete all content from your blog?" confirm=confirm}}
|
||||||
|
|
||||||
|
<p>This is permanent! No backups, no restores, no magic undo button. <br /> We warned you, ok?</p>
|
||||||
|
|
||||||
|
{{/modal-dialog}}
|
6
ghost/admin/templates/modals/delete-post.hbs
Normal file
6
ghost/admin/templates/modals/delete-post.hbs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{{#modal-dialog action="closeModal" showClose=true type="action" style="wide,centered" animation="fade"
|
||||||
|
title="Are you sure you want to delete this post?" confirm=confirm}}
|
||||||
|
|
||||||
|
<p>This is permanent! No backups, no restores, no magic undo button. <br /> We warned you, ok?</p>
|
||||||
|
|
||||||
|
{{/modal-dialog}}
|
72
ghost/admin/templates/modals/markdown.hbs
Normal file
72
ghost/admin/templates/modals/markdown.hbs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{{#modal-dialog action="closeModal" showClose=true style="wide" animation="fade"
|
||||||
|
title="Markdown Help"}}
|
||||||
|
<section class="markdown-help-container">
|
||||||
|
<table class="modal-markdown-help-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Result</th>
|
||||||
|
<th>Markdown</th>
|
||||||
|
<th>Shortcut</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Bold</strong></td>
|
||||||
|
<td>**text**</td>
|
||||||
|
<td>Ctrl / Cmd + B</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><em>Emphasize</em></td>
|
||||||
|
<td>*text*</td>
|
||||||
|
<td>Ctrl / Cmd + I</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Strike-through</td>
|
||||||
|
<td>~~text~~</td>
|
||||||
|
<td>Ctrl + Alt + U</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><a href="#">Link</a></td>
|
||||||
|
<td>[title](http://)</td>
|
||||||
|
<td>Ctrl + Shift + L</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Image</td>
|
||||||
|
<td>![alt](http://)</td>
|
||||||
|
<td>Ctrl + Shift + I</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>List</td>
|
||||||
|
<td>* item</td>
|
||||||
|
<td>Ctrl + L</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Blockquote</td>
|
||||||
|
<td>> quote</td>
|
||||||
|
<td>Ctrl + Q</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>H1</td>
|
||||||
|
<td># Heading</td>
|
||||||
|
<td>Ctrl + Alt + 1</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>H2</td>
|
||||||
|
<td>## Heading</td>
|
||||||
|
<td>Ctrl + Alt + 2</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>H3</td>
|
||||||
|
<td>### Heading</td>
|
||||||
|
<td>Ctrl + Alt + 3</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Inline Code</code></td>
|
||||||
|
<td>`code`</td>
|
||||||
|
<td>Cmd + K / Ctrl + Shift + K</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
For further Markdown syntax reference: <a href="http://daringfireball.net/projects/markdown/syntax" target="_blank">Markdown Documentation</a>
|
||||||
|
</section>
|
||||||
|
{{/modal-dialog}}
|
9
ghost/admin/templates/modals/upload.hbs
Normal file
9
ghost/admin/templates/modals/upload.hbs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{{#upload-modal action="closeModal" close=true type="action" style="wide"
|
||||||
|
animation="fade"}}
|
||||||
|
|
||||||
|
<section class="js-drop-zone">
|
||||||
|
<img class="js-upload-target" {{bind-attr src=src}} alt="logo">
|
||||||
|
<input data-url="upload" class="js-fileupload main" type="file" name="uploadimage" {{#if options.acceptEncoding}}accept="{{options.acceptEncoding}}"{{/if}}>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{/upload-modal}}
|
@ -26,7 +26,7 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Delete all Content</label>
|
<label>Delete all Content</label>
|
||||||
<a href="javascript:void(0);" class="button-delete js-delete">Delete</a>
|
<a href="javascript:void(0);" class="button-delete js-delete" {{action "openModal" "deleteAll"}}>Delete</a>
|
||||||
<p>Delete all posts and tags from the database.</p>
|
<p>Delete all posts and tags from the database.</p>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
{{#if logo}}
|
{{#if logo}}
|
||||||
<a class="js-modal-logo" href="#"><img id="blog-logo" src="{{logo}}" alt="logo"></a>
|
<a class="js-modal-logo" href="#"><img id="blog-logo" src="{{logo}}" alt="logo"></a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="button-add js-modal-logo" >Upload Image</a>
|
<a class="button-add js-modal-logo" {{action 'openModal' 'upload'}}>Upload Image</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<p>Display a sexy logo for your publication</p>
|
<p>Display a sexy logo for your publication</p>
|
||||||
</div>
|
</div>
|
||||||
@ -41,7 +41,7 @@
|
|||||||
{{#if cover}}
|
{{#if cover}}
|
||||||
<a class="js-modal-cover" href="#"><img id="blog-cover" src="{{cover}}" alt="cover photo"></a>
|
<a class="js-modal-cover" href="#"><img id="blog-cover" src="{{cover}}" alt="cover photo"></a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="button-add js-modal-cover">Upload Image</a>
|
<a class="button-add js-modal-cover" {{action 'openModal' 'upload'}}>Upload Image</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<p>Display a cover image on your site</p>
|
<p>Display a cover image on your site</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<header class="user-profile-header">
|
<header class="user-profile-header">
|
||||||
<img id="user-cover" class="cover-image" {{bind-attr src=cover title=coverTitle}} />
|
<img id="user-cover" class="cover-image" {{bind-attr src=cover title=coverTitle}} />
|
||||||
|
|
||||||
<a class="edit-cover-image js-modal-cover button" {{action 'cover'}}>Change Cover</a>
|
<a class="edit-cover-image js-modal-cover button" {{action 'openModal' 'upload'}}>Change Cover</a>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<form class="user-profile" novalidate="novalidate">
|
<form class="user-profile" novalidate="novalidate">
|
||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<figure class="user-image">
|
<figure class="user-image">
|
||||||
<div id="user-image" class="img" {{bind-attr style=image}} href="#"><span class="hidden">{{name}}'s Picture</span></div>
|
<div id="user-image" class="img" {{bind-attr style=image}} href="#"><span class="hidden">{{name}}'s Picture</span></div>
|
||||||
<a {{action 'image'}} class="edit-user-image js-modal-image">Edit Picture</a>
|
<a href="" {{action 'openModal' 'upload'}} class="edit-user-image js-modal-image">Edit Picture</a>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
Loading…
Reference in New Issue
Block a user