diff --git a/bp-docs.php b/bp-docs.php
index f4c08202..3d84b43e 100644
--- a/bp-docs.php
+++ b/bp-docs.php
@@ -108,6 +108,8 @@ function includes() {
require( BP_DOCS_INCLUDES_PATH . 'theme-bridge.php' );
+ require( BP_DOCS_INCLUDES_PATH . 'edit-lock.php' );
+
// formatting.php contains filters and functions used to modify appearance only
require( BP_DOCS_INCLUDES_PATH . 'formatting.php' );
@@ -173,8 +175,9 @@ function load_constants() {
}
// You should never really need to override this bad boy
- if ( !defined( 'BP_DOCS_INSTALL_PATH' ) )
- define( 'BP_DOCS_INSTALL_PATH', WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . BP_DOCS_PLUGIN_SLUG . DIRECTORY_SEPARATOR );
+ if ( !defined( 'BP_DOCS_INSTALL_PATH' ) ) {
+ define( 'BP_DOCS_INSTALL_PATH', plugin_dir_path( __FILE__ ) );
+ }
// Ditto
if ( !defined( 'BP_DOCS_INCLUDES_PATH' ) )
@@ -541,32 +544,12 @@ function protect_doc_access() {
}
if ( ! bp_docs_current_user_can( $action ) ) {
- $redirect_to = wp_get_referer();
-
- if ( ! $redirect_to || trailingslashit( $redirect_to ) == trailingslashit( wp_guess_url() ) ) {
- $redirect_to = bp_get_root_domain();
- }
-
- switch ( $action ) {
- case 'read' :
- $message = __( 'You are not allowed to read that Doc.', 'bp-docs' );
- break;
+ $redirect_to = wp_login_url( bp_docs_get_doc_link() );
- case 'create' :
- $message = __( 'You are not allowed to create Docs.', 'bp-docs' );
- break;
-
- case 'edit' :
- $message = __( 'You are not allowed to edit that Doc.', 'bp-docs' );
- break;
-
- case 'view_history' :
- $message = __( 'You are not allowed to view that Doc\'s history.', 'bp-docs' );
- break;
- }
-
- bp_core_add_message( $message, 'error' );
- bp_core_redirect( $redirect_to );
+ bp_core_no_access( array(
+ 'mode' => 2,
+ 'redirect' => $redirect_to,
+ ) );
}
}
diff --git a/includes/addon-taxonomy.php b/includes/addon-taxonomy.php
index 2a6929f7..fa64dda6 100644
--- a/includes/addon-taxonomy.php
+++ b/includes/addon-taxonomy.php
@@ -110,7 +110,7 @@ function register_taxonomy() {
function register_with_post_type() {
$this->taxonomies = array( /* 'category', */ $this->docs_tag_tax_name );
- foreach( $this->taxonomies as $tax ) {
+ foreach ( $this->taxonomies as $tax ) {
register_taxonomy_for_object_type( $tax, bp_docs_get_post_type_name() );
}
}
@@ -125,7 +125,7 @@ function register_with_post_type() {
* @return int $post_id Returns the doc's post_id on success
*/
function save_post( $query ) {
- foreach( $this->taxonomies as $tax_name ) {
+ foreach ( $this->taxonomies as $tax_name ) {
if ( $tax_name == 'category' )
$tax_name = 'post_category';
@@ -151,10 +151,6 @@ function save_post( $query ) {
}
wp_set_post_terms( $query->doc_id, $terms, $tax_name );
-
- // Store these terms in the item term cache, to be used for tag clouds etc
- $this->cache_terms_for_item( $terms, $query->doc_id );
-
}
do_action( 'bp_docs_taxonomy_saved', $query );
@@ -180,11 +176,11 @@ function delete_post( $new_status, $old_status, $post ) {
$doc_id = $post->ID;
// Terms for the item (group, user, etc)
- $item_terms = $this->get_item_terms();
+ $item_terms = $this->get_item_terms();
// Terms for the doc
- $doc_terms = wp_get_post_terms( $doc_id, $this->docs_tag_tax_name );
+ $doc_terms = wp_get_post_terms( $doc_id, $this->docs_tag_tax_name );
- foreach( $doc_terms as $doc_term ) {
+ foreach ( $doc_terms as $doc_term ) {
$term_name = $doc_term->name;
// If the term is currently used (should always be true - this is a
@@ -201,8 +197,6 @@ function delete_post( $new_status, $old_status, $post ) {
}
}
}
-
- $this->save_item_terms( $item_terms );
}
/**
@@ -212,72 +206,21 @@ function delete_post( $new_status, $old_status, $post ) {
* @since 1.0-beta
*/
function show_terms() {
- foreach( $this->taxonomies as $tax_name ) {
+ foreach ( $this->taxonomies as $tax_name ) {
$html = '';
- $tagtext = array();
- $tags = wp_get_post_terms( get_the_ID(), $tax_name );
+ $tagtext = array();
+ $tags = wp_get_post_terms( get_the_ID(), $tax_name );
- foreach( $tags as $tag ) {
- $tagtext[] = bp_docs_get_tag_link( array( 'tag' => $tag->name ) );
- }
+ foreach ( $tags as $tag ) {
+ $tagtext[] = bp_docs_get_tag_link( array( 'tag' => $tag->name ) );
+ }
if ( ! empty( $tagtext ) ) {
$html = '
' . sprintf( __( 'Tags: %s', 'bp-docs' ), implode( ', ', $tagtext ) ) . '
';
}
- echo apply_filters( 'bp_docs_taxonomy_show_terms', $html, $tagtext );
- }
- }
-
- /**
- * Store taxonomy terms and their use count for a given item
- *
- * @package BuddyPress Docs
- * @since 1.0-beta
- *
- * @param array $terms The terms submitted in the most recent save
- * @param int $doc_id The unique id of the doc
- */
- function cache_terms_for_item( $terms = array(), $doc_id ) {
- $existing_terms = $this->get_item_terms();
-
- // First, make sure that each submitted term is recorded
- foreach ( $terms as $term ) {
- if ( empty( $existing_terms[$term] ) || ! is_array( $existing_terms[$term] ) )
- $existing_terms[$term] = array();
-
- if ( ! in_array( $doc_id, $existing_terms[$term] ) )
- $existing_terms[$term][] = $doc_id;
+ echo apply_filters( 'bp_docs_taxonomy_show_terms', $html, $tagtext );
}
-
- // Then, loop through to see if any existing terms have been deleted
- foreach ( $existing_terms as $existing_term => $docs ) {
- // If the existing term is not in the list of submitted terms...
- if ( ! in_array( $existing_term, $terms ) ) {
- // ... check to see whether the current doc is listed under that
- // term. If so, that indicates that the term has been removed from
- // the doc
- $key = array_search( $doc_id, $docs );
- if ( $key !== false ) {
- unset( $docs[$key] );
- }
- }
-
- // Reset the array keys for the term's docs
- $docs = array_values( $docs );
-
- if ( empty( $docs ) ) {
- // If there are no more docs associated with the term, we can remove
- // it from the array
- unset( $existing_terms[$existing_term] );
- } else {
- // Othewise, store the docs back in the existing terms array
- $existing_terms[$existing_term] = $docs;
- }
- }
-
- // Save the terms back to the item
- $this->save_item_terms( $existing_terms );
}
/**
@@ -322,23 +265,24 @@ function save_item_terms( $terms ) {
function modify_tax_query( $tax_query ) {
// Check for the existence tag filters in the request URL
- if ( !empty( $_REQUEST['bpd_tag'] ) ) {
+ if ( ! empty( $_REQUEST['bpd_tag'] ) ) {
// The bpd_tag argument may be comma-separated
$tags = explode( ',', urldecode( $_REQUEST['bpd_tag'] ) );
// Clean up the tag input
- foreach( $tags as $key => $value ) {
+ foreach ( $tags as $key => $value ) {
$tags[$key] = esc_attr( $value );
}
$tax_query[] = array(
'taxonomy' => $this->docs_tag_tax_name,
'terms' => $tags,
- 'field' => 'slug'
+ 'field' => 'slug',
);
- if ( !empty( $_REQUEST['bool'] ) && $_REQUEST['bool'] == 'and' )
+ if ( !empty( $_REQUEST['bool'] ) && $_REQUEST['bool'] == 'and' ) {
$tax_query['operator'] = 'AND';
+ }
}
return apply_filters( 'bp_docs_modify_tax_query_for_tax', $tax_query );
@@ -367,11 +311,11 @@ function tags_th() {
*/
function tags_td() {
- $tags = get_the_terms( get_the_ID(), $this->docs_tag_tax_name );
- $tagtext = array();
+ $tags = get_the_terms( get_the_ID(), $this->docs_tag_tax_name );
+ $tagtext = array();
- foreach( (array)$tags as $tag ) {
- if ( !empty( $tag->name ) ) {
+ foreach ( (array) $tags as $tag ) {
+ if ( ! empty( $tag->name ) ) {
$tagtext[] = bp_docs_get_tag_link( array( 'tag' => $tag->name ) );
}
}
@@ -399,10 +343,10 @@ function tags_td() {
function info_header_message( $message, $filters ) {
$this->current_filters = $filters;
- if ( !empty( $filters['tags'] ) ) {
+ if ( ! empty( $filters['tags'] ) ) {
$tagtext = array();
- foreach( $filters['tags'] as $tag ) {
+ foreach ( $filters['tags'] as $tag ) {
$tagtext[] = bp_docs_get_tag_link( array( 'tag' => $tag ) );
}
@@ -436,25 +380,11 @@ function filter_markup() {
location ' . $att_url . ' {
+ rewrite ^.*' . str_replace( '/wp-content/', '', $att_url ) . '([0-9]+)/(.*) /?p=$1&bp-attachment=$2 permanent;
+}
+
';
+ }
+
+ if ( $is_iis7 ) {
+ $help_url = 'https://github.com/boonebgorges/buddypress-docs/wiki/Attachment-Privacy#iis7';
+
+ $help_p = __( 'It looks like you are running
IIS 7. We recommend the following setting in your Web.config file:', 'bp-docs' );
+ $help_p .= '
<rule name="buddypress-docs-attachments">
+ <match url="^' . $att_url . '([0-9]+)/(.*)$"/>
+ <conditions>
+ <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="false"/>
+ </conditions>
+ <action type="Redirect" url="?p={R:1}&bp-attachment={R:2}"/>
+</rule>
';
+ }
+
+ ?>
+
+
+
Your BuddyPress Docs attachments directory is publicly accessible. Doc attachments will not be properly protected from direct viewing, even if the parent Docs are non-public.', 'bp-docs' ) ?>
+
+
+
+
+
+
+
this wiki page for more information.', 'bp-docs' ), $help_url ) ?>
+
+
+
+
+ doc_id = 0;
+
+ $rules = array(
+ 'RewriteEngine On',
+ 'RewriteBase /',
+ 'RewriteRule (.+) ?bp-attachment=$1 [R=302,NC]',
+ );
+
+ if ( ! empty( $rules ) ) {
+ if ( ! file_exists( 'insert_with_markers' ) ) {
+ require_once( ABSPATH . 'wp-admin/includes/misc.php' );
+ }
+ insert_with_markers( $test_dir . DIRECTORY_SEPARATOR . '.htaccess', 'BuddyPress Docs', $rules );
+ }
+ }
+
+ // Make a dummy file
+ file_put_contents( $test_dir . DIRECTORY_SEPARATOR . 'test.html', $test_text );
+ }
+
+ $test_url = $uploads['baseurl'] . '/bp-attachments/0/test.html';
+ $r = wp_remote_get( $test_url );
+
+ // If the response body includes our test text, we have a problem
+ $is_protected = true;
+ if ( ! is_wp_error( $r ) && $r['body'] === $test_text ) {
+ $is_protected = false;
+ }
+
+ // Cache
+ $cache = $is_protected ? '1' : '0';
+ bp_update_option( 'bp_docs_attachment_protection', $cache );
+
+ return $is_protected;
+ }
}
/**
@@ -633,3 +834,10 @@ function bp_docs_enable_attachments() {
$enabled = get_option( 'bp-docs-enable-attachments', 'yes' );
return apply_filters( 'bp_docs_enable_attachments', 'yes' === $enabled );
}
+
+/**
+ * Are attachment downloads protected?
+ */
+function bp_docs_attachment_protection( $force_check = false ) {
+ return buddypress()->bp_docs->attachments->check_is_protected( $force_check );
+}
diff --git a/includes/component.php b/includes/component.php
index 4b1586e4..2dd26f31 100644
--- a/includes/component.php
+++ b/includes/component.php
@@ -120,9 +120,6 @@ function setup_hooks() {
// Respect $activities_template->disable_blogforum_replies
add_filter( 'bp_activity_can_comment', array( $this, 'activity_can_comment' ) );
- // AJAX handler for removing the edit lock when a user clicks away from Edit mode
- add_action( 'wp_ajax_remove_edit_lock', array( $this, 'remove_edit_lock' ) );
-
// Add body class
add_filter( 'bp_get_the_body_class', array( $this, 'body_class' ) );
@@ -474,7 +471,7 @@ function catch_page_load() {
$doc = bp_docs_get_current_doc();
// Todo: get this into a proper method as well, blech
- delete_post_meta( $doc->ID, '_edit_lock' );
+ delete_post_meta( $doc->ID, '_bp_docs_last_pinged' );
bp_core_add_message( __( 'Lock successfully removed', 'bp-docs' ) );
bp_core_redirect( bp_docs_get_doc_link( $doc->ID ) );
@@ -487,7 +484,7 @@ function catch_page_load() {
$doc = bp_docs_get_current_doc();
// Todo: get this into a proper method as well, blech
- delete_post_meta( $doc->ID, '_edit_lock' );
+ delete_post_meta( $doc->ID, '_bp_docs_last_pinged' );
bp_core_redirect( bp_docs_get_doc_link( $doc->ID ) );
}
@@ -984,23 +981,6 @@ function handle_filters() {
bp_core_redirect( $redirect_url );
}
- /**
- * AJAX handler for remove_edit_lock option
- *
- * This function is called when a user is editing a Doc and clicks a link to leave the page
- *
- * @package BuddyPress Docs
- * @since 1.1
- */
- function remove_edit_lock() {
- $doc_id = isset( $_POST['doc_id'] ) ? $_POST['doc_id'] : false;
-
- if ( !$doc_id )
- return false;
-
- delete_post_meta( $doc_id, '_edit_lock' );
- }
-
/**
* Sets the includes URL for use when loading scripts and styles
*
@@ -1029,6 +1009,10 @@ function body_class( $classes ) {
$classes[] = 'mobile';
}
+ if ( bp_docs_is_doc_edit() ) {
+ $classes[] = 'bp-docs-edit';
+ }
+
return array_unique( $classes );
}
@@ -1040,8 +1024,8 @@ function body_class( $classes ) {
public function get_item_terms( $terms ) {
global $wpdb, $bp;
- // Only on global directories
- if ( ! bp_docs_is_global_directory() ) {
+ // Only on global directory and mygroups view
+ if ( ! bp_docs_is_global_directory() && ! bp_docs_is_mygroups_directory() ) {
return $terms;
}
@@ -1115,7 +1099,7 @@ function enqueue_scripts() {
// Edit mode requires bp-docs-js to be dependent on TinyMCE, so we must
// reregister bp-docs-js with the correct dependencies
wp_deregister_script( 'bp-docs-js' );
- wp_register_script( 'bp-docs-js', plugins_url( BP_DOCS_PLUGIN_SLUG . '/includes/js/bp-docs.js' ), array( 'jquery', 'editor' ) );
+ wp_register_script( 'bp-docs-js', plugins_url( BP_DOCS_PLUGIN_SLUG . '/includes/js/bp-docs.js' ), array( 'jquery', 'editor', 'heartbeat' ) );
wp_register_script( 'word-counter', site_url() . '/wp-admin/js/word-count.js', array( 'jquery' ) );
@@ -1124,14 +1108,20 @@ function enqueue_scripts() {
// Only load our JS on the right sorts of pages. Generous to account for
// different item types
- if ( in_array( bp_docs_get_docs_slug(), $this->slugstocheck ) || bp_docs_is_single_doc() || bp_docs_is_global_directory() || bp_docs_is_doc_create() ) {
+ if ( in_array( bp_docs_get_docs_slug(), $this->slugstocheck ) || bp_docs_is_single_doc() || bp_docs_is_global_directory() || bp_docs_is_mygroups_directory() || bp_docs_is_doc_create() ) {
wp_enqueue_script( 'bp-docs-js' );
wp_enqueue_script( 'comment-reply' );
- wp_localize_script( 'bp-docs-js', 'bp_docs', array(
+
+ $strings = array(
'upload_title' => __( 'Upload File', 'bp-docs' ),
'upload_button' => __( 'OK', 'bp-docs' ),
'still_working' => __( 'Still working?', 'bp-docs' ),
- ) );
+ );
+
+ if ( bp_docs_is_doc_edit() ) {
+ $strings['pulse'] = bp_docs_heartbeat_pulse();
+ }
+ wp_localize_script( 'bp-docs-js', 'bp_docs', $strings );
}
}
diff --git a/includes/css/edit.css b/includes/css/edit.css
index a826f632..09467f5f 100644
--- a/includes/css/edit.css
+++ b/includes/css/edit.css
@@ -62,6 +62,10 @@ td.content-column select {
padding: inherit;
}
+.uploader-editor {
+ display: none;
+}
+
/* Theme compat: Text mode editor */
#buddypress .standard-form textarea#doc_content {
width: 100%;
@@ -181,6 +185,9 @@ td.content-column select {
#editorcontainer textarea {
width: 99%; border: none;
border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0; margin-top: -1px; }
+.wp-editor-container {
+ border: 1px solid #eaeaea;
+}
#edButtonHTML,
#edButtonPreview {
background-color: #F1F1F1; padding: 2px 10px;
diff --git a/includes/css/screen.css b/includes/css/screen.css
index 42d3276a..71eab987 100644
--- a/includes/css/screen.css
+++ b/includes/css/screen.css
@@ -1 +1 @@
-.hide-if-no-js{display:none}.description{font-weight:normal;font-style:italic}.description code{font-style:normal;background:#eee;padding:2px 4px}#bp-create-doc-button{float:right;margin:5px 19px;font-weight:bold}body.bp-docs div.page ul{list-style-type:none}#bp-docs-all-docs{width:auto}.doc-tabs{overflow:hidden}.doc-tabs ul{padding-left:0}.doc-tabs li{float:left;margin:0 5px;list-style-type:none}.doc-tabs li:first-child{margin-left:0}.doc-tabs li a{background:#f1f1f1;text-decoration:none;display:block;padding:4px 10px;border-radius:5px 5px 0 0}.doc-tabs li.current a{background:#f3f3f3;color:#555;font-weight:bold}.doc-header h4{margin-bottom:15px !important}.docs-filter{display:block;width:400px;float:left;margin-bottom:15px}.doc-search{float:right;width:250px;text-align:right}.docs-filter-tags{width:100%}.docs-filter-tags ul li{display:block;width:120px;float:left;padding:6px}.doctable{border-collapse:separate;border-spacing:0}.doctable p{padding:0;margin:0}.doctable tr:hover .row-actions{visibility:visible}.doctable tr:nth-child(even){background-color:#f3f3f3}.doctable .bp-doc-trashed-doc .attachment-clip-cell{border-left:4px solid red}.bp-docs-trashed-doc-notice{color:red;font-size:.9em;font-style:italic}#buddypress #bp-docs-all-docs li{background:#eee}#buddypress div.doc-permissions{float:none;width:auto;margin-bottom:1em}#buddypress table.doctable td{vertical-align:top}#buddypress table.doctable tr:nth-child(even){background-color:#f3f3f3}#buddypress table.doctable tr th{background-color:#f3f3f3}.row-actions{visibility:hidden;padding:2px 0 0}body.mobile .row-actions{visibility:visible}.row-actions a{color:#999;font-size:11px}.row-actions a.delete{color:#f00}#docs-filter-submit{margin:10px 4px}.title-cell{width:30%}.author-cell,.created-date-cell,.edited-date-cell{text-align:center;width:100px}.current-orderby a{padding-left:20px}.asc a{background:url(../images/sort-col-asc.gif) no-repeat}.desc a{background:url(../images/sort-col-desc.gif) no-repeat}.doc-edit-link{margin:15px 0 20px 0}.doc-meta,#doc-meta,.docs #comments{padding-top:20px;border-top:1px solid #ddd}div.docs-info-header{background:#f3f3f3;padding:5px 10px;margin-bottom:10px}#associated_group_summary .item{padding-top:1em}#associated_group_summary .meta{font-size:11px;color:#888}#associated_group_summary img.avatar{margin-left:0}#doc-attachments-ul{margin-top:1em;list-style-type:none}#doc-attachments-ul li{margin:0px 5px 0px 0;padding:6px}#doc-attachments-ul li.even{background-color:#f3f3f3}#doc-attachments-ul .doc-attachment-delete{float:right;margin-top:.15em;margin-right:.3em}.bp-docs-attachment-clip{cursor:pointer;display:block;margin-top:10px}.doc-attachment-mime-icon{display:block;float:left;width:24px;height:24px;margin-right:5px;background:transparent url("../images/mime-type-sprites.png") no-repeat}.doc-attachment-mime-tar,.doc-attachment-mime-zip,.doc-attachment-mime-gz,.doc-attachment-mime-gzip,.doc-attachment-mime-rar,.doc-attachment-mime-7z{background-position:0 0px}.doc-attachment-mime-mp3,.doc-attachment-mime-m4a,.doc-attachment-mime-m4b,.doc-attachment-mime-ra,.doc-attachment-mime-ram,.doc-attachment-mime-wav,.doc-attachment-mime-ogg,.doc-attachment-mime-oga,.doc-attachment-mime-mid,.doc-attachment-mime-midi,.doc-attachment-mime-wma,.doc-attachment-mime-mka{background-position:0 -40px}.doc-attachment-mime-ics{background-position:0 -80px}.doc-attachment-mime-mdb,.doc-attachment-mime-odb{background-position:0 -120px}.doc-attachment-mime-odg{background-position:0 -160px}.doc-attachment-mime-jpg,.doc-attachment-mime-jpeg,.doc-attachment-mime-gif,.doc-attachment-mime-png,.doc-attachment-mime-bmp,.doc-attachment-mime-tif,.doc-attachment-mime-tiff,.doc-attachment-mime-ico{background-position:0 -200px}.doc-attachment-mime-pdf{background-position:0 -240px}.doc-attachment-mime-xla,.doc-attachment-mime-xls,.doc-attachment-mime-xlt,.doc-attachment-mime-xlw,.doc-attachment-mime-xlsx,.doc-attachment-mime-xlsm,.doc-attachment-mime-xlsb,.doc-attachment-mime-xlsb,.doc-attachment-mime-xlsx,.doc-attachment-mime-xlsm,.doc-attachment-mime-xlam,.doc-attachment-mime-ods,.doc-attachment-mime-odc{background-position:0 -280px}.doc-attachment-mime-txt,.doc-attachment-mime-asc,.doc-attachment-mime-c,.doc-attachment-mime-cc,.doc-attachment-mime-h,.doc-attachment-mime-csv,.doc-attachment-mime-tsv,.doc-attachment-mime-ics,.doc-attachment-mime-rtx,.doc-attachment-mime-css,.doc-attachment-mime-htm,.doc-attachment-mime-html{background-position:0 -320px}.doc-attachment-mime-asf,.doc-attachment-mime-asx,.doc-attachment-mime-wax,.doc-attachment-mime-wmv,.doc-attachment-mime-wmx,.doc-attachment-mime-avi,.doc-attachment-mime-divx,.doc-attachment-mime-flv,.doc-attachment-mime-mov,.doc-attachment-mime-qt,.doc-attachment-mime-mpeg,.doc-attachment-mime-mpg,.doc-attachment-mime-mpe,.doc-attachment-mime-mp4,.doc-attachment-mime-m4v,.doc-attachment-mime-ogv,.doc-attachment-mime-mkv{background-position:0 -360px}body.js .bp-docs-attachment-drawer{display:none}.bp-docs-attachment-drawer h4{margin:.5em 0}.bp-docs-attachment-drawer>ul{list-style-type:none}.bp-docs-attachment-drawer>ul>li{margin-left:0}.hide-pane,.show-pane,.paperclip-vertical,.paperclip-jaunty{background:url("../images/bp-docs-ui-sprites.png") no-repeat;display:block;float:left;margin-left:10px;margin-top:5px}.hide-pane{background-position:0 0;width:16px;height:16px}.show-pane{background-position:0 -28px;width:16px;height:16px}.paperclip-vertical{background-position:0 -55px;width:13px;height:36px}.paperclip-jaunty{background-position:0 -105px;width:17px;height:36px}.toggle-switch,.entry-content p.toggle-switch{display:block;font-size:1em;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;border:1px solid #ccc;background-color:#f3f3f3;padding:3px 0;text-indent:16px;margin:16px 0 0}.toggle-switch.active-switch,.entry-content p.toggle-switch.active-switch{-moz-border-radius-bottomleft:10px;-webkit-border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-webkit-border-bottom-right-radius:10px;border-radius:3px 3px 0px 0px}.toggle-switch a,.entry-content p.toggle-switch a{color:#757575;text-decoration:none;display:block;width:100%;height:100%}.toggle-switch a:hover,.entry-content p.toggle-switch a:hover{font-weight:bold}.standard-form label.toggle-switch{margin:16px 0 0}.toggle-content{-moz-border-radius-bottomleft:2px;-webkit-border-bottom-left-radius:2px;-moz-border-radius-bottomright:2px;-webkit-border-bottom-right-radius:2px;border:1px solid #ccc;border-top:none;overflow:hidden}td.desc-column{width:300px;padding:0px 18px 12px}.docs-info-header .docs-filter{margin-bottom:0}#docs-filter-meta{font-size:.8em;color:#666;margin-bottom:0}a.docs-filter-title{margin:0 7px;text-decoration:none}a.docs-filter-title:visited{color:inherit}a.docs-filter-title.current{font-weight:bold}.docs-filter-section{border:1px solid #ccc;border-radius:2px;font-size:.8em;padding:6px 10px;margin-top:8px;transition:max-height 2s ease;overflow:hidden;position:relative}#docs-filter-section-tags a.tags-action-button,#docs-filter-section-tags a.tags-action-button:visited{display:inline;line-height:3em;text-decoration:none;background:#fff;background-opacity:.5;padding:5px 10px;border-radius:3px}body.js .docs-filter-section{display:none}body.js .docs-filter-section.docs-filter-section-open{display:block}p.currently-viewing{margin-bottom:5px;font-size:.8em;margin-top:8px}p#filter-by-tag{margin-bottom:0}.docs-info-header .toggle-switch{margin-top:8px}ul#tags-list{list-style-type:none;margin-bottom:0;padding:0;-moz-column-count:2;-moz-column-gap:10%;-webkit-column-count:2;-webkit-column-gap:10%;column-count:2;column-gap:10%}ul#tags-list li{margin-left:0}ul#tags-list li.hidden-tag{display:none}ul#tags-list li.tags-ellipses{font-style:italic}.groups-cell ul li img.avatar{float:none}.groups-cell ul li a{vertical-align:middle;font-size:.85em}.groups-cell ul{list-style-type:none;padding-left:0}.groups-cell ul li{margin-bottom:.5em}select#has-attachment{margin:8px 10px}div#bp-docs-pagination{position:relative;height:30px}div#bp-docs-pagination-count{position:absolute;left:0;top:5px;font-size:.9em;color:#999}div#bp-docs-paginate-links{position:absolute;right:0;top:5px}div#bp-docs-paginate-links a{padding:0 4px}div.doc-content{padding:20px;border:3px solid #f3f3f3}div.doc-content img{margin:10px}div.doc-content img.mceIcon{margin:0}#bp-docs-single-doc-header{overflow:hidden}body.trashed-doc #buddypress{border-left:4px solid red;padding-left:10px}div.doc-permissions{float:right;width:35%;background:#f0f0f0;border:1px solid #ddd;border-radius:3px;padding:4px}div.doc-permissions div:last-child{clear:both}#doc-permissions-summary,#doc-group-summary{font-size:1.0em;padding:3px 12px;border:1px solid}#doc-permissions-summary.doc-public{background:#b2ffb2;border-color:#00ff00}#doc-permissions-summary.doc-limited{background:#ffffe0;border-color:#e6db55}#doc-permissions-summary.doc-private{background:#ffebe8;border-color:#ff0000}a.doc-permissions-toggle{display:block;float:right;font-size:12px;cursor:hand}dl.doc-permissions-types dd,dl.doc-permissions-types dt{height:1.5em}dl.doc-permissions-types dt{width:50%;float:left;clear:left}#doc-group-summary{border-color:#f0f0f0}#doc-group-summary img.avatar{float:none}#doc-permissions-details ul{list-style-type:none;padding-left:0}#doc-permissions-details ul li{margin-bottom:.5em}span.bp-docs-level-icon{display:block;float:left;width:1.2em;height:1.2em;margin:3px 5px}.bp-docs-level-anyone span.bp-docs-level-icon{-moz-border-radius:.6em;-webkit-border-radius:.6em;border-radius:.6em;background:green}.bp-docs-level-friends span.bp-docs-level-icon,.bp-docs-level-loggedin span.bp-docs-level-icon,.bp-docs-level-group-members span.bp-docs-level-icon{width:0;height:0;border-left:.6em solid transparent;border-right:.6em solid transparent;border-bottom:1.2em solid yellow}.bp-docs-level-admins-mods span.bp-docs-level-icon,.bp-docs-level-no-one span.bp-docs-level-icon,.bp-docs-level-creator span.bp-docs-level-icon{background:red}div.doc-is-locked .toggle-switch{display:block;background:#bbb url(../images/padlock.gif) no-repeat;text-indent:25px;padding-top:3px}div.doc-is-locked .toggle-content{border:2px solid #f33;margin-top:5px;padding:7px 10px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}div.doc-meta p{margin-bottom:5px}a.nonexistent-doc{color:#f33}h2.doc-title{display:inline-block;width:50%}.comments-closed{padding:10px 20px;background:#f3f3f3;margin-top:10px}#respond{margin-top:20px}.doc-content ul{list-style:disc}.doc-content ol{list-style:decimal}.doc-content li{margin-left:20px}.doc-content blockquote{background:#f3f3f3;padding:5px;margin:10px 30px}div.hidden{display:none}table.group-docs-options td.label{width:200px}table.diff{width:100%}table.diff col.content{width:50%}table.diff tr{background-color:transparent}table.diff td,table.diff th{padding:.5em;font-family:Consolas, Monaco, Courier, monospace;border:none}table.diff .diff-deletedline del,table.diff .diff-addedline ins{text-decoration:none}table.diff .diff-deletedline{background-color:#fdd}table.diff .diff-deletedline del{background-color:#f99}table.diff .diff-addedline{background-color:#dfd}table.diff .diff-addedline ins{background-color:#9f9}#att-info{background-color:#E4F2FD}table#post-revisions{margin-top:20px}@media screen and (min-width: 4em){#docs-filter-section-tags a.tags-action-button,#docs-filter-section-tags a.tags-action-button:visited{display:block;margin-bottom:1em;padding:0;text-align:center}}@media screen and (min-width: 50em){.entry-content ul#tags-list{-moz-column-count:4;-moz-column-gap:5%;-webkit-column-count:4;-webkit-column-gap:5%;column-count:4;column-gap:5%}}@media screen and (min-width: 71em){.entry-content ul#tags-list{-moz-column-count:5;-moz-column-gap:5%;-webkit-column-count:5;-webkit-column-gap:5%;column-count:5;column-gap:5%}}
+.hide-if-no-js{display:none}.description{font-weight:normal;font-style:italic}.description code{font-style:normal;background:#eee;padding:2px 4px}#bp-create-doc-button{float:right;margin:5px 19px;font-weight:bold}body.bp-docs div.page ul{list-style-type:none}#bp-docs-all-docs{width:auto}.doc-tabs{overflow:hidden}.doc-tabs ul{padding-left:0}.doc-tabs li{float:left;margin:0 5px;list-style-type:none}.doc-tabs li:first-child{margin-left:0}.doc-tabs li a{background:#f1f1f1;text-decoration:none;display:block;padding:4px 10px;border-radius:5px 5px 0 0}.doc-tabs li.current a{background:#f3f3f3;color:#555;font-weight:bold}.doc-header h4{margin-bottom:15px !important}.docs-filter{display:block;width:400px;float:left;margin-bottom:15px}.doc-search{float:right;width:250px;text-align:right}.docs-filter-tags{width:100%}.docs-filter-tags ul li{display:block;width:120px;float:left;padding:6px}.doctable{border-collapse:separate;border-spacing:0}.doctable p{padding:0;margin:0}.doctable tr:hover .row-actions{visibility:visible}.doctable tr:nth-child(even){background-color:#f3f3f3}.doctable .bp-doc-trashed-doc .attachment-clip-cell{border-left:4px solid red}.bp-docs-trashed-doc-notice{color:red;font-size:.9em;font-style:italic}#buddypress #bp-docs-all-docs li{background:#eee}#buddypress div.doc-permissions{float:none;width:auto;margin-bottom:1em}#buddypress table.doctable td{vertical-align:top}#buddypress table.doctable tr:nth-child(even){background-color:#f3f3f3}#buddypress table.doctable tr th{background-color:#f3f3f3}.row-actions{visibility:hidden;padding:2px 0 0}body.mobile .row-actions{visibility:visible}.row-actions a{color:#999;font-size:11px}.row-actions a.delete{color:#f00}#docs-filter-submit{margin:10px 4px}.title-cell{width:30%}.author-cell,.created-date-cell,.edited-date-cell{text-align:center;width:100px}.current-orderby a{padding-left:20px}.asc a{background:url(../images/sort-col-asc.gif) no-repeat}.desc a{background:url(../images/sort-col-desc.gif) no-repeat}.doc-edit-link{margin:15px 0 20px 0}.doc-meta,#doc-meta,.docs #comments{padding-top:20px;border-top:1px solid #ddd}div.docs-info-header{background:#f3f3f3;padding:5px 10px;margin-bottom:10px}#associated_group_summary .item{padding-top:1em}#associated_group_summary .meta{font-size:11px;color:#888}#associated_group_summary img.avatar{margin-left:0}#doc-attachments-ul{margin-top:1em;list-style-type:none}#doc-attachments-ul li{margin:0px 5px 0px 0;padding:6px}#doc-attachments-ul li.even{background-color:#f3f3f3}#doc-attachments-ul .doc-attachment-delete{float:right;margin-top:.15em;margin-right:.3em}.bp-docs-attachment-clip{cursor:pointer;display:block;margin-top:10px}.doc-attachment-mime-icon{display:block;float:left;width:24px;height:24px;margin-right:5px;background:transparent url("../images/mime-type-sprites.png") no-repeat}.doc-attachment-mime-tar,.doc-attachment-mime-zip,.doc-attachment-mime-gz,.doc-attachment-mime-gzip,.doc-attachment-mime-rar,.doc-attachment-mime-7z{background-position:0 0px}.doc-attachment-mime-mp3,.doc-attachment-mime-m4a,.doc-attachment-mime-m4b,.doc-attachment-mime-ra,.doc-attachment-mime-ram,.doc-attachment-mime-wav,.doc-attachment-mime-ogg,.doc-attachment-mime-oga,.doc-attachment-mime-mid,.doc-attachment-mime-midi,.doc-attachment-mime-wma,.doc-attachment-mime-mka{background-position:0 -40px}.doc-attachment-mime-ics{background-position:0 -80px}.doc-attachment-mime-mdb,.doc-attachment-mime-odb{background-position:0 -120px}.doc-attachment-mime-odg{background-position:0 -160px}.doc-attachment-mime-jpg,.doc-attachment-mime-jpeg,.doc-attachment-mime-gif,.doc-attachment-mime-png,.doc-attachment-mime-bmp,.doc-attachment-mime-tif,.doc-attachment-mime-tiff,.doc-attachment-mime-ico{background-position:0 -200px}.doc-attachment-mime-pdf{background-position:0 -240px}.doc-attachment-mime-xla,.doc-attachment-mime-xls,.doc-attachment-mime-xlt,.doc-attachment-mime-xlw,.doc-attachment-mime-xlsx,.doc-attachment-mime-xlsm,.doc-attachment-mime-xlsb,.doc-attachment-mime-xlsb,.doc-attachment-mime-xlsx,.doc-attachment-mime-xlsm,.doc-attachment-mime-xlam,.doc-attachment-mime-ods,.doc-attachment-mime-odc{background-position:0 -280px}.doc-attachment-mime-txt,.doc-attachment-mime-asc,.doc-attachment-mime-c,.doc-attachment-mime-cc,.doc-attachment-mime-h,.doc-attachment-mime-csv,.doc-attachment-mime-tsv,.doc-attachment-mime-ics,.doc-attachment-mime-rtx,.doc-attachment-mime-css,.doc-attachment-mime-htm,.doc-attachment-mime-html{background-position:0 -320px}.doc-attachment-mime-asf,.doc-attachment-mime-asx,.doc-attachment-mime-wax,.doc-attachment-mime-wmv,.doc-attachment-mime-wmx,.doc-attachment-mime-avi,.doc-attachment-mime-divx,.doc-attachment-mime-flv,.doc-attachment-mime-mov,.doc-attachment-mime-qt,.doc-attachment-mime-mpeg,.doc-attachment-mime-mpg,.doc-attachment-mime-mpe,.doc-attachment-mime-mp4,.doc-attachment-mime-m4v,.doc-attachment-mime-ogv,.doc-attachment-mime-mkv{background-position:0 -360px}body.js .bp-docs-attachment-drawer{display:none}.bp-docs-attachment-drawer h4{margin:.5em 0}.bp-docs-attachment-drawer>ul{list-style-type:none}.bp-docs-attachment-drawer>ul>li{margin-left:0}.toggleable.toggle-closed .toggle-content{display:none}.hide-pane,.show-pane,.paperclip-vertical,.paperclip-jaunty{background:url("../images/bp-docs-ui-sprites.png") no-repeat;display:block;float:left;margin-left:10px;margin-top:5px}.hide-pane{background-position:0 0;width:16px;height:16px}.show-pane{background-position:0 -28px;width:16px;height:16px}.paperclip-vertical{background-position:0 -55px;width:13px;height:36px}.paperclip-jaunty{background-position:0 -105px;width:17px;height:36px}.toggle-switch,.entry-content p.toggle-switch{display:block;font-size:1em;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;border:1px solid #ccc;background-color:#f3f3f3;padding:3px 0;text-indent:16px;margin:16px 0 0}.toggle-switch.active-switch,.entry-content p.toggle-switch.active-switch{-moz-border-radius-bottomleft:10px;-webkit-border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-webkit-border-bottom-right-radius:10px;border-radius:3px 3px 0px 0px}.toggle-switch a,.entry-content p.toggle-switch a{color:#757575;text-decoration:none;display:block;width:100%;height:100%}.toggle-switch a:hover,.entry-content p.toggle-switch a:hover{font-weight:bold}.standard-form label.toggle-switch{margin:16px 0 0}.toggle-content{-moz-border-radius-bottomleft:2px;-webkit-border-bottom-left-radius:2px;-moz-border-radius-bottomright:2px;-webkit-border-bottom-right-radius:2px;border:1px solid #ccc;border-top:none;overflow:hidden}td.desc-column{width:50%;padding:0px 18px 12px}.docs-info-header .docs-filter{margin-bottom:0}#docs-filter-meta{font-size:.8em;color:#666;margin-bottom:0}a.docs-filter-title{margin:0 7px;text-decoration:none}a.docs-filter-title:visited{color:inherit}a.docs-filter-title.current{font-weight:bold}.docs-filter-section{border:1px solid #ccc;border-radius:2px;font-size:.8em;padding:6px 10px;margin-top:8px;transition:max-height 2s ease;overflow:hidden;position:relative}#docs-filter-section-tags a.tags-action-button,#docs-filter-section-tags a.tags-action-button:visited{display:inline;line-height:3em;text-decoration:none;background:#fff;background-opacity:.5;padding:5px 10px;border-radius:3px}body.js .docs-filter-section{display:none}body.js .docs-filter-section.docs-filter-section-open{display:block}p.currently-viewing{margin-bottom:5px;font-size:.8em;margin-top:8px}p#filter-by-tag{margin-bottom:0}.docs-info-header .toggle-switch{margin-top:8px}ul#tags-list{list-style-type:none;margin-bottom:0;padding:0;-moz-column-count:2;-moz-column-gap:10%;-webkit-column-count:2;-webkit-column-gap:10%;column-count:2;column-gap:10%}ul#tags-list li{margin-left:0}ul#tags-list li.hidden-tag{display:none}ul#tags-list li.tags-ellipses{font-style:italic}.groups-cell{padding-left:10px}.groups-cell ul{list-style-type:none;padding-left:0}.groups-cell ul li{margin-bottom:.5em;margin-left:0}.groups-cell ul li a{vertical-align:middle;font-size:.85em}.groups-cell ul li img.avatar{float:none}select#has-attachment{margin:8px 10px}div#bp-docs-pagination{position:relative;height:30px}div#bp-docs-pagination-count{position:absolute;left:0;top:5px;font-size:.9em;color:#999}div#bp-docs-paginate-links{position:absolute;right:0;top:5px}div#bp-docs-paginate-links a{padding:0 4px}div.doc-content{padding:20px;border:3px solid #f3f3f3}div.doc-content img{margin:10px}div.doc-content img.mceIcon{margin:0}#bp-docs-single-doc-header{overflow:hidden}body.trashed-doc #buddypress{border-left:4px solid red;padding-left:10px}div.doc-permissions{float:right;width:35%;background:#f0f0f0;border:1px solid #ddd;border-radius:3px;padding:4px}div.doc-permissions div:last-child{clear:both}#doc-permissions-summary,#doc-group-summary{font-size:1.0em;padding:3px 12px;border:1px solid}#doc-permissions-summary.doc-public{background:#b2ffb2;border-color:#00ff00}#doc-permissions-summary.doc-limited{background:#ffffe0;border-color:#e6db55}#doc-permissions-summary.doc-private{background:#ffebe8;border-color:#ff0000}a.doc-permissions-toggle{display:block;float:right;font-size:12px;cursor:hand}dl.doc-permissions-types dd,dl.doc-permissions-types dt{height:1.5em}dl.doc-permissions-types dt{width:50%;float:left;clear:left}#doc-group-summary{border-color:#f0f0f0}#doc-group-summary img.avatar{float:none}#doc-permissions-details ul{list-style-type:none;padding-left:0}#doc-permissions-details ul li{margin-bottom:.5em}span.bp-docs-level-icon{display:block;float:left;width:1.2em;height:1.2em;margin:3px 5px}.bp-docs-level-anyone span.bp-docs-level-icon{-moz-border-radius:.6em;-webkit-border-radius:.6em;border-radius:.6em;background:green}.bp-docs-level-friends span.bp-docs-level-icon,.bp-docs-level-loggedin span.bp-docs-level-icon,.bp-docs-level-group-members span.bp-docs-level-icon{width:0;height:0;border-left:.6em solid transparent;border-right:.6em solid transparent;border-bottom:1.2em solid yellow}.bp-docs-level-admins-mods span.bp-docs-level-icon,.bp-docs-level-no-one span.bp-docs-level-icon,.bp-docs-level-creator span.bp-docs-level-icon{background:red}div.doc-is-locked .toggle-content{border:2px solid #f33;margin-top:5px;padding:7px 10px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}div.doc-meta p{margin-bottom:5px}a.nonexistent-doc{color:#f33}h2.doc-title{display:inline-block;width:50%}.comments-closed{padding:10px 20px;background:#f3f3f3;margin-top:10px}#respond{margin-top:20px}.doc-content ul{list-style:disc}.doc-content ol{list-style:decimal}.doc-content li{margin-left:20px}.doc-content blockquote{background:#f3f3f3;padding:5px;margin:10px 30px}div.hidden{display:none}table.group-docs-options td.label{width:200px}table.diff{width:100%}table.diff col.content{width:50%}table.diff tr{background-color:transparent}table.diff td,table.diff th{padding:.5em;font-family:Consolas, Monaco, Courier, monospace;border:none}table.diff .diff-deletedline del,table.diff .diff-addedline ins{text-decoration:none}table.diff .diff-deletedline{background-color:#fdd}table.diff .diff-deletedline del{background-color:#f99}table.diff .diff-addedline{background-color:#dfd}table.diff .diff-addedline ins{background-color:#9f9}#att-info{background-color:#E4F2FD}table#post-revisions{margin-top:20px}@media screen and (min-width: 4em){#docs-filter-section-tags a.tags-action-button,#docs-filter-section-tags a.tags-action-button:visited{display:block;margin-bottom:1em;padding:0;text-align:center}}@media screen and (min-width: 50em){.entry-content ul#tags-list{-moz-column-count:4;-moz-column-gap:5%;-webkit-column-count:4;-webkit-column-gap:5%;column-count:4;column-gap:5%}}@media screen and (min-width: 71em){.entry-content ul#tags-list{-moz-column-count:5;-moz-column-gap:5%;-webkit-column-count:5;-webkit-column-gap:5%;column-count:5;column-gap:5%}}@media screen and (max-width: 820px){.created-date-cell{display:none}}@media screen and (max-width: 620px){.tags-cell{display:none}}@media screen and (max-width: 520px){.groups-cell{display:none}}@media screen and (max-width: 420px){.attachment-clip-cell,.edited-date-cell{display:none}}
diff --git a/includes/edit-lock.php b/includes/edit-lock.php
new file mode 100644
index 00000000..5b8ad81b
--- /dev/null
+++ b/includes/edit-lock.php
@@ -0,0 +1,324 @@
+user_nicename ) ) {
+ $bounce = add_query_arg( 'by', $by->user_nicename, $bounce );
+ }
+ $response['bp_docs_bounce'] = $bounce;
+ }
+
+ return $response;
+}
+add_filter( 'heartbeat_received', 'bp_docs_heartbeat_callback', 10, 2 );
+
+/**
+ * Prevent a user from visiting the Edit page if it's locked.
+ *
+ * @since 1.6.0
+ */
+function bp_docs_edit_lock_redirect() {
+ if ( ! bp_docs_is_doc_edit() ) {
+ return;
+ }
+
+ $doc_id = get_queried_object_id();
+
+ $lock = bp_docs_check_post_lock( $doc_id );
+
+ if ( ! empty( $lock ) && $lock != bp_loggedin_user_id() ) {
+ $bounce = bp_docs_get_doc_link( $doc_id );
+ wp_redirect( $bounce );
+ }
+}
+add_action( 'bp_actions', 'bp_docs_edit_lock_redirect' );
+
+/**
+ * Check to see if the post is currently being edited by another user.
+ *
+ * This is a verbatim copy of wp_check_post_lock(), which is only available
+ * in the admin
+ *
+ * @since 1.2.8
+ *
+ * @param int $post_id ID of the post to check for editing
+ * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
+ */
+function bp_docs_check_post_lock( $post_id ) {
+ if ( !$post = get_post( $post_id ) )
+ return false;
+
+ if ( !$lock = get_post_meta( $post->ID, '_bp_docs_last_pinged', true ) )
+ return false;
+
+ $lock = explode( ':', $lock );
+ $time = $lock[0];
+ $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
+
+ $heartbeat_interval = bp_docs_heartbeat_pulse();
+
+ // Bail out of the lock if four pings have been missed (one minute, by default)
+ $time_window = apply_filters( 'bp_docs_post_lock_interval', $heartbeat_interval * 4 );
+
+ if ( $time && $time > time() - $time_window && $user != get_current_user_id() ) {
+ return $user;
+ }
+
+ return false;
+}
+
+/**
+ * Get the lock status of a doc
+ *
+ * The function first tries to get the lock status out of $bp. If it has to look it up, it
+ * stores the data in $bp for future use.
+ *
+ * @package BuddyPress Docs
+ * @since 1.0-beta-2
+ *
+ * @param int $doc_id Optional. Defaults to the doc currently being viewed
+ * @return int Returns 0 if there is no lock, otherwise returns the user_id of the locker
+ */
+function bp_docs_is_doc_edit_locked( $doc_id = false ) {
+ global $bp, $post;
+
+ // Try to get the lock out of $bp first
+ if ( isset( $bp->bp_docs->current_doc_lock ) ) {
+ $is_edit_locked = $bp->bp_docs->current_doc_lock;
+ } else {
+ $is_edit_locked = 0;
+
+ if ( empty( $doc_id ) )
+ $doc_id = !empty( $post->ID ) ? $post->ID : false;
+
+ if ( $doc_id ) {
+ $is_edit_locked = bp_docs_check_post_lock( $doc_id );
+ }
+
+ // Put into the $bp global to avoid extra lookups
+ $bp->bp_docs->current_doc_lock = $is_edit_locked;
+ }
+
+ return apply_filters( 'bp_docs_is_doc_edit_locked', $is_edit_locked, $doc_id );
+}
+
+/**
+ * Echoes the output of bp_docs_get_current_doc_locker_name()
+ *
+ * @package BuddyPress Docs
+ * @since 1.0-beta-2
+ */
+function bp_docs_current_doc_locker_name() {
+ echo bp_docs_get_current_doc_locker_name();
+}
+ /**
+ * Get the name of the user locking the current document, if any
+ *
+ * @package BuddyPress Docs
+ * @since 1.0-beta-2
+ *
+ * @return string $locker_name The full name of the locking user
+ */
+ function bp_docs_get_current_doc_locker_name() {
+ $locker_name = '';
+
+ $locker_id = bp_docs_is_doc_edit_locked();
+
+ if ( $locker_id )
+ $locker_name = bp_core_get_user_displayname( $locker_id );
+
+ return apply_filters( 'bp_docs_get_current_doc_locker_name', $locker_name, $locker_id );
+ }
+
+/**
+ * Echoes the output of bp_docs_get_force_cancel_edit_lock_link()
+ *
+ * @package BuddyPress Docs
+ * @since 1.0-beta-2
+ */
+function bp_docs_force_cancel_edit_lock_link() {
+ echo bp_docs_get_force_cancel_edit_lock_link();
+}
+ /**
+ * Get the URL for canceling the edit lock on the current doc
+ *
+ * @package BuddyPress Docs
+ * @since 1.0-beta-2
+ *
+ * @return string $cancel_link href for the cancel edit lock link
+ */
+ function bp_docs_get_force_cancel_edit_lock_link() {
+ global $post;
+
+ $doc_id = !empty( $post->ID ) ? $post->ID : false;
+
+ if ( !$doc_id )
+ return false;
+
+ $doc_permalink = bp_docs_get_doc_link( $doc_id );
+
+ $cancel_link = wp_nonce_url( add_query_arg( 'bpd_action', 'cancel_edit_lock', $doc_permalink ), 'bp_docs_cancel_edit_lock' );
+
+ return apply_filters( 'bp_docs_get_force_cancel_edit_lock_link', $cancel_link, $doc_permalink );
+ }
+
+/**
+ * Echoes the output of bp_docs_get_cancel_edit_link()
+ *
+ * @package BuddyPress Docs
+ * @since 1.0-beta-2
+ */
+function bp_docs_cancel_edit_link() {
+ echo bp_docs_get_cancel_edit_link();
+}
+ /**
+ * Get the URL for canceling out of Edit mode on a doc
+ *
+ * This used to be a straight link back to non-edit mode, but something fancier is needed
+ * in order to detect the Cancel and to remove the edit lock.
+ *
+ * @package BuddyPress Docs
+ * @since 1.0-beta-2
+ *
+ * @return string $cancel_link href for the cancel edit link
+ */
+ function bp_docs_get_cancel_edit_link() {
+ global $bp, $post;
+
+ $doc_id = get_queried_object_id();
+
+ if ( !$doc_id )
+ return false;
+
+ $doc_permalink = bp_docs_get_doc_link( $doc_id );
+
+ $cancel_link = add_query_arg( 'bpd_action', 'cancel_edit', $doc_permalink );
+
+ return apply_filters( 'bp_docs_get_cancel_edit_link', $cancel_link, $doc_permalink );
+ }
+
+/**
+ * AJAX handler for remove_edit_lock option
+ *
+ * This function is called when a user is editing a Doc and clicks a link to leave the page
+ *
+ * @package BuddyPress Docs
+ * @since 1.1
+ */
+function bp_docs_remove_edit_lock() {
+ $doc_id = isset( $_POST['doc_id'] ) ? $_POST['doc_id'] : false;
+
+ if ( !$doc_id )
+ return false;
+
+ delete_post_meta( $doc_id, '_bp_docs_last_pinged' );
+}
+add_action( 'wp_ajax_remove_edit_lock', 'bp_docs_remove_edit_lock' );
+
+/**
+ * AJAX handler for setting edit lock.
+ *
+ * Called when a user enters an Edit page.
+ *
+ * @since 1.6.0
+ */
+function bp_docs_add_edit_lock_cb() {
+ $doc_id = isset( $_POST['doc_id'] ) ? (int) $_POST['doc_id'] : false;
+
+ if ( ! $doc_id ) {
+ return;
+ }
+
+ $doc = get_post( $doc_id );
+
+ if ( ! $doc || is_wp_error( $doc ) ) {
+ return;
+ }
+
+ if ( bp_docs_get_post_type_name() !== $doc->post_type ) {
+ return;
+ }
+
+ if ( ! is_user_logged_in() ) {
+ return;
+ }
+
+ // Is this post already locked?
+ $lock = bp_docs_check_post_lock( $doc_id );
+ if ( ! empty( $lock ) && $lock != bp_loggedin_user_id() ) {
+ die();
+ }
+
+ $now = time();
+ $user_id = bp_loggedin_user_id();
+ $lock = "$now:$user_id";
+
+ update_post_meta( $doc_id, '_bp_docs_last_pinged', $lock );
+
+ die( json_encode( '1' ) );
+}
+add_action( 'wp_ajax_add_edit_lock', 'bp_docs_add_edit_lock_cb' );
+
diff --git a/includes/functions.php b/includes/functions.php
index 7b9c7198..30b503b3 100644
--- a/includes/functions.php
+++ b/includes/functions.php
@@ -717,35 +717,6 @@ function bp_docs_hide_sitewide_for_doc( $doc_id ) {
return apply_filters( 'bp_docs_hide_sitewide_for_doc', $hide_sitewide, $doc_id );
}
-/**
- * Check to see if the post is currently being edited by another user.
- *
- * This is a verbatim copy of wp_check_post_lock(), which is only available
- * in the admin
- *
- * @since 1.2.8
- *
- * @param int $post_id ID of the post to check for editing
- * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
- */
-function bp_docs_check_post_lock( $post_id ) {
- if ( !$post = get_post( $post_id ) )
- return false;
-
- if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
- return false;
-
- $lock = explode( ':', $lock );
- $time = $lock[0];
- $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
-
- $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
-
- if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
- return $user;
- return false;
-}
-
function bp_docs_get_doc_ids_accessible_to_current_user() {
global $wpdb;
diff --git a/includes/integration-groups.php b/includes/integration-groups.php
index afce5810..c6bb5fd6 100644
--- a/includes/integration-groups.php
+++ b/includes/integration-groups.php
@@ -43,7 +43,6 @@ function __construct() {
// Taxonomy helpers
add_filter( 'bp_docs_taxonomy_get_item_terms', array( $this, 'get_group_terms' ) );
- add_action( 'bp_docs_taxonomy_save_item_terms', array( $this, 'save_group_terms' ) );
// Filter the core user_can_edit function for group-specific functionality
add_filter( 'bp_docs_user_can', array( $this, 'user_can' ), 10, 4 );
@@ -68,8 +67,9 @@ function __construct() {
add_filter( 'bp_docs_loop_additional_td', array( $this, 'groups_td' ), 5 );
// Update group last active metadata when a doc is created, updated, or saved
- add_filter( 'bp_docs_doc_saved', array( $this, 'update_group_last_active' ) );
- add_filter( 'bp_docs_doc_deleted', array( $this, 'update_group_last_active' ) );
+ add_filter( 'bp_docs_after_save', array( $this, 'update_group_last_active' ) );
+ add_filter( 'bp_docs_before_doc_delete', array( $this, 'update_group_last_active' ) );
+ add_filter( 'wp_insert_comment', array( $this, 'update_group_last_active_comment' ), 10, 2 );
// Sneak into the nav before it's rendered to insert the group Doc count. Hooking
// to bp_actions because of the craptastic nature of the BP_Group_Extension loader
@@ -176,19 +176,40 @@ function get_current_view( $view, $item_type ) {
*/
function pre_query_args( $query_args, $bp_docs_query ) {
if ( ! empty( $bp_docs_query->query_args['group_id'] ) ) {
- $terms = array();
- foreach ( (array) $bp_docs_query->query_args['group_id'] as $gid ) {
- $terms[] = bp_docs_get_term_slug_from_group_id( $gid );
- }
- $query_args['tax_query'][] = array(
- 'taxonomy' => bp_docs_get_associated_item_tax_name(),
- 'field' => 'slug',
- 'terms' => $terms,
- );
+ $query_args['tax_query'][] = self::tax_query_arg_for_groups( $bp_docs_query->query_args['group_id'] );
}
return $query_args;
}
+ /**
+ * Generate the tax_query param for limiting to groups.
+ *
+ * @since 1.6.0
+ *
+ * @param int|array $group_ids IDs of groups.
+ * @return array
+ */
+ public static function tax_query_arg_for_groups( $group_ids ) {
+ $group_ids = wp_parse_id_list( $group_ids );
+
+ $terms = array();
+ foreach ( $group_ids as $gid ) {
+ $terms[] = bp_docs_get_term_slug_from_group_id( $gid );
+ }
+
+ if ( empty( $terms ) ) {
+ $terms = array( 0 );
+ }
+
+ $arg = array(
+ 'taxonomy' => bp_docs_get_associated_item_tax_name(),
+ 'field' => 'slug',
+ 'terms' => $terms,
+ );
+
+ return $arg;
+ }
+
/**
* Gets the list of terms used by a group's docs
*
@@ -212,11 +233,39 @@ function get_group_terms( $terms = array() ) {
}
}
- if ( $group_id ) {
- $terms = groups_get_groupmeta( $group_id, 'bp_docs_terms' );
+ if ( ! $group_id ) {
+ return $terms;
+ }
- if ( empty( $terms ) )
- $terms = array();
+ $query_args = array(
+ 'post_type' => bp_docs_get_post_type_name(),
+ 'update_meta_cache' => false,
+ 'update_term_cache' => true,
+ 'showposts' => '-1',
+ 'posts_per_page' => '-1',
+ 'tax_query' => array(
+ self::tax_query_arg_for_groups( $group_id ),
+ ),
+ );
+
+ $group_doc_query = new WP_Query( $query_args );
+
+ $terms = array();
+ foreach ( $group_doc_query->posts as $p ) {
+ $p_terms = wp_get_post_terms( $p->ID, buddypress()->bp_docs->docs_tag_tax_name );
+ foreach ( $p_terms as $p_term ) {
+ if ( ! isset( $terms[ $p_term->name ] ) ) {
+ $terms[ $p_term->name ] = array();
+ }
+
+ if ( ! in_array( $p->ID, $terms[ $p_term->name ] ) ) {
+ $terms[ $p_term->name ][] = $p->ID;
+ }
+ }
+ }
+
+ if ( empty( $terms ) ) {
+ $terms = array();
}
return apply_filters( 'bp_docs_taxonomy_get_group_terms', $terms );
@@ -225,24 +274,14 @@ function get_group_terms( $terms = array() ) {
/**
* Saves the list of terms used by a group's docs
*
+ * No longer used.
+ *
* @package BuddyPress Docs
* @since 1.0-beta
*
* @param array $terms The terms to be saved to groupmeta
*/
- function save_group_terms( $terms ) {
- $doc = get_post();
-
- if ( ! isset( $doc->post_type ) || $doc->post_type !== bp_docs_get_post_type_name() ) {
- return $terms;
- }
-
- $group_id = bp_docs_get_associated_group_id( $doc->ID, $doc );
-
- if ( $group_id ) {
- groups_update_groupmeta( $group_id, 'bp_docs_terms', $terms );
- }
- }
+ function save_group_terms( $terms ) {}
/**
* Determine whether a user can edit the group doc in question
@@ -720,9 +759,25 @@ function groups_td() {
* @package BuddyPress Docs
* @since 1.1.8
*/
- function update_group_last_active() {
- if ( bp_is_group() ) {
- groups_update_groupmeta( bp_get_current_group_id(), 'last_activity', bp_core_current_time() );
+ function update_group_last_active( $doc_id ) {
+ $group = intval( bp_docs_get_associated_group_id( $doc_id ) );
+
+ if ( $group ) {
+ groups_update_groupmeta( $group, 'last_activity', bp_core_current_time() );
+ }
+ }
+
+ /**
+ * Update group last activy date when a comment is posted to a group Doc.
+ *
+ * @since 1.6.0
+ *
+ * @param int $comment_id
+ * @param object $comment
+ */
+ public function update_group_last_active_comment( $comment_id, $comment ) {
+ if ( 1 == $comment->comment_approved ) {
+ $this->update_group_last_active( $comment->comment_post_ID );
}
}
diff --git a/includes/integration-users.php b/includes/integration-users.php
index b3a03790..2ee59721 100644
--- a/includes/integration-users.php
+++ b/includes/integration-users.php
@@ -24,7 +24,6 @@ function __construct() {
// Taxonomy helpers
add_filter( 'bp_docs_taxonomy_get_item_terms', array( &$this, 'get_user_terms' ) );
- add_action( 'bp_docs_taxonomy_save_item_terms', array( &$this, 'save_user_terms' ) );
}
/**
@@ -124,7 +123,7 @@ function setup_single_doc_subnav() {
'parent_slug' => bp_docs_get_docs_slug(),
'screen_function' => array( $bp->bp_docs, 'template_loader' ),
'position' => 30,
- 'user_has_access' => true // todo
+ 'user_has_access' => true, // todo
) );
}
}
@@ -152,12 +151,49 @@ function update_doc_count() {
* @return array $terms
*/
function get_user_terms( $terms = array() ) {
+ global $wpdb;
- if ( bp_is_user() ) {
- $terms = get_user_meta( bp_displayed_user_id(), 'bp_docs_terms', true );
+ if ( ! bp_is_user() ) {
+ return $terms;
+ }
+
+ $query_args = array(
+ 'post_type' => bp_docs_get_post_type_name(),
+ 'update_meta_cache' => false,
+ 'update_term_cache' => true,
+ 'showposts' => '-1',
+ 'posts_per_page' => '-1',
+ );
+
+ if ( bp_docs_is_edited_by() ) {
+ $query_args['post__in'] = BP_Docs_Query::get_edited_by_post_ids_for_user( bp_displayed_user_id() );
+ $query_args['post_status'] = array( 'publish' );
+ } else if ( bp_docs_is_started_by() ) {
+ $query_args['author'] = bp_displayed_user_id();
+ $query_args['post_status'] = array( 'publish', 'trash' );
+ } else {
+ // Just in case
+ $query_args['post__in'] = array( 0 );
+ }
- if ( empty( $terms ) )
- $terms = array();
+ $user_doc_query = new WP_Query( $query_args );
+
+ $terms = array();
+ foreach ( $user_doc_query->posts as $p ) {
+ $p_terms = wp_get_post_terms( $p->ID, buddypress()->bp_docs->docs_tag_tax_name );
+ foreach ( $p_terms as $p_term ) {
+ if ( ! isset( $terms[ $p_term->name ] ) ) {
+ $terms[ $p_term->name ] = array();
+ }
+
+ if ( ! in_array( $p->ID, $terms[ $p_term->name ] ) ) {
+ $terms[ $p_term->name ][] = $p->ID;
+ }
+ }
+ }
+
+ if ( empty( $terms ) ) {
+ $terms = array();
}
return apply_filters( 'bp_docs_taxonomy_get_user_terms', $terms );
@@ -166,19 +202,15 @@ function get_user_terms( $terms = array() ) {
/**
* Saves the list of terms used by a user's docs
*
+ * No longer used.
+ *
* @package BuddyPress_Docs
* @subpackage Users
* @since 1.2
*
* @param array $terms The terms to be saved to usermeta
*/
- function save_user_terms( $terms ) {
-
- // bp_is_user isn't true at doc edit. (So neither is bp_displayed_user)
- if ( bp_docs_is_docs_component() ) {
- update_user_meta( bp_loggedin_user_id(), 'bp_docs_terms', $terms );
- }
- }
+ function save_user_terms( $terms ) {}
}
diff --git a/includes/js/bp-docs.js b/includes/js/bp-docs.js
index 61ee7f09..35ec584c 100644
--- a/includes/js/bp-docs.js
+++ b/includes/js/bp-docs.js
@@ -1,7 +1,26 @@
jQuery(document).ready(function($){
+ var doc_id = $( '#existing-doc-id' ).val();
+
/* Unhide JS content */
$('.hide-if-no-js').show();
+ // If this is an edit page, set the lock
+ if ( $( 'body' ).hasClass( 'bp-docs-edit' ) ) {
+ var lock_data = {
+ action: 'add_edit_lock',
+ doc_id: doc_id
+ };
+
+ $.ajax({
+ url: ajaxurl,
+ type: 'POST',
+ data: lock_data,
+ success: function(response){
+ return true;
+ }
+ });
+ }
+
$('.bp-docs-attachment-clip').on('click', function(e) {
var att_doc_id = $(e.target).closest('.bp-docs-attachment-clip').attr('id').split('-').pop();
var att_doc_drawer = $('#bp-docs-attachment-drawer-'+att_doc_id);
@@ -27,10 +46,10 @@ jQuery(document).ready(function($){
/* When a toggle is clicked, show the toggle-content */
$('.toggle-link').click(function(){
// Traverse for some items
- var toggleable = $(this).parents('.toggleable');
- var tc = $(toggleable).find('.toggle-content');
- var ts = $(toggleable).find('.toggle-switch');
- var pom = $(this).find('.plus-or-minus');
+ var $toggleable = $(this).parents('.toggleable');
+ var tc = $toggleable.find('.toggle-content');
+ var ts = $toggleable.find('.toggle-switch');
+ var $pom = $(this).find('.plus-or-minus');
// Toggle the active-content class
if($(tc).hasClass('active-content')){
@@ -47,19 +66,19 @@ jQuery(document).ready(function($){
}
// Slide the tags up or down
- $(tc).slideToggle(400, function(){
- var rclass, aclass;
- if ( $(pom).hasClass('show-pane') ) {
- rclass = 'show-pane';
- aclass = 'hide-pane';
- } else {
- rclass = 'hide-pane';
- aclass = 'show-pane';
- }
+ var rclass, aclass;
+ if ( $pom.hasClass('show-pane') ) {
+ rclass = 'show-pane';
+ aclass = 'hide-pane';
+ $toggleable.removeClass( 'toggle-open' ).addClass( 'toggle-closed' );
+ } else {
+ rclass = 'hide-pane';
+ aclass = 'show-pane';
+ $toggleable.removeClass( 'toggle-closed' ).addClass( 'toggle-open' );
+ }
- $(pom).removeClass(rclass);
- $(pom).addClass(aclass);
- });
+ $pom.removeClass(rclass);
+ $pom.addClass(aclass);
return false;
});
@@ -147,6 +166,30 @@ jQuery(document).ready(function($){
return false;
});
+ // Set the interval and the namespace event
+ if ( typeof wp != 'undefined' && typeof wp.heartbeat != 'undefined' && typeof bp_docs.pulse != 'undefined' ) {
+
+ wp.heartbeat.interval( Number( bp_docs.pulse ) );
+
+ jq.fn.extend({
+ 'heartbeat-send': function() {
+ return this.bind( 'heartbeat-send.buddypress-docs' );
+ },
+ });
+ }
+
+ $( document ).on( 'heartbeat-send.buddypress-docs', function( e, data ) {
+ data['doc_id'] = $('#existing-doc-id').val();
+ });
+
+ // Increment newest_activities and activity_last_id if data has been returned
+ $( document ).on( 'heartbeat-tick', function( e, data ) {
+ if ( ! data['bp_docs_bounce'] ) {
+ return;
+ }
+
+ window.location = data['bp_docs_bounce'];
+ });
/**
* Collapse the Tags filter section
*/
diff --git a/includes/query-builder.php b/includes/query-builder.php
index f71398a3..7766f991 100644
--- a/includes/query-builder.php
+++ b/includes/query-builder.php
@@ -255,8 +255,8 @@ function get_wp_query() {
/**
*
*/
- function get_edited_by_post_ids() {
- $editor_ids = wp_parse_id_list( $this->query_args['edited_by_id'] );
+ public static function get_edited_by_post_ids_for_user( $editor_ids ) {
+ $editor_ids = wp_parse_id_list( $editor_ids );
$post_ids = array();
foreach ( $editor_ids as $editor_id ) {
@@ -291,6 +291,13 @@ function get_edited_by_post_ids() {
return array_unique( $post_ids );
}
+ /**
+ *
+ */
+ function get_edited_by_post_ids() {
+ return self::get_edited_by_post_ids_for_user( $this->query_args['edited_by_id'] );
+ }
+
/**
*/
function get_access_tax_query() {
@@ -570,6 +577,8 @@ function save( $args = false ) {
// the WP admin handles automatically)
do_action( 'bp_docs_doc_saved', $this );
+ do_action( 'bp_docs_after_save', $this->doc_id );
+
$message_type = $result['redirect'] == 'single' ? 'success' : 'error';
$redirect_url = trailingslashit( bp_get_root_domain() . '/' . bp_docs_get_docs_slug() );
diff --git a/includes/scss/screen.scss b/includes/scss/screen.scss
index f7f6917a..0361d928 100644
--- a/includes/scss/screen.scss
+++ b/includes/scss/screen.scss
@@ -68,7 +68,7 @@ body.bp-docs div.page ul {
padding: 4px 10px;
border-radius: 5px 5px 0 0;
}
-
+
&.current a {
background: $grey;
color: #555;
@@ -108,12 +108,12 @@ body.bp-docs div.page ul {
.doctable {
border-collapse: separate;
border-spacing: 0;
-
+
p {
padding: 0;
margin: 0;
}
-
+
tr:hover .row-actions {
visibility: visible;
}
@@ -195,6 +195,10 @@ body.mobile .row-actions {
width: 100px;
}
+.group-cell {
+
+}
+
.current-orderby a {
padding-left: 20px;
}
@@ -402,6 +406,11 @@ body.js .bp-docs-attachment-drawer {
}
/* TOGGLES */
+
+.toggleable.toggle-closed .toggle-content {
+ display: none;
+}
+
.hide-pane, .show-pane, .paperclip-vertical, .paperclip-jaunty{
background: url('../images/bp-docs-ui-sprites.png') no-repeat;
display: block;
@@ -454,9 +463,9 @@ body.js .bp-docs-attachment-drawer {
-webkit-border-bottom-right-radius: 10px;
border-radius: 3px 3px 0px 0px;
}
-
+
a {
- color: $grey_text;
+ color: $grey_text;
text-decoration: none;
display: block;
width: 100%;
@@ -483,7 +492,7 @@ body.js .bp-docs-attachment-drawer {
}
td.desc-column {
- width: 300px;
+ width: 50%;
padding: 0px 18px 12px;
}
@@ -516,7 +525,7 @@ a.docs-filter-title.current {
font-size: .8em;
padding: 6px 10px;
margin-top: 8px;
- transition: max-height 2s ease;
+ transition: max-height 2s ease;
overflow: hidden;
position: relative;
}
@@ -572,21 +581,27 @@ ul#tags-list {
}
}
-.groups-cell ul li img.avatar {
- float: none;
-}
+.groups-cell {
+ padding-left: 10px;
-.groups-cell ul li a {
- vertical-align: middle;
- font-size: .85em;
-}
+ ul {
+ list-style-type: none;
+ padding-left: 0;
-.groups-cell ul {
- list-style-type: none;
- padding-left: 0;
-}
-.groups-cell ul li {
- margin-bottom: .5em;
+ li {
+ margin-bottom: .5em;
+ margin-left: 0;
+
+ a {
+ vertical-align: middle;
+ font-size: .85em;
+ }
+
+ img.avatar {
+ float: none;
+ }
+ }
+ }
}
select#has-attachment {
@@ -726,14 +741,6 @@ span.bp-docs-level-icon {
background: red;
}
-
-div.doc-is-locked .toggle-switch {
- display: block;
- background: #bbb url(../images/padlock.gif) no-repeat;
- text-indent: 25px;
- padding-top: 3px;
-}
-
div.doc-is-locked .toggle-content {
border: 2px solid #f33;
margin-top: 5px;
@@ -837,7 +844,7 @@ table#post-revisions {
}
//Media query for most screens, unseen by IE 7 or 8
-@media screen and (min-width:4em) {
+@media screen and (min-width:4em) {
#docs-filter-section-tags a.tags-action-button,
#docs-filter-section-tags a.tags-action-button:visited {
display: block; // Let the button span the entire box
@@ -847,14 +854,38 @@ table#post-revisions {
}
}
//Media query for larger screens, like tablet
-@media screen and (min-width:50em) {
+@media screen and (min-width:50em) {
.entry-content ul#tags-list {
@include multi-columns(4, 5%);
}
}
//Media query for larger screens, like desktop
-@media screen and (min-width:71em) {
+@media screen and (min-width:71em) {
.entry-content ul#tags-list {
@include multi-columns(5, 5%);
}
}
+
+@media screen and (max-width:820px) {
+ .created-date-cell {
+ display: none;
+ }
+}
+
+@media screen and (max-width:620px) {
+ .tags-cell {
+ display: none;
+ }
+}
+
+@media screen and (max-width:520px) {
+ .groups-cell {
+ display: none;
+ }
+}
+
+@media screen and (max-width:420px) {
+ .attachment-clip-cell, .edited-date-cell {
+ display: none;
+ }
+}
diff --git a/includes/templatetags-edit.php b/includes/templatetags-edit.php
index 52897fed..58c01be0 100644
--- a/includes/templatetags-edit.php
+++ b/includes/templatetags-edit.php
@@ -263,7 +263,13 @@ function bp_docs_add_external_tinymce_plugins( $plugins ) {
* @return array $buttons Button list, with BP Docs buttons added
*/
function bp_docs_add_external_tinymce_buttons_row1( $buttons ) {
- $justify_right_key = array_search( 'justifyright', $buttons );
+ // TinyMCE 4.0+
+ $justify_right_key = array_search( 'alignright', $buttons );
+
+ // 3.0
+ if ( false === $justify_right_key ) {
+ $justify_right_key = array_search( 'justifyright', $buttons );
+ }
if ( $justify_right_key !== 0 ) {
// Shift the buttons one to the right and remove from original array
@@ -282,6 +288,15 @@ function bp_docs_add_external_tinymce_buttons_row1( $buttons ) {
$ks = array_pop( $buttons );
$buttons = array_merge( $buttons, array( 'print' ), array( $ks ) );
+ // Fullscreen is kinda busted here, so remove it
+ $fs = array_search( 'fullscreen', $buttons );
+ if ( false !== $fs ) {
+ unset( $buttons[ $fs ] );
+ }
+
+ // Reset indexes
+ $buttons = array_values( $buttons );
+
return $buttons;
}
add_filter( 'mce_buttons', 'bp_docs_add_external_tinymce_buttons_row1' );
diff --git a/includes/templatetags.php b/includes/templatetags.php
index 6dd91477..80aee877 100644
--- a/includes/templatetags.php
+++ b/includes/templatetags.php
@@ -204,7 +204,7 @@ function bp_docs_get_info_header() {
$message = implode( "\n", $message );
// We are viewing a subset of docs, so we'll add a link to clear filters
- $message .= ' - ' . sprintf( __( '
View All Docs', 'bp-docs' ), remove_query_arg( 'bpd_tag' ) );
+ $message .= ' - ' . sprintf( __( '
View All Docs', 'bp-docs' ), remove_query_arg( array( 'bpd_tag', 's', 'search_submit' ) ) );
}
?>
@@ -957,140 +957,6 @@ function bp_docs_current_group_is_public() {
return false;
}
-/**
- * Get the lock status of a doc
- *
- * The function first tries to get the lock status out of $bp. If it has to look it up, it
- * stores the data in $bp for future use.
- *
- * @package BuddyPress Docs
- * @since 1.0-beta-2
- *
- * @param int $doc_id Optional. Defaults to the doc currently being viewed
- * @return int Returns 0 if there is no lock, otherwise returns the user_id of the locker
- */
-function bp_docs_is_doc_edit_locked( $doc_id = false ) {
- global $bp, $post;
-
- // Try to get the lock out of $bp first
- if ( isset( $bp->bp_docs->current_doc_lock ) ) {
- $is_edit_locked = $bp->bp_docs->current_doc_lock;
- } else {
- $is_edit_locked = 0;
-
- if ( empty( $doc_id ) )
- $doc_id = !empty( $post->ID ) ? $post->ID : false;
-
- if ( $doc_id ) {
- // Because we're not using WP autosave at the moment, ensure that
- // the lock interval always returns as in process
- add_filter( 'wp_check_post_lock_window', create_function( false, 'return time();' ) );
-
- $is_edit_locked = bp_docs_check_post_lock( $doc_id );
- }
-
- // Put into the $bp global to avoid extra lookups
- $bp->bp_docs->current_doc_lock = $is_edit_locked;
- }
-
- return apply_filters( 'bp_docs_is_doc_edit_locked', $is_edit_locked, $doc_id );
-}
-
-/**
- * Echoes the output of bp_docs_get_current_doc_locker_name()
- *
- * @package BuddyPress Docs
- * @since 1.0-beta-2
- */
-function bp_docs_current_doc_locker_name() {
- echo bp_docs_get_current_doc_locker_name();
-}
- /**
- * Get the name of the user locking the current document, if any
- *
- * @package BuddyPress Docs
- * @since 1.0-beta-2
- *
- * @return string $locker_name The full name of the locking user
- */
- function bp_docs_get_current_doc_locker_name() {
- $locker_name = '';
-
- $locker_id = bp_docs_is_doc_edit_locked();
-
- if ( $locker_id )
- $locker_name = bp_core_get_user_displayname( $locker_id );
-
- return apply_filters( 'bp_docs_get_current_doc_locker_name', $locker_name, $locker_id );
- }
-
-/**
- * Echoes the output of bp_docs_get_force_cancel_edit_lock_link()
- *
- * @package BuddyPress Docs
- * @since 1.0-beta-2
- */
-function bp_docs_force_cancel_edit_lock_link() {
- echo bp_docs_get_force_cancel_edit_lock_link();
-}
- /**
- * Get the URL for canceling the edit lock on the current doc
- *
- * @package BuddyPress Docs
- * @since 1.0-beta-2
- *
- * @return string $cancel_link href for the cancel edit lock link
- */
- function bp_docs_get_force_cancel_edit_lock_link() {
- global $post;
-
- $doc_id = !empty( $post->ID ) ? $post->ID : false;
-
- if ( !$doc_id )
- return false;
-
- $doc_permalink = bp_docs_get_doc_link( $doc_id );
-
- $cancel_link = wp_nonce_url( add_query_arg( 'bpd_action', 'cancel_edit_lock', $doc_permalink ), 'bp_docs_cancel_edit_lock' );
-
- return apply_filters( 'bp_docs_get_force_cancel_edit_lock_link', $cancel_link, $doc_permalink );
- }
-
-/**
- * Echoes the output of bp_docs_get_cancel_edit_link()
- *
- * @package BuddyPress Docs
- * @since 1.0-beta-2
- */
-function bp_docs_cancel_edit_link() {
- echo bp_docs_get_cancel_edit_link();
-}
- /**
- * Get the URL for canceling out of Edit mode on a doc
- *
- * This used to be a straight link back to non-edit mode, but something fancier is needed
- * in order to detect the Cancel and to remove the edit lock.
- *
- * @package BuddyPress Docs
- * @since 1.0-beta-2
- *
- * @return string $cancel_link href for the cancel edit link
- */
- function bp_docs_get_cancel_edit_link() {
- global $bp, $post;
-
- $doc_id = !empty( $bp->bp_docs->current_post->ID ) ? $bp->bp_docs->current_post->ID : false;
-
- if ( !$doc_id )
- return false;
-
- $doc_permalink = bp_docs_get_doc_link( $doc_id );
-
- $cancel_link = add_query_arg( 'bpd_action', 'cancel_edit', $doc_permalink );
-
- return apply_filters( 'bp_docs_get_cancel_edit_link', $cancel_link, $doc_permalink );
- }
-
/**
* Echoes the output of bp_docs_get_delete_doc_link()
*
@@ -1922,20 +1788,58 @@ function bp_docs_get_doc_attachments( $doc_id = null ) {
return apply_filters( 'bp_docs_get_doc_attachments', $atts, $doc_id );
}
+/**
+ * Get the URL for an attachment download.
+ *
+ * Is sensitive to whether Docs can be directly downloaded.
+ *
+ * @param int $attachment_id
+ */
+function bp_docs_attachment_url( $attachment_id ) {
+ echo bp_docs_get_attachment_url( $attachment_id );
+}
+ /**
+ * Get the URL for an attachment download.
+ *
+ * Is sensitive to whether Docs can be directly downloaded.
+ *
+ * @param int $attachment_id
+ */
+ function bp_docs_get_attachment_url( $attachment_id ) {
+ $attachment = get_post( $attachment_id );
+
+ if ( bp_docs_attachment_protection() ) {
+ $attachment = get_post( $attachment_id );
+ $att_base = basename( get_attached_file( $attachment_id ) );
+ $doc_url = bp_docs_get_doc_link( $attachment->post_parent );
+ $att_url = add_query_arg( 'bp-attachment', $att_base, $doc_url );
+ } else {
+ $att_url = wp_get_attachment_url( $attachment_id );
+ }
+
+ // Backward compatibility: fix IIS URLs that were broken by a
+ // previous implementation
+ $att_url = preg_replace( '|bp\-attachments([0-9])|', 'bp-attachments/$1', $att_url );
+
+ return apply_filters( 'bp_docs_attachment_url_base', $att_url, $attachment );
+ }
+
+
// @todo make
optional?
function bp_docs_attachment_item_markup( $attachment_id, $format = 'full' ) {
$markup = '';
+ $att_url = bp_docs_get_attachment_url( $attachment_id );
+
$attachment = get_post( $attachment_id );
- $attachment_url = apply_filters( 'bp_docs_attachment_url_base', wp_get_attachment_url( $attachment->ID ), $attachment );
+ $att_base = basename( get_attached_file( $attachment_id ) );
+ $doc_url = bp_docs_get_doc_link( $attachment->post_parent );
- $attachment_ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $attachment_url );
- $attachment_filename = basename( $attachment_url );
+ $attachment_ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $att_url );
if ( 'full' === $format ) {
$attachment_delete_html = '';
if ( bp_docs_current_user_can( 'edit' ) && ( bp_docs_is_doc_edit() || bp_docs_is_doc_create() ) ) {
- $doc_url = bp_docs_get_doc_link( $attachment->post_parent );
$attachment_delete_url = wp_nonce_url( $doc_url, 'bp_docs_delete_attachment_' . $attachment_id );
$attachment_delete_url = add_query_arg( array(
'delete_attachment' => $attachment_id,
@@ -1951,18 +1855,19 @@ function bp_docs_attachment_item_markup( $attachment_id, $format = 'full' ) {
'%s%s',
$attachment_id,
$attachment_ext,
- $attachment_url,
- esc_attr( $attachment_filename ),
- esc_html( $attachment_filename ),
+ $att_url,
+ esc_attr( $att_base ),
+ esc_html( $att_base ),
$attachment_delete_html
);
} else {
$markup = sprintf(
- '
%s',
+ '
%s',
$attachment_id,
- $attachment_url,
- esc_attr( $attachment_filename ),
- esc_html( $attachment_filename )
+ $attachment_ext,
+ $att_url,
+ esc_attr( $att_base ),
+ esc_html( $att_base )
);
}
@@ -1997,9 +1902,9 @@ function bp_docs_attachment_icon() {
return;
}
- $pc = plugins_url( BP_DOCS_PLUGIN_SLUG . '/includes/images/paperclip.png' );
+ // $pc = plugins_url( BP_DOCS_PLUGIN_SLUG . '/includes/images/paperclip.png' );
- $html = '
';
+ $html = '
';
echo $html;
}
diff --git a/loader.php b/loader.php
index 420a8d0b..e648089b 100644
--- a/loader.php
+++ b/loader.php
@@ -3,7 +3,7 @@
Plugin Name: BuddyPress Docs
Plugin URI: http://github.com/boonebgorges/buddypress-docs
Description: Adds collaborative Docs to BuddyPress
-Version: 1.5.7
+Version: 1.6.0
Author: Boone B Gorges
Author URI: http://boone.gorg.es
Licence: GPLv3
@@ -13,7 +13,7 @@
It's on like Donkey Kong
*/
-define( 'BP_DOCS_VERSION', '1.5.7' );
+define( 'BP_DOCS_VERSION', '1.6.0' );
// BuddyPress Docs introduces a lot of overhead. Unless otherwise specified,
// don't load the plugin on subsites of an MS install
diff --git a/readme.txt b/readme.txt
index d92f392c..3ce9c01a 100755
--- a/readme.txt
+++ b/readme.txt
@@ -3,8 +3,8 @@ Contributors: boonebgorges, cuny-academic-commons
Donate link: http://teleogistic.net/donate
Tags: buddypress, docs, wiki, documents, collaboration
Requires at least: WordPress 3.3, BuddyPress 1.5
-Tested up to: WordPress 3.8, BuddyPress 1.9.2
-Stable tag: 1.5.7
+Tested up to: WordPress 3.9, BuddyPress 2.0.0
+Stable tag: 1.6.0
Adds collaborative Docs to BuddyPress.
@@ -33,6 +33,13 @@ This plugin is in active development. For feature requests and bug reports, visi
== Changelog ==
+= 1.6.0 =
+* Overhaul of the way group/user tag clouds work
+* Improved support for attachments on nginx and IIS
+* Improved doc edit locking mechanisms
+* Improved appearance on devices of various sizes
+* Support for WordPress 3.9 and TinyMCE 4.x
+
= 1.5.7 =
* Improve appearance of row actions on mobile devices
* Improve appearance of tags filter on IE < 9
diff --git a/tests/test-bp-docs.php b/tests/test-bp-docs.php
index 993678f7..f397b16a 100644
--- a/tests/test-bp-docs.php
+++ b/tests/test-bp-docs.php
@@ -76,21 +76,23 @@ function test_change_group_association() {
$group = $this->factory->group->create();
$group2 = $this->factory->group->create();
- $doc_id = $this->factory->doc->create( array( 'group' => $group->id ) );
+ $doc_id = $this->factory->doc->create( array(
+ 'group' => $group,
+ ) );
- bp_docs_set_associated_group_id( $doc_id, $group2->id );
+ bp_docs_set_associated_group_id( $doc_id, $group );
- $this->assertEquals( bp_docs_get_associated_group_id( $doc_id ), $group2->id );
+ $this->assertEquals( bp_docs_get_associated_group_id( $doc_id ), $group );
}
function test_set_group_association_on_create() {
- $doc_id = $this->factory->doc->create( array( 'group' => $group->id ) );
-
$group = $this->factory->group->create();
+ $doc_id = $this->factory->doc->create( array( 'group' => $group ) );
+
$permalink = get_permalink( $doc_id );
$this->go_to( $permalink );
- $_POST['associated_group_id'] = $group->id;
+ $_POST['associated_group_id'] = $group;
//unset( $_POST['associated_group_id'] );
// We need this dummy $_POST data to make the save go through. Ugh
@@ -103,12 +105,14 @@ function test_set_group_association_on_create() {
$maybe_group_id = bp_docs_get_associated_group_id( $doc_id );
- $this->assertEquals( $group->id, $maybe_group_id );
+ $this->assertEquals( $group, $maybe_group_id );
}
function test_delete_group_association() {
$group = $this->factory->group->create();
- $doc_id = $this->factory->doc->create( array( 'group' => $group->id ) );
+ $doc_id = $this->factory->doc->create( array(
+ 'group' => $group,
+ ) );
$permalink = get_permalink( $doc_id );
$this->go_to( $permalink );
@@ -117,6 +121,7 @@ function test_delete_group_association() {
// We need this dummy $_POST data to make the save go through. Ugh
$doc = $this->factory->doc->get_object_by_id( $doc_id );
+ $_POST['doc_id'] = $doc_id;
$_POST['doc_content'] = $doc->post_content;
$_POST['doc']['title'] = $doc->post_title;
@@ -144,6 +149,61 @@ function test_bp_docs_get_doc_link() {
}
+ /**
+ * @group last_activity
+ */
+ function test_update_group_last_activity_on_new_doc() {
+ $g = $this->factory->group->create();
+ $d = $this->factory->doc->create( array(
+ 'group' => $g,
+ ) );
+
+ $last_activity = date( 'Y-m-d H:i:s', time() - 100000 );
+ groups_update_groupmeta( $g, 'last_activity', $last_activity );
+
+ // call manually because the hook is outside of the proper
+ // group document creation workflow
+ do_action( 'bp_docs_after_save', $d );
+
+ $this->assertNotEquals( $last_activity, groups_get_groupmeta( $g, 'last_activity' ) );
+ }
+
+ /**
+ * @group last_activity
+ */
+ function test_update_group_last_activity_on_doc_delete() {
+ $g = $this->factory->group->create();
+ $d = $this->factory->doc->create( array(
+ 'group' => $g,
+ ) );
+
+ $last_activity = date( 'Y-m-d H:i:s', time() - 100000 );
+ groups_update_groupmeta( $g, 'last_activity', $last_activity );
+
+ bp_docs_trash_doc( $d );
+
+ $this->assertNotEquals( $last_activity, groups_get_groupmeta( $g, 'last_activity' ) );
+ }
+
+ /**
+ * @group last_activity
+ */
+ function test_update_group_last_activity_on_doc_comment() {
+ $g = $this->factory->group->create();
+ $d = $this->factory->doc->create( array(
+ 'group' => $g,
+ ) );
+
+ $last_activity = date( 'Y-m-d H:i:s', time() - 100000 );
+ groups_update_groupmeta( $g, 'last_activity', $last_activity );
+
+ $c = $this->factory->comment->create( array(
+ 'comment_post_ID' => $d,
+ ) );
+
+ $this->assertNotEquals( $last_activity, groups_get_groupmeta( $g, 'last_activity' ) );
+ }
+
}