aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2016-05-24 12:00:43 -0400
committerPaul Duncan <pabs@pablotron.org>2016-05-24 12:00:43 -0400
commitc758a064eb97b16fd875c9f5a624bb98f8a774dc (patch)
tree7142b85e14d98ae23a0a25a781d1104fdb91a27b
parent0cfd477f80c3773e97ec5b9a19c13e0aaf229d9f (diff)
downloadguff-c758a064eb97b16fd875c9f5a624bb98f8a774dc.tar.bz2
guff-c758a064eb97b16fd875c9f5a624bb98f8a774dc.zip
add full editing, fts search
-rw-r--r--data/assets/js/admin/dialogs/blog-edit.js20
-rw-r--r--data/assets/js/admin/dialogs/page-edit.js23
-rw-r--r--data/assets/js/admin/dialogs/post-edit.js88
-rw-r--r--data/assets/js/admin/dialogs/project-edit.js21
-rw-r--r--data/assets/js/admin/tabs/posts.js124
-rw-r--r--src/guff.cr196
-rw-r--r--src/views/admin-page.ecr72
7 files changed, 359 insertions, 185 deletions
diff --git a/data/assets/js/admin/dialogs/blog-edit.js b/data/assets/js/admin/dialogs/blog-edit.js
index 46a782b..0084028 100644
--- a/data/assets/js/admin/dialogs/blog-edit.js
+++ b/data/assets/js/admin/dialogs/blog-edit.js
@@ -1,7 +1,23 @@
jQuery(function($) {
"use strict";
- $('#blog-edit-dialog').on('post-data-loaded', function(r) {
- console.log(r);
+ var p = '#blog-edit-';
+
+ $(p + 'dialog').on('guff.loaded', function(ev) {
+ var r = ev.post_data;
+ $(p + 'tags').val(r.tags);
+ });
+
+ $(p + 'confirm').click(function() {
+ $(p + 'dialog').trigger({
+ type: 'guff.save',
+
+ post_data: {
+ tags: $(p + 'tags').val(),
+ },
+ });
+
+ // stop event
+ return false;
});
});
diff --git a/data/assets/js/admin/dialogs/page-edit.js b/data/assets/js/admin/dialogs/page-edit.js
index 8af9ec2..05d69a7 100644
--- a/data/assets/js/admin/dialogs/page-edit.js
+++ b/data/assets/js/admin/dialogs/page-edit.js
@@ -1,7 +1,26 @@
jQuery(function($) {
"use strict";
- $('#page-edit-dialog').on('post-data-loaded', function(r) {
- console.log(r);
+ var p = '#page-edit-';
+
+ $(p + 'dialog').on('guff.loaded', function(ev) {
+ var r = ev.post_data;
+
+ $(p + 'layout a').removeClass('btn-primary').addClass('btn-default');
+ $(p + 'layout a[data-val="' + r.layout + '"]')
+ .toggleClass('btn-primary btn-default');
+ });
+
+ $(p + 'confirm').click(function() {
+ $(p + 'dialog').trigger({
+ type: 'guff.save',
+
+ post_data: {
+ layout: $(p + 'layout .btn-primary').data('val'),
+ },
+ });
+
+ // stop event
+ return false;
});
});
diff --git a/data/assets/js/admin/dialogs/post-edit.js b/data/assets/js/admin/dialogs/post-edit.js
index 31b85ee..01baba1 100644
--- a/data/assets/js/admin/dialogs/post-edit.js
+++ b/data/assets/js/admin/dialogs/post-edit.js
@@ -8,7 +8,7 @@ jQuery(function($) {
if (slug.prop('disabled')) {
slug.val(
name.val().toLowerCase()
- .replace(/[^a-z0-9_\.-]+/g, '-')
+ .replace(/[^a-z0-9_-]+/g, '-')
.replace(/^-+|-+$/g, '')
);
}
@@ -17,9 +17,39 @@ jQuery(function($) {
$.each(['blog', 'page', 'project'], function(i, id) {
var p = '#' + id + '-edit-';
- $(p + 'dialog').one('shown.bs.modal', function() {
- // lazy-init editor
- CKEDITOR.replace(id + '-edit-body');
+ $(p + 'dialog').on('guff.loaded', function(ev) {
+ var r = ev.post_data,
+ slug_lock = (r.slug_lock == "1");
+
+ $(p + 'name').val(r.name);
+ $(p + 'slug').val(r.slug)
+ .prop('disabled', slug_lock ? 'disabled' : null);
+
+ $(p + 'slug-lock')
+ .toggleClass('btn-default', slug_lock)
+ .toggleClass('btn-primary', !slug_lock)
+ .find('fa')
+ .toggleClass('fa-lock', slug_lock)
+ .toggleClass('fa-unlock', !slug_lock);
+
+ var editor = CKEDITOR.instances[id + '-edit-body'];
+ if (!editor) {
+ // lazy-init editor
+ editor = CKEDITOR.replace(id + '-edit-body');
+ }
+
+ if (editor.status == 'ready') {
+ // editor is ready, set body data
+ editor.setData(r.body);
+ } else {
+ editor.once('instanceReady', function() {
+ editor.setData(r.body);
+ });
+ }
+
+ $(p + 'state a').removeClass('btn-primary').addClass('btn-default');
+ $(p + 'state a[data-val="' + r.state + '"]')
+ .toggleClass('btn-primary btn-default');
}).on('show.bs.modal', function() {
var me = $(this);
@@ -50,7 +80,7 @@ jQuery(function($) {
me.find('.modal-body.loading-done').removeClass('hidden');
me.trigger({
- type: "post-data-loaded",
+ type: "guff.loaded",
post_data: r,
});
});
@@ -61,21 +91,40 @@ jQuery(function($) {
$(this).data('close-dialog-confirmed') ||
confirm('Close without saving changes?')
);
- }).find('button[data-dismiss="modal"]').click(function() {
- // override close confirmation
- // FIXME: should this only be on save?
- $(p + 'dialog').data('close-dialog-confirmed', true);
- });
+ }).on('guff.save', function(ev) {
+ $(p + 'confirm').addClass('disabled')
+ .find('.loading').toggleClass('hidden');
+
+ send(id + "/set", $.extend({
+ post_id: $(p + 'dialog').data('post_id'),
+ name: $(p + 'name').val(),
+ slug_lock: $(p + 'slug-lock').hasClass('btn-default') ? 't' : 'f',
+ slug: $(p + 'slug').val(),
+ body: CKEDITOR.instances[id + '-edit-body'].getData(),
+ state: $(p + 'state .btn-primary').data('val'),
+ }, ev.post_data)).always(function() {
+ $(p + 'confirm').removeClass('disabled')
+ .find('.loading').toggleClass('hidden');
+ }).fail(function(r) {
+ var error = r.responseText;
- $(p + 'confirm').click(function() {
- if ($(this).hasClass('disabled'))
- return false;
+ try {
+ var data = $.parseJSON(r.responseText);
+ if (data.error)
+ error = data.error;
+ } catch (e) {}
- // TODO: see #user-add-confirm
- alert('TODO: create');
+ alert('Error: ' + error);
+ }).done(function(r) {
+ // reload posts
+ $('#posts-reload').click();
- // stop event
- return false;
+ // dismiss dialog
+ $(p + 'dialog').data('close-dialog-confirmed', true).modal('hide');
+ });
+ }).find('button[data-dismiss="modal"]').click(function() {
+ // override close confirmation dialog
+ $(p + 'dialog').data('close-dialog-confirmed', true);
});
});
@@ -109,8 +158,9 @@ jQuery(function($) {
return false;
});
- $('.state-buttons').on('a', 'click', function() {
- $(this).parent().find('.btn-primary').toggleClass('btn-default btn-primary');
+ $('.state-buttons a').click(function() {
+ $(this).parent().find('.btn-primary')
+ .toggleClass('btn-default btn-primary');
$(this).toggleClass('btn-default btn-primary');
// stop event
diff --git a/data/assets/js/admin/dialogs/project-edit.js b/data/assets/js/admin/dialogs/project-edit.js
index a31abf2..17236f6 100644
--- a/data/assets/js/admin/dialogs/project-edit.js
+++ b/data/assets/js/admin/dialogs/project-edit.js
@@ -1,7 +1,24 @@
jQuery(function($) {
"use strict";
- $('#project-edit-dialog').on('post-data-loaded', function(r) {
- console.log(r);
+ var p = '#project-edit-';
+
+ $(p + 'dialog').on('guff.loaded', function(ev) {
+ var r = ev.post_data;
+
+ $(p + 'repo').val(r.repo_url);
+ });
+
+ $(p + 'confirm').click(function() {
+ $(p + 'dialog').trigger({
+ type: 'guff.save',
+
+ post_data: {
+ repo_url: $(p + 'repo').val(),
+ },
+ });
+
+ // stop event
+ return false;
});
});
diff --git a/data/assets/js/admin/tabs/posts.js b/data/assets/js/admin/tabs/posts.js
index 00117d6..03f3483 100644
--- a/data/assets/js/admin/tabs/posts.js
+++ b/data/assets/js/admin/tabs/posts.js
@@ -2,122 +2,30 @@ jQuery(function($) {
"use strict";
var TEMPLATES = new LuigiTemplate.Cache({
- user: [
- "<a ",
- "href='#' ",
- "class='list-group-item %{css|h}' ",
- "title='Edit user \"%{user_name|h}\".' ",
- "data-row='%{row|json|h}' ",
- "data-q='%{q|h}' ",
- ">",
- "<i class='fa fa-fw fa-spinner fa-spin hidden loading'></i>",
- "<i class='fa fa-fw fa-user loading'></i>",
- " ",
- "%{user_name|h} (%{email|h})",
-
- "<span class='badge pull-right'>",
- "%{role_name|h}",
- "</span>",
- "</a>",
- ],
-
- loading: [
- "<span class='list-group-item disabled'>",
- "<i class='fa fa-spinner fa-spin'></i>",
- " ",
- "Loading...",
- "</span>",
- ],
-
- error: [
- "<span class='list-group-item list-group-item-danger disabled'>",
- "<i class='fa fa-exclamation-triangle'></i>",
- " ",
- "Error: %{responseText|h}",
- "</span>",
- ],
});
- function update_slug(name, slug) {
- if (slug.prop('disabled')) {
- slug.val(
- name.val().toLowerCase()
- .replace(/[^a-z0-9_\.-]+/g, '-')
- .replace(/^-+|-+$/g, '')
- );
- }
- }
+ $('.add-post').click(function() {
+ var type = $(this).data('type');
- $.each(['blog', 'page', 'project'], function(i, id) {
- var p = '#' + id + '-edit-';
+ // dismiss dropdown
+ $('body').trigger('click');
- $(p + 'dialog').one('shown.bs.modal', function() {
- // lazy-init editor
- CKEDITOR.replace(id + '-edit-body');
- }).on('show.bs.modal', function() {
- // reset close confirmation
- $(this).data('close-dialog-confirmed', false);
-
- // hide all bodies
- $(this).find('.modal-body').addClass('hidden');
- }).on('shown.bs.modal', function() {
- $(p + 'name').focus();
- }).on('hide.bs.modal', function() {
- return (
- $(this).data('close-dialog-confirmed') ||
- confirm('Close without saving changes?')
- );
- }).find('button[data-dismiss="modal"]').click(function() {
- // override close confirmation
- // FIXME: should this only be on save?
- $(p + 'dialog').data('close-dialog-confirmed', true);
- });
+ send(type + '/add').fail(function(r) {
+ var msg = r.responseText;
- $(p + 'confirm').click(function() {
- if ($(this).hasClass('disabled'))
- return false;
+ try {
+ var data = $.parseJSON(r);
+ if (data.error)
+ msg = data.error;
+ } catch (e) {}
- // TODO: see #user-add-confirm
- alert('TODO: create');
+ alert('Error: ' + msg);
+ }).done(function(r) {
+ console.log(r);
- // stop event
- return false;
+ // show edit dialog
+ $('#' + type + '-edit-dialog').data('post_id', r.post_id).modal('show')
});
- });
-
- $('.post-name').keydown(function() {
- var name = $(this),
- slug = $(this).parents('.modal-body').find('.post-slug');
-
- setTimeout(function() {
- update_slug(name, slug);
- }, 10);
- });
-
- $('.post-slug-lock').click(function() {
- var modal_body = $(this).parents('.modal-body');
-
- // toggle locked state
- $(this).toggleClass('btn-default btn-primary')
- .find('.fa').toggleClass('fa-lock fa-unlock');
- var locked = $(this).hasClass('btn-default');
-
- // update slug disabled state
- var slug = modal_body.find('.post-slug');
- slug.prop('disabled', locked ? 'disabled' : null);
-
- if (locked) {
- // auto-generate slug
- update_slug(modal_body.find('.post-name'), slug);
- }
-
- // stop event
- return false;
- });
-
- $('.state-buttons').on('a', 'click', function() {
- $(this).parent().find('.btn-primary').toggleClass('btn-default btn-primary');
- $(this).toggleClass('btn-default btn-primary');
// stop event
return false;
diff --git a/src/guff.cr b/src/guff.cr
index b082b4e..6367671 100644
--- a/src/guff.cr
+++ b/src/guff.cr
@@ -215,6 +215,28 @@ module Guff
end
end
+ class PagedResultSet
+ def initialize(
+ @page : Int32,
+ @num_rows : Int64,
+ @limit : Int32,
+ @rows : Array(Hash(String, String))
+ )
+ end
+
+ def to_json(io)
+ {
+ "meta": {
+ "page": @page,
+ "num_rows": @num_rows,
+ "num_pages": (1.0 * @num_rows / @limit).ceil
+ },
+
+ "rows": @rows
+ }.to_json(io)
+ end
+ end
+
module Models
abstract class Model
def initialize(@context : Context)
@@ -228,12 +250,23 @@ module Guff
(?, ?, (SELECT state_id FROM states WHERE state = 'draft'))
",
+ fts_add: "
+ INSERT INTO posts_fts(rowid, name, slug, body)
+ SELECT post_id, name, slug, body FROM posts WHERE post_id = ?
+ ",
+
set: "
UPDATE posts
SET %s
WHERE post_id = ?
",
+ fts_set: "
+ UPDATE posts_fts
+ SET %s
+ WHERE rowid = ?
+ ",
+
count_posts: "
SELECT COUNT(*)
@@ -290,8 +323,20 @@ module Guff
site_id : Int64,
user_id : Int64,
) : Int64
- @context.dbs.rw.query(SQL[:add], [site_id.to_s, user_id.to_s])
- @context.dbs.rw.last_insert_row_id.to_i64
+ db = @context.dbs.rw
+ post_id = -1_i64
+
+ db.transaction do
+ # add entry
+ db.query(SQL[:add], [site_id.to_s, user_id.to_s])
+ post_id = db.last_insert_row_id.to_i64
+
+ # populate fts index
+ db.query(SQL[:fts_add], [post_id.to_s])
+ end
+
+ # return post_id
+ post_id
end
def set(
@@ -314,6 +359,8 @@ module Guff
)
sets = [] of String
args = [] of String
+ fts_sets = [] of String
+ fts_args = [] of String
if site_id
sets << "site_id = ?"
@@ -351,6 +398,9 @@ module Guff
if slug
sets << "slug = ?"
args << slug
+
+ fts_sets << "slug = ?"
+ fts_args << slug
end
unless slug_lock.nil?
@@ -361,16 +411,29 @@ module Guff
if name
sets << "name = ?"
args << name
+
+ fts_sets << "name = ?"
+ fts_args << name
end
if body
sets << "body = ?"
args << body
+
+ fts_sets << "body = ?"
+ fts_args << body.gsub(/<.+?>/, " ")
end
if sets.size > 0
+ # update posts
args << post_id.to_s
@context.dbs.rw.query(SQL[:set] % sets.join(","), args)
+
+ if fts_sets.size > 0
+ # update posts fts
+ fts_args << post_id.to_s
+ @context.dbs.rw.query(SQL[:fts_set] % fts_sets.join(","), fts_args)
+ end
end
end
@@ -380,6 +443,7 @@ module Guff
site_id : Int64? = nil,
post_type : String? = nil,
state : String? = nil,
+ q : String? = nil,
page : Int32 = 1,
)
filters = %w{1}
@@ -389,11 +453,13 @@ module Guff
raise "invalid page: #{page}" unless page > 0
if site_id
+ # add site filter
filters << "a.site_id = ?"
args << site_id.to_s
end
if post_type
+ # add type filter
filters << case post_type
when "blog"
"c.post_id IS NOT NULL"
@@ -407,12 +473,25 @@ module Guff
end
if state
+ # add state filter
filters << "b.state = ?"
args << state
else
+ # default state filter
filters << "b.state IN ('draft', 'posted')"
end
+ if q && q.match(/\S+/)
+ # add search filter
+ filters << "a.post_id IN (
+ SELECT rowid
+ FROM posts_fts
+ WHERE posts_fts MATCH ?
+ )"
+
+ args << q
+ end
+
# build where clause
filter_sql = filters.join(" AND ")
@@ -441,15 +520,12 @@ module Guff
end
# return results
- {
- "meta": {
- "page": page,
- "num_posts": num_posts,
- "num_pages": (1.0 * num_posts / LIMIT).ceil
- },
-
- "rows": rows,
- }
+ PagedResultSet.new(
+ page: page,
+ num_rows: num_posts,
+ limit: LIMIT,
+ rows: rows,
+ )
end
end
@@ -581,7 +657,7 @@ module Guff
end
def get(post_id : Int64)
- @context.dbs.ro.row(SQL[:get], [post_id.to_s])
+ @context.dbs.ro.row(SQL[:get], [post_id.to_s]).not_nil!
end
end
@@ -710,7 +786,7 @@ module Guff
end
def get(post_id : Int64)
- @context.dbs.ro.row(SQL[:get], [post_id.to_s])
+ @context.dbs.ro.row(SQL[:get], [post_id.to_s]).not_nil!
end
end
@@ -876,7 +952,7 @@ module Guff
end
def get(post_id : Int64)
- @context.dbs.ro.row(SQL[:get], [post_id.to_s])
+ @context.dbs.ro.row(SQL[:get], [post_id.to_s]).not_nil!
end
end
@@ -1138,12 +1214,25 @@ module Guff
LIMIT 1
",
+
+ get_default_id: "
+ SELECT site_id
+
+ FROM sites
+
+ WHERE is_active
+ AND is_default
+ "
}
def get_id(host : String?) : Int64?
r = @context.dbs.ro.one(SQL[:get_id], [host || ""])
r ? r.to_i64 : nil
end
+
+ def get_default_id : Int64
+ @context.dbs.ro.one(SQL[:get_default_id]).not_nil!.to_i64
+ end
end
class RoleModel < Model
@@ -1317,6 +1406,7 @@ module Guff
site_id: params["site_id"]? ? params["site_id"].to_i64 : nil,
state: params["state"]?,
post_type: params["post_type"]?,
+ q: params["q"]?,
page: params["page"].to_i32,
)
end
@@ -1325,7 +1415,7 @@ module Guff
module PageAPI
def do_page_add(params : HTTP::Params)
post_id = @context.models.page.add(
- site_id: params["site_id"].to_i64,
+ site_id: params["site_id"]? ? params["site_id"].to_i64 : @context.models.site.get_default_id,
user_id: @context.user_id.not_nil!,
)
@@ -1356,12 +1446,21 @@ module Guff
nil
end
+
+ def do_page_get(params : HTTP::Params)
+ @context.models.page.get(
+ post_id: params["post_id"].to_i64
+ ).reduce({} of String => String) do |r, k, v|
+ r[k] = v.to_s
+ r
+ end
+ end
end
module ProjectAPI
def do_project_add(params : HTTP::Params)
post_id = @context.models.project.add(
- site_id: params["site_id"].to_i64,
+ site_id: params["site_id"]? ? params["site_id"].to_i64 : @context.models.site.get_default_id,
user_id: @context.user_id.not_nil!,
)
@@ -1392,12 +1491,21 @@ module Guff
nil
end
+
+ def do_project_get(params : HTTP::Params)
+ @context.models.project.get(
+ post_id: params["post_id"].to_i64
+ ).reduce({} of String => String) do |r, k, v|
+ r[k] = v.to_s
+ r
+ end
+ end
end
module BlogAPI
def do_blog_add(params : HTTP::Params)
post_id = @context.models.blog.add(
- site_id: params["site_id"].to_i64,
+ site_id: params["site_id"]? ? params["site_id"].to_i64 : @context.models.site.get_default_id,
user_id: @context.user_id.not_nil!,
)
@@ -1426,6 +1534,15 @@ module Guff
nil
end
+
+ def do_blog_get(params : HTTP::Params)
+ @context.models.blog.get(
+ post_id: params["post_id"].to_i64
+ ).reduce({} of String => String) do |r, k, v|
+ r[k] = v.to_s
+ r
+ end
+ end
end
module UserAPI
@@ -1566,10 +1683,9 @@ module Guff
new_post_button: "
<a
href='#'
- class='btn btn-primary'
+ class='btn btn-primary add-post'
title='Create new blog post.'
- data-toggle='modal'
- data-target='#blog-edit-dialog'
+ data-type='blog'
>
<i class='fa fa-plus-circle'></i>
New Post
@@ -1581,33 +1697,16 @@ module Guff
title='Show additonal options.'
data-toggle='dropdown'
>
- <span class='hidden'>
- <i class='fa fa-plus-circle'></i>
- New
- </span>
-
<i class='fa fa-caret-down'></i>
</a>
<ul class='dropdown-menu'>
- <li class='hidden'>
- <a
- href='#'
- title='Create new blog post.'
- data-toggle='modal'
- data-target='#blog-edit-dialog'
- >
- <i class='fa fa-fw fa-bullhorn'></i>
- New Post
- </a>
- </li>
-
<li>
<a
href='#'
title='Create new page.'
- data-toggle='modal'
- data-target='#page-edit-dialog'
+ class='add-post'
+ data-type='page'
>
<i class='fa fa-fw fa-bookmark-o'></i>
New Page
@@ -1618,8 +1717,8 @@ module Guff
<a
href='#'
title='Create new project.'
- data-toggle='modal'
- data-target='#project-edit-dialog'
+ class='add-post'
+ data-type='project'
>
<i class='fa fa-fw fa-cube'></i>
New Project
@@ -1633,6 +1732,7 @@ module Guff
href='#'
class='btn %s'
title='Mark as %s.'
+ data-val='%s'
>
<i class='fa %s'></i>
%s
@@ -1679,6 +1779,7 @@ module Guff
io << TEMPLATES[:state_button] % [
h(row[:css]),
h(row[:name]),
+ h(row[:id]),
h(row[:icon]),
h(row[:name])
]
@@ -2368,7 +2469,7 @@ module Guff
INSERT INTO states(state_id, state, state_name) VALUES
(1, 'draft', 'Draft'),
(2, 'posted', 'Posted'),
- (3, 'deletd', 'Deleted')
+ (3, 'deleted', 'Deleted')
}, %{
CREATE TABLE posts (
post_id INTEGER PRIMARY KEY,
@@ -2395,13 +2496,19 @@ module Guff
slug = LOWER(slug)
),
- slug_lock BOOLEAN NOT NULL DEFAULT true,
+ slug_lock BOOLEAN NOT NULL DEFAULT 1,
body TEXT NOT NULL DEFAULT ''
)
}, %{
CREATE INDEX in_posts_site_id ON posts(site_id)
}, %{
+ CREATE VIRTUAL TABLE posts_fts USING fts4(
+ name,
+ slug,
+ body
+ )
+ }, %{
CREATE TABLE blogs (
post_id INTEGER PRIMARY KEY
REFERENCES posts(post_id)
@@ -2540,6 +2647,9 @@ module Guff
'This is the body of a test blog entry.'
)
}, %{
+ INSERT INTO posts_fts(rowid, name, slug, body)
+ SELECT post_id, name, slug, body FROM posts
+ }, %{
INSERT INTO pages(post_id, layout_id) VALUES (
1,
(SELECT layout_id FROM layouts WHERE layout = 'default')
diff --git a/src/views/admin-page.ecr b/src/views/admin-page.ecr
index 71beb6f..33beb24 100644
--- a/src/views/admin-page.ecr
+++ b/src/views/admin-page.ecr
@@ -226,7 +226,21 @@
</h4><!-- modal-title -->
</div><!-- modal-header -->
- <div class='modal-body'>
+ <div class='modal-body loading-text'>
+ <p>
+ <i class='fa fa-spinner fa-spin'></i>
+ Loading...
+ </p>
+ </div><!-- modal-body -->
+
+ <div class='modal-body loading-error'>
+ <div class='well'>
+ <i class='fa fa-exclamation-triangle'></i>
+ Error: <span class='error-text'></span>
+ </div><!-- well -->
+ </div><!-- modal-body -->
+
+ <div class='modal-body loading-done'>
<div class='form-group'>
<label for='user-add-name'>
Name
@@ -341,7 +355,7 @@
</div><!-- modal-body -->
<div class='modal-body loading-error'>
- <div class='well well'>
+ <div class='well'>
<i class='fa fa-exclamation-triangle'></i>
Error: <span class='error-text'></span>
</div><!-- well -->
@@ -441,7 +455,7 @@
</h4><!-- modal-title -->
</div><!-- modal-header -->
- <div class='modal-body'>
+ <div class='modal-body loading-done'>
<div class='row'>
<div class='col-md-6'>
<div class='form-group'>
@@ -542,7 +556,10 @@
State
</label>
- <div class='btn-group btn-group-justified state-buttons'><%=
+ <div
+ id='blog-edit-state'
+ class='btn-group btn-group-justified state-buttons'
+ ><%=
state_buttons
%></div><!-- btn-group -->
@@ -604,7 +621,21 @@
</h4><!-- modal-title -->
</div><!-- modal-header -->
- <div class='modal-body'>
+ <div class='modal-body loading-text'>
+ <p>
+ <i class='fa fa-spinner fa-spin'></i>
+ Loading...
+ </p>
+ </div><!-- modal-body -->
+
+ <div class='modal-body loading-error'>
+ <div class='well'>
+ <i class='fa fa-exclamation-triangle'></i>
+ Error: <span class='error-text'></span>
+ </div><!-- well -->
+ </div><!-- modal-body -->
+
+ <div class='modal-body loading-done'>
<div class='row'>
<div class='col-md-6'>
<div class='form-group'>
@@ -683,7 +714,10 @@
Layout
</label>
- <div class='btn-group btn-group-justified state-buttons'>
+ <div
+ id='page-edit-layout'
+ class='btn-group btn-group-justified state-buttons'
+ >
<a
href='#'
class='btn btn-default'
@@ -715,7 +749,10 @@
State
</label>
- <div class='btn-group btn-group-justified state-buttons'><%=
+ <div
+ id='page-edit-state'
+ class='btn-group btn-group-justified state-buttons'
+ ><%=
state_buttons
%></div><!-- btn-group -->
@@ -776,7 +813,21 @@
</h4><!-- modal-title -->
</div><!-- modal-header -->
- <div class='modal-body'>
+ <div class='modal-body loading-text'>
+ <p>
+ <i class='fa fa-spinner fa-spin'></i>
+ Loading...
+ </p>
+ </div><!-- modal-body -->
+
+ <div class='modal-body loading-error'>
+ <div class='well well'>
+ <i class='fa fa-exclamation-triangle'></i>
+ Error: <span class='error-text'></span>
+ </div><!-- well -->
+ </div><!-- modal-body -->
+
+ <div class='modal-body loading-done'>
<div class='row'>
<div class='col-md-6'>
<div class='form-group'>
@@ -877,7 +928,10 @@
State
</label>
- <div class='btn-group btn-group-justified state-buttons'><%=
+ <div
+ id='project-edit-state'
+ class='btn-group btn-group-justified state-buttons'
+ ><%=
state_buttons
%></div><!-- btn-group -->