Co-Authors Plus - Version 1.1.3

Version Description

Download this release

Release Info

Developer batmoo
Plugin Icon wp plugin Co-Authors Plus
Version 1.1.3
Comparing to
See all releases

Version 1.1.3

admin.css ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #coauthors-table {
2
+
3
+ }
4
+ div.dbx-content #coauthors-table {
5
+ width:100%;
6
+ }
7
+ #coauthors-table td {
8
+ padding-left:0;
9
+ padding-right:0;
10
+ vertical-align: middle;
11
+ background: #F9F9F9;
12
+ }
13
+ #coauthors-table td.select select {
14
+ margin-top:0;
15
+ }
16
+ div.dbx-content #coauthors-table td.select select {
17
+ width:100%;
18
+ }
19
+
20
+ span.author-tag {
21
+ display:block;
22
+ padding: 5px 3px;
23
+ color: #21759B;
24
+ border-bottom: 1px solid #21759B;
25
+ cursor: text;
26
+ }
27
+ span.author-tag:hover {
28
+ cursor: text;
29
+ background: #EAF2FA ;
30
+ color:#D54E21;
31
+ }
32
+ input.coauthor-suggest {
33
+ margin:5px 0;
34
+ color:#888;
35
+ }
36
+ input.coauthor-suggest:focus {
37
+ color: #333;
38
+ }
39
+
40
+ span.delete-coauthor {
41
+ padding: 3px;
42
+ text-decoration: underline;
43
+ color:#FF0000;
44
+ font-size:11px;
45
+ }
46
+ span.delete-coauthor:hover {
47
+ cursor: pointer;
48
+ background: #FF0000;
49
+ color: #fff;
50
+ }
admin.js ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ (function(){
3
+
4
+ var coauthors_table = null;
5
+
6
+ var coauthorsTable = jQuery('#coauthors-table');
7
+ var editing = false;
8
+
9
+ /*
10
+ * Get an author's name from their ID
11
+ * Iterates through the coauthors-select input box until finds the entry with the associated ID
12
+ *
13
+ */
14
+ function coauthors_get_author_name( authorID ) {
15
+ var select = jQuery('#coauthors-select');
16
+
17
+ if(authorID){
18
+ //Find the provided author ID
19
+ var name = "";
20
+ select.find("option").each(function(i){
21
+ if(this.value == authorID) {
22
+ name = this.innerHTML;
23
+ return;
24
+ }
25
+
26
+ });
27
+ return name;
28
+ }
29
+ return false;
30
+
31
+ }
32
+
33
+
34
+ function coauthors_select_author( authorID, selectID ) {
35
+ if(!selectID) selectID = '#coauthors-select';
36
+
37
+ var select = jQuery(selectID);
38
+
39
+ if(authorID){
40
+ //Find the provided author ID
41
+ select.find("option").each(function(i){
42
+ if(this.value == authorID) {
43
+ jQuery(this).attr('selected','true')
44
+ return false;
45
+ }
46
+ });
47
+ }
48
+
49
+ }
50
+
51
+ function coauthors_remove_author( authorName ) {
52
+ var select = jQuery('#coauthors-select');
53
+ if(authorName){
54
+ //Find the provided author ID
55
+ select.find("option").each(function(i){
56
+ if(this.innerHTML == authorName) {
57
+ jQuery(this).removeAttr('selected');
58
+ return true;
59
+ }
60
+ });
61
+ }
62
+ }
63
+
64
+ // Old function not needed; though may be useful for duplicate validation
65
+ var coauthors_select_onchange = function(event){
66
+
67
+ };
68
+
69
+ var coauthors_delete_onclick = function(event){
70
+
71
+ if(confirm('Are you sure you want to delete this author?')) {
72
+ var tr = jQuery(this).parent().parent();
73
+ var name = tr.find('span.author-tag').text();
74
+ coauthors_remove_author(name);
75
+ tr.remove();
76
+
77
+ return true;
78
+ }
79
+ return false;
80
+ };
81
+
82
+ function coauthors_insert_author_edit_cells(tr){
83
+
84
+ var deleteBtn = jQuery('<span></span>')
85
+ .addClass('delete-coauthor')
86
+ .text('Delete')
87
+ .bind('click', coauthors_delete_onclick)
88
+ ;
89
+
90
+ var td = jQuery('<td></td>')
91
+ .addClass('delete')
92
+ ;
93
+ td.append(deleteBtn);
94
+ jQuery(tr).append(td);
95
+ return tr;
96
+
97
+ }
98
+
99
+ function coauthors_save_coauthor(authorID, authorName, co) {
100
+
101
+ coauthors_remove_author(co.next().text());
102
+
103
+ // get sibling <span>, update, and hide
104
+ co.next().html(authorName)
105
+ .show()
106
+ ;
107
+
108
+ // select new author
109
+ if(co.attr('name')=='coauthors-main') {
110
+ coauthors_select_author( authorID, '#post_author_override' );
111
+ } else {
112
+ coauthors_select_author( authorID )
113
+ }
114
+
115
+ editing = false;
116
+ }
117
+
118
+
119
+
120
+ function coauthors_add_coauthor(authorID, authorName, co, init){
121
+ var selectedIndex = -1;
122
+
123
+ if(editing) {
124
+ coauthors_save_coauthor(authorID, authorName, co)
125
+
126
+ } else {
127
+
128
+ if(!co) var co = coauthors_create_autosuggest(authorName)
129
+ var tag = coauthors_create_author_tag(authorName);
130
+
131
+ coauthors_add_to_table(co, tag);
132
+
133
+ // Add new author to <select>
134
+ coauthors_select_author( authorID )
135
+
136
+ if(!init) {
137
+ // Create new author-suggest and append it to a new row
138
+ var newCO = coauthors_create_autosuggest('', false);
139
+ coauthors_add_to_table(newCO);
140
+ }
141
+ }
142
+
143
+ co.bind('blur', coauthors_stop_editing);
144
+
145
+ // Set the value for the auto-suggest box to the Author's name and hide it
146
+ co.val(authorName)
147
+ .hide()
148
+ .unbind('focus')
149
+ ;
150
+
151
+ return true;
152
+ }
153
+
154
+
155
+ function coauthors_add_to_table( co, tag, del ) {
156
+ if(co) {
157
+ var td = jQuery('<td></td>');
158
+ td.className = 'suggest';
159
+ td.append(co);
160
+ td.append(tag);
161
+ var tr = jQuery('<tr></tr>');
162
+ tr.append(td);
163
+
164
+ //Add buttons to row
165
+ if(tag && !del) coauthors_insert_author_edit_cells(tr);
166
+
167
+ jQuery('#coauthors-table').append(tr);
168
+ }
169
+ }
170
+
171
+ function coauthors_create_autosuggest(authorName, inputName) {
172
+
173
+ if(!inputName) inputName = 'coauthors2[]';
174
+
175
+ var co = jQuery('<input/>')
176
+ .attr({
177
+ 'class': 'coauthor-suggest',
178
+ 'name': inputName
179
+ })
180
+ .appendTo(div)
181
+
182
+ .suggest(coauthor_ajax_suggest_link,{
183
+ onSelect:
184
+ function() {
185
+
186
+ var vals = this.value.split("|");
187
+
188
+ var id = jQuery.trim(vals[0]);
189
+ var name = jQuery.trim(vals[1]);
190
+
191
+ if(id=="New") {
192
+ alert('Eventually, this will allow you to add a new author right from here. But it\'s not ready yet. *sigh*');
193
+ } else {
194
+ coauthors_add_coauthor(id, name, co);
195
+ }
196
+ }
197
+ })
198
+ .keydown(function(e) {
199
+ if(e.keyCode == 13) {return false;}
200
+
201
+ })
202
+ ;
203
+
204
+ if(authorName)
205
+ co.attr('value', authorName);
206
+ else
207
+ co.attr('value', 'Search for an author')
208
+ .focus(function(){co.val('')})
209
+ .blur(function(){co.val('Search for an author')})
210
+ ;
211
+
212
+ return co;
213
+
214
+ }
215
+
216
+ function coauthors_stop_editing(event) {
217
+ var co = jQuery(event.target);
218
+ var tag = jQuery(co.next());
219
+
220
+ co.attr('value',tag.text());
221
+
222
+ co.hide();
223
+ tag.show();
224
+ editing = false;
225
+ }
226
+
227
+ function coauthors_create_author_tag (name) {
228
+ var tag = jQuery('<span></span>')
229
+ .html(name)
230
+ .attr('title', 'Click to edit')
231
+ .addClass('author-tag')
232
+ // Add Click event to edit
233
+ .click(function(){
234
+ if(!editing) {
235
+ editing = true;
236
+
237
+ var co = tag.prev();
238
+
239
+ tag.hide();
240
+ co.show()
241
+ .focus()
242
+ ;
243
+
244
+ co.previousAuthor = tag.text();
245
+ }
246
+
247
+ });
248
+
249
+ return tag;
250
+ }
251
+
252
+
253
+ if(document.getElementById('post_author_override')){
254
+ if(!coauthors_can_edit_others_posts){
255
+ jQuery('#authordiv, #pageauthordiv').remove();
256
+ return;
257
+ }
258
+
259
+ //Note that there can be co-authors (changes dbx title from "Post Author" to "Post Author(s)")
260
+ var h3 = jQuery('#authordiv :header, #pageauthordiv :header').html(
261
+ /page[^\/]+$/.test(window.location.href) ?
262
+ coauthors_dbx_page_title
263
+ :
264
+ coauthors_dbx_post_title
265
+ );
266
+
267
+ //Add the controls to add co-authors
268
+ var div = jQuery('#authordiv div, #pageauthordiv div').filter(function(){
269
+ if(jQuery(this).is('.inside') || jQuery(this).is('.dbx-content'))
270
+ return true;
271
+ return false;
272
+ })[0];
273
+
274
+ if(div){
275
+
276
+ var table = jQuery('<table></table>')
277
+ .attr('id', 'coauthors-table')
278
+ ;
279
+
280
+ var coauthors_table = jQuery('<tbody></tbody>')
281
+ .appendTo(table)
282
+ ;
283
+
284
+ var tr = jQuery('<tr></tr>');
285
+ var td = jQuery('<td></td>')
286
+ .addClass('select')
287
+ ;
288
+
289
+ var select = jQuery('#post_author_override')[0];
290
+
291
+ td.append(select);
292
+ tr.append(td);
293
+ coauthors_table.append(tr);
294
+ jQuery(div).append(table);
295
+
296
+ // Create input and span for first entry
297
+ var nameFirst = select[select.selectedIndex].innerHTML;
298
+ var coFirst = coauthors_create_autosuggest(nameFirst, 'coauthors-main')
299
+ coFirst.hide();
300
+ var tagFirst = coauthors_create_author_tag(nameFirst);
301
+ jQuery(select).after(tagFirst)
302
+ .after(coFirst)
303
+ ;
304
+ // Add blur event to suggest box
305
+ coFirst.bind('blur', coauthors_stop_editing);
306
+
307
+ // Create coauthors select box by cloning it from the drop-down
308
+ var coauthors = jQuery('#post_author_override').clone(true)
309
+ .attr('id', 'coauthors-select')
310
+ .attr('name', 'coauthors[]')
311
+ .attr({'multiple':'multiple', 'size':5})
312
+ .attr('style','height:10em')
313
+ .attr('selectedIndex', '-1')
314
+ ;
315
+ coauthors.insertAfter('#post_author_override');
316
+
317
+ // Hide both select boxes
318
+ jQuery('#post_author_override').hide();
319
+ coauthors.hide();
320
+
321
+ var help = jQuery('<p></p>').text('Click on an author to edit. Click on "Delete" to remove them.');
322
+ jQuery('#authordiv .inside').append(help);
323
+
324
+ var presenceInput;
325
+ try {
326
+ //For MSIE
327
+ presenceInput = document.createElement('<input name="coauthors_plugin_is_active" type="hidden" value="1" />');
328
+ if(!presenceInput || presenceInput.name != 'coauthors_plugin_is_active')
329
+ throw Error();
330
+ } catch(e){
331
+ presenceInput = document.createElement('input');
332
+ presenceInput.name = "coauthors_plugin_is_active";
333
+ presenceInput.value = 1;
334
+ presenceInput.type = 'hidden';
335
+ }
336
+ div.appendChild(presenceInput);
337
+ }
338
+
339
+ // Select authors already added to the post
340
+ var addedAlready = {};
341
+ jQuery('#the-list tr').each(function(){
342
+ var userID = jQuery(this).find('textarea').val();
343
+ if(jQuery(this).find("input[@value='_coauthor']").length && !addedAlready[userID]){
344
+ var authorName = coauthors_get_author_name(userID);
345
+ if(authorName) coauthors_add_coauthor(userID, authorName, undefined, true );
346
+ addedAlready[userID] = true;
347
+ }
348
+ });
349
+
350
+ // Create new author-suggest and append it to a new row
351
+ var newCO = coauthors_create_autosuggest('', false);
352
+ coauthors_add_to_table(newCO);
353
+
354
+ }
355
+
356
+ })();
co-authors.php ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Co-Authors Plus
4
+ Plugin URI: http://wordpress.org/extend/plugins/co-authors-plus/
5
+ Description: Allows multiple authors to be assigned to a post. Co-authored posts appear on a co-author's posts page and feed. New template tags allow listing of co-authors. Editors may assign co-authors to a post via the 'Post Author' box. <em>This plugin is an extended version of the Co-Authors plugin originally developed at [Shepherd Interactive](http://www.shepherd-interactive.com/ "Shepherd Interactive specializes in web design and development in Portland, Oregon") (2007). Their plugin was inspired by 'Multiple Authors' plugin by Mark Jaquith (2005).</em>
6
+ Version: 1.1.3
7
+ Author: Mohammad Jangda
8
+ Author URI: http://digitalize.ca
9
+ Copyright: Some parts (C) 2009, Mohammad; Other parts (C) 2008, Weston Ruter, Shepherd Interactive
10
+
11
+ GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
12
+ This program is free software; you can redistribute it and/or modify
13
+ it under the terms of the GNU General Public License as published by
14
+ the Free Software Foundation; either version 2 of the License, or
15
+ (at your option) any later version.
16
+
17
+ This program is distributed in the hope that it will be useful,
18
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ GNU General Public License for more details.
21
+
22
+ You should have received a copy of the GNU General Public License
23
+ along with this program; if not, write to the Free Software
24
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
+
26
+
27
+ ## Change Log ##
28
+
29
+ *2009-04-23 / 1.1.3*
30
+
31
+ * Add blur event to disable input box
32
+ * Limit only one edit at a time.
33
+ * Check Cross-browser compatibility (Firefox 3 OS X, Safari 3 OS X, IE7 Vista).
34
+ * Add suggest javascript plugin to Edit Page.
35
+
36
+ *2009-04-19 / 1.1.2*
37
+
38
+ * Disabled form submit when enter pressed.
39
+
40
+ *2009-04-15 / 1.1.1*
41
+
42
+ * Changed SQL query to return only contributer-level and above users.
43
+
44
+ *2009-04-14: 1.1.0*
45
+
46
+ @@ To do @@
47
+ - Setting to enable/disable co-authors for Pages
48
+ - Check Cross-browser compatibility
49
+ - admin.js: need to check to ensure that an author added is not a duplicate
50
+ - Display all coauthors in table on "Edit Posts" page
51
+
52
+ */
53
+
54
+ define('COAUTHORS_DEFAULT_BEFORE', '');
55
+ define('COAUTHORS_DEFAULT_BETWEEN', ', ');
56
+ define('COAUTHORS_DEFAULT_BETWEEN_LAST', ' and ');
57
+ define('COAUTHORS_DEFAULT_AFTER', '');
58
+ define('COAUTHORS_VERSION', '1.1.2');
59
+
60
+ if(floatval(get_option('coauthors_version')) < 1.0)
61
+ coauthors_updatedb();
62
+
63
+ add_option('coauthors_version', COAUTHORS_VERSION);
64
+
65
+ function coauthors_updatedb(){
66
+ global $wpdb;
67
+ //Update old versions of plugin to use new hidden meta key
68
+ $wpdb->query("UPDATE $wpdb->postmeta SET meta_key = '_coauthor' WHERE meta_key = 'coauthor';");
69
+ }
70
+ register_activation_hook(__FILE__, 'coauthors_updatedb');
71
+
72
+ # Load up the localization file if we're using WordPress in a different language
73
+ # Place l10n files named like "co-authors-[value in wp-config].mo" in the "localization" folder
74
+ load_plugin_textdomain('co-authors', PLUGINDIR . '/co-authors-plus/localization');
75
+
76
+ function coauthors_user_has_cap($allcaps, $caps, $args){
77
+ $current_user = wp_get_current_user();
78
+
79
+ $relatedCaps = array(
80
+ 'edit_post',
81
+ 'edit_others_posts',
82
+ 'publish_posts',
83
+ 'edit_page',
84
+ 'edit_others_pages',
85
+ 'publish_pages',
86
+ 'edit_pages',
87
+ 'edit_posts',
88
+ 'edit_published_pages',
89
+ 'edit_published_posts',
90
+ //delete_post
91
+ //delete_page
92
+ //moderate_comments
93
+ );
94
+
95
+ foreach($caps as $cap){
96
+ if(!in_array($cap, $relatedCaps))
97
+ return $allcaps;
98
+ }
99
+
100
+ //Get the post in question
101
+ $postID = $args[2] ? $args[2] : $_POST['ID'];
102
+ $post = get_post($postID);
103
+ $post_status = $_POST['post_status'] ? $_POST['post_status'] : $post->post_status;
104
+
105
+ //Disallow if post is published and they are a contributor
106
+ if(!in_array($post_status, array('draft','pending')) && (($post->post_type == 'post' && !$allcaps['edit_published_posts']) || ($post->post_type == 'page' && !$allcaps['edit_published_pages']))){
107
+ return $allcaps;
108
+ }
109
+
110
+ $coauthors = get_post_custom_values('_coauthor', $postID);
111
+ if(!empty($coauthors) && in_array($current_user->ID, $coauthors)){
112
+ foreach($relatedCaps as $cap){
113
+ $allcaps[$cap] = true;
114
+ }
115
+ }
116
+
117
+ return $allcaps;
118
+ }
119
+ add_filter('user_has_cap', 'coauthors_user_has_cap', 10, 3);
120
+
121
+
122
+ //Modify the author query posts SQL to include posts co-authored
123
+ function coauthors_posts_join_filter($join){
124
+ global $wpdb,$wp_query;
125
+ if(is_author()){
126
+ $join .= " LEFT JOIN $wpdb->postmeta ON $wpdb->postmeta.post_id = $wpdb->posts.id "
127
+ . "AND $wpdb->postmeta.meta_key = '_coauthor' "
128
+ . "AND $wpdb->postmeta.meta_value = '" . $wp_query->query_vars['author'] . "' "; //this condition removes need for DISTINCT
129
+ }
130
+ return $join;
131
+ }
132
+ add_filter('posts_join', 'coauthors_posts_join_filter');
133
+ function coauthors_posts_where_filter($where){
134
+ global $wpdb;
135
+ if(is_author())
136
+ $where = preg_replace('/(\b(?:' . $wpdb->posts . '\.)?post_author\s*=\s*(\d+))/', '($1 OR (' . $wpdb->postmeta . '.meta_value = \'$2\'))', $where, 1); #' . $wpdb->postmeta . '.meta_id IS NOT NULL AND
137
+ return $where;
138
+ }
139
+ add_filter('posts_where', 'coauthors_posts_where_filter');
140
+
141
+ //function coauthors_posts_query_filter($sql){ //this was needed when meta_value = query_vars[author] was not tested in the LEFT JOIN ON clause
142
+ // return preg_replace("{^(\s*SELECT\b(?!\s*DISTINCT))}i", '$1 DISTINCT', $sql);
143
+ //}
144
+ //add_filter('posts_request', 'coauthors_posts_query_filter');
145
+
146
+
147
+ class CoAuthorsIterator {
148
+ var $position = -1;
149
+ var $original_authordata;
150
+ var $authordata_array;
151
+ var $count;
152
+
153
+ function CoAuthorsIterator($postID = 0){
154
+ global $post, $authordata, $wpdb;
155
+ $postID = (int)$postID;
156
+ if(!$postID && $post)
157
+ $postID = (int)$post->ID;
158
+ if(!$postID)
159
+ trigger_error(__('No post ID provided for CoAuthorsIterator constructor. Are you not in a loop or is $post not set?', 'co-authors')); //return null;
160
+ if(empty($authordata))
161
+ $authordata = get_userdata($wpdb->get_var("SELECT post_author FROM $wpdb->posts WHERE ID = $postID;"));
162
+
163
+ //Gather all of the co-authors
164
+ $this->authordata_array = array($authordata);
165
+ $userids = get_post_meta($post->ID, '_coauthor', false);
166
+ if(!empty($userids)){
167
+ if(!is_array($userids))
168
+ $userids = array($userids);
169
+ foreach($userids as $user_id){
170
+ $a = get_userdata($user_id);
171
+ if(!empty($a)) //in case the user has been deleted while plugin was deactivated
172
+ $this->authordata_array[] = $a;
173
+ }
174
+ }
175
+ $this->count = count($this->authordata_array);
176
+ }
177
+
178
+ function iterate(){
179
+ global $authordata;
180
+ $this->position++;
181
+
182
+ //At the end of the loop
183
+ if($this->position > $this->count-1){
184
+ $authordata = $this->original_authordata;
185
+ $this->position = -1;
186
+ return false;
187
+ }
188
+
189
+ //At the beginning of the loop
190
+ if($this->position == 0 && !empty($authordata))
191
+ $this->original_authordata = $authordata;
192
+
193
+ $authordata = $this->authordata_array[$this->position];
194
+
195
+ return true;
196
+ }
197
+
198
+ function get_position(){
199
+ if($this->position === -1)
200
+ return false;
201
+ return $this->position;
202
+ }
203
+ function is_last(){
204
+ return $this->position === $this->count-1;
205
+ }
206
+ function is_first(){
207
+ return $this->position === 0;
208
+ }
209
+ function count(){
210
+ return $this->count;
211
+ }
212
+ function get_all(){
213
+ return $this->authordata_array;
214
+ }
215
+ }
216
+
217
+ //Helper function for the following new template tags
218
+ function coauthors__echo($tag, $between, $betweenLast, $before, $after){
219
+ $i = new CoAuthorsIterator();
220
+ echo $before;
221
+ if($i->iterate())
222
+ $tag();
223
+ while($i->iterate()){
224
+ echo $i->is_last() ? $betweenLast : $between;
225
+ $tag();
226
+ }
227
+ echo $after;
228
+ }
229
+
230
+ //Provide co-author equivalents to the existing author template tags
231
+ function coauthors($between = null, $betweenLast = null, $before = null, $after = null){
232
+ if($between === NULL)
233
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
234
+ if($betweenLast === NULL)
235
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
236
+ if($before === NULL)
237
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
238
+ if($after === NULL)
239
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
240
+ coauthors__echo('the_author', $between, $betweenLast, $before, $after);
241
+ }
242
+ function coauthors_posts_links($between = null, $betweenLast = null, $before = null, $after = null){
243
+ if($between === NULL)
244
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
245
+ if($betweenLast === NULL)
246
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
247
+ if($before === NULL)
248
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
249
+ if($after === NULL)
250
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
251
+ coauthors__echo('the_author_posts_link', $between, $betweenLast, $before, $after);
252
+ }
253
+ function coauthors_firstnames($between = null, $betweenLast = null, $before = null, $after = null){
254
+ if($between === NULL)
255
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
256
+ if($betweenLast === NULL)
257
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
258
+ if($before === NULL)
259
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
260
+ if($after === NULL)
261
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
262
+ coauthors__echo('the_author_firstname', $between, $betweenLast, $before, $after);
263
+ }
264
+ function coauthors_lastnames($between = null, $betweenLast = null, $before = null, $after = null){
265
+ if($between === NULL)
266
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
267
+ if($betweenLast === NULL)
268
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
269
+ if($before === NULL)
270
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
271
+ if($after === NULL)
272
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
273
+ coauthors__echo('the_author_lastname', $between, $betweenLast, $before, $after);
274
+ }
275
+ function coauthors_nicknames($between = null, $betweenLast = null, $before = null, $after = null){
276
+ if($between === NULL)
277
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
278
+ if($betweenLast === NULL)
279
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
280
+ if($before === NULL)
281
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
282
+ if($after === NULL)
283
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
284
+ coauthors__echo('the_author_nickname', $between, $betweenLast, $before, $after);
285
+ }
286
+ function coauthors_links($between = null, $betweenLast = null, $before = null, $after = null){
287
+ if($between === NULL)
288
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
289
+ if($betweenLast === NULL)
290
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
291
+ if($before === NULL)
292
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
293
+ if($after === NULL)
294
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
295
+ coauthors__echo('the_author_link', $between, $betweenLast, $before, $after);
296
+ }
297
+ function coauthors_IDs($between = null, $betweenLast = null, $before = null, $after = null){
298
+ if($between === NULL)
299
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
300
+ if($betweenLast === NULL)
301
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
302
+ if($before === NULL)
303
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
304
+ if($after === NULL)
305
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
306
+ coauthors__echo('the_author_ID', $between, $betweenLast, $before, $after);
307
+ }
308
+ //function coauthors_emails($between = null, $betweenLast = null, $before = null, $after = null){
309
+ // if($between === NULL)
310
+ // $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
311
+ // if($betweenLast === NULL)
312
+ // $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
313
+ // if($before === NULL)
314
+ // $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
315
+ // if($after === NULL)
316
+ // $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
317
+ // coauthors__echo('the_author_email', $between, $betweenLast, $before, $after);
318
+ //}
319
+ //function coauthors_urls($between = null, $betweenLast = null, $before = null, $after = null){
320
+ // if($between === NULL)
321
+ // $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
322
+ // if($betweenLast === NULL)
323
+ // $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
324
+ // if($before === NULL)
325
+ // $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
326
+ // if($after === NULL)
327
+ // $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
328
+ // coauthors__echo('the_author_url', $between, $betweenLast, $before, $after);
329
+ //}
330
+ //function coauthors_icq($between = null, $betweenLast = null, $before = null, $after = null){
331
+ // if($between === NULL)
332
+ // $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
333
+ // if($betweenLast === NULL)
334
+ // $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
335
+ // if($before === NULL)
336
+ // $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
337
+ // if($after === NULL)
338
+ // $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
339
+ // coauthors__echo('the_author_icq', $between, $betweenLast, $before, $after);
340
+ //}
341
+
342
+
343
+ function coauthors_init(){
344
+ if(is_admin())
345
+ wp_enqueue_script( 'jquery' );
346
+ }
347
+ add_action('init', 'coauthors_init');
348
+
349
+ function coauthors_add_stylesheet() {
350
+ global $current_user;
351
+ print '<link rel="stylesheet" type="text/css" href="../' . PLUGINDIR . '/co-authors-plus/admin.css" />';
352
+ }
353
+ add_action('admin_print_scripts', 'coauthors_add_stylesheet');
354
+
355
+ function coauthors_modify_post_sidebar(){
356
+ global $current_user;
357
+
358
+ print '<script type="text/javascript">';
359
+ print 'var coauthors_can_edit_others_posts = ' . ($current_user->has_cap('edit_others_posts') ? 'true' : 'false') . "\n";
360
+ print 'var coauthors_dbx_post_title = "' . __('Post Author(s)', 'co-authors') . '";';
361
+ print 'var coauthors_dbx_page_title = "' . __('Page Author(s)', 'co-authors') . '";';
362
+ print 'var coauthors_add_author_label = "' . __('+ Add author', 'co-authors') . '";';
363
+ print 'var coauthors_confirm_delete_label = "' . __('Are you sure you want to remove the user \u201C%s\u201D as an author?', 'co-authors') . '";';
364
+ #print 'var coauthors_moveUp_author_label = "' . __('+ Add author', 'co-authors') . '";';
365
+ #print 'var coauthors_moveDown_author_label = "' . __('+ Add author', 'co-authors') . '";';
366
+ #print 'var coauthors_delete_author_label = "' . __('+ Add author', 'co-authors') . '";';
367
+ print '</script>';
368
+
369
+ print '<script type="text/javascript" src="../' . PLUGINDIR . '/co-authors-plus/admin.js"></script>';
370
+
371
+
372
+ }
373
+ add_action('admin_footer', 'coauthors_modify_post_sidebar'); //dbx_post_sidebar,edit_form_advanced
374
+
375
+ //Update a post's co-authors
376
+ function coauthors_update_post($postID){
377
+ global $current_user, $wpdb;
378
+ if($current_user->has_cap('edit_others_posts') && @$_POST['coauthors_plugin_is_active']){
379
+ //Delete all existing co-authors from a post
380
+ delete_post_meta($postID, '_coauthor');
381
+
382
+ //Newly add each co-author to the post meta
383
+ if(is_array($_POST['coauthors'])){
384
+ foreach(array_unique($_POST['coauthors']) as $authorID){
385
+ if(is_numeric($authorID) && $wpdb->get_var("SELECT ID FROM $wpdb->users WHERE ID = $authorID")){
386
+ add_post_meta($postID, '_coauthor', (int)$authorID, false);
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ add_action('edit_post', 'coauthors_update_post');
393
+ add_action('save_post', 'coauthors_update_post');
394
+
395
+ function coauthors_delete_user_action($userID){
396
+ global $wpdb;
397
+ //$reassign = null;
398
+ ////Get $reassign parameter from calling wp_delete_user function
399
+ //if(function_exists('debug_backtrace')){
400
+ // $callstack = debug_backtrace();
401
+ // foreach($callstack as $caller){
402
+ // if($caller['function'] == 'wp_delete_user'){
403
+ // if(is_numeric($caller['args'][1/*reassign*/]))
404
+ // $reassign = (int)$caller['args'][1/*reassign*/];
405
+ // break;
406
+ // }
407
+ // }
408
+ //}
409
+ ////Otherwise, try to get the reassign user from POST data
410
+ //else if(@$_POST['delete_option'] == 'reassign' && is_numeric(@$_POST['reassign_user'])) {
411
+ // $reassign = (int)$_POST['reassign_user'];
412
+ //}
413
+
414
+ //Reassign all co-author post meta
415
+ //if($reassign){
416
+ // $postIDs = $wpdb->get_col("SELECT ID FROM $wpdb->posts p LEFT JOIN $wpdb->postmeta pm ON p.ID = pm.post_id AND p.post_type != 'revision' AND pm.meta_key = '_coauthor' AND pm.meta_value = '$reassign';");
417
+ // foreach($postIDs as $postID){
418
+ // //if the post's post_author != $reassign and there isn't a post meta coauthor which is $reassign
419
+ // if($wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts p
420
+ // LEFT JOIN $wpdb->postmeta pm
421
+ // ON p.ID = pm.post_id AND pm.meta_key = '_coauthor' AND pm.meta_value = '$reassign'
422
+ // WHERE p.ID = $postID AND p.post_type != 'revision' AND (p.post_author = '$reassign' OR pm.meta_value = '$reassign')") == 0)
423
+ // {
424
+ // update_post_meta($postID, '_coauthor', $reassign, $userID);
425
+ // }
426
+ // //the reassign author already exists for this post, so just delete the post meta
427
+ // else {
428
+ // delete_post_meta($postID, '_coauthor', $userID);
429
+ // }
430
+ // }
431
+ //}
432
+ ////Delete all co-author post meta
433
+ //else
434
+ $wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key = '_coauthor' AND meta_value = '$userID';");
435
+ }
436
+ add_action('delete_user', 'coauthors_delete_user_action');
437
+
438
+
439
+ //customized wp_list_authors() from WP core
440
+ /**
441
+ * List all the *co-authors* of the blog, with several options available.
442
+ * optioncount (boolean) (false): Show the count in parenthesis next to the author's name.
443
+ * exclude_admin (boolean) (true): Exclude the 'admin' user that is installed by default.
444
+ * show_fullname (boolean) (false): Show their full names.
445
+ * hide_empty (boolean) (true): Don't show authors without any posts.
446
+ * feed (string) (''): If isn't empty, show links to author's feeds.
447
+ * feed_image (string) (''): If isn't empty, use this image to link to feeds.
448
+ * echo (boolean) (true): Set to false to return the output, instead of echoing.
449
+ * @param array $args The argument array.
450
+ * @return null|string The output, if echo is set to false.
451
+ */
452
+ function coauthors_wp_list_authors($args = ''){
453
+ global $wpdb;
454
+
455
+ $defaults = array(
456
+ 'optioncount' => false, 'exclude_admin' => true,
457
+ 'show_fullname' => false, 'hide_empty' => true,
458
+ 'feed' => '', 'feed_image' => '', 'echo' => true
459
+ );
460
+
461
+ $r = wp_parse_args( $args, $defaults );
462
+ extract($r, EXTR_SKIP);
463
+
464
+ $return = '';
465
+
466
+ // TODO: Move select to get_authors().
467
+ $authors = $wpdb->get_results("SELECT ID, user_nicename from $wpdb->users " . ($exclude_admin ? "WHERE user_login <> 'admin' " : '') . "ORDER BY display_name");
468
+
469
+ $author_count = array();
470
+ $sql = "SELECT DISTINCT
471
+ p1.post_author,
472
+ (COUNT(ID)+(SELECT COUNT(*)
473
+ FROM $wpdb->posts p2, $wpdb->postmeta pm
474
+ WHERE p2.ID = pm.post_id
475
+ AND pm.meta_key = '_coauthor'
476
+ AND pm.meta_value = p1.post_author)
477
+ ) AS count
478
+ FROM $wpdb->posts p1
479
+ WHERE post_type = 'post' AND " . get_private_posts_cap_sql( 'post' ) . "
480
+ GROUP BY post_author";
481
+
482
+ foreach ((array) $wpdb->get_results($sql) as $row) {
483
+ $author_count[$row->post_author] = $row->count;
484
+ }
485
+
486
+ foreach ( (array) $authors as $author ) {
487
+ $author = get_userdata( $author->ID );
488
+ $posts = (isset($author_count[$author->ID])) ? $author_count[$author->ID] : 0;
489
+ $name = $author->display_name;
490
+
491
+ if ( $show_fullname && ($author->first_name != '' && $author->last_name != '') )
492
+ $name = "$author->first_name $author->last_name";
493
+
494
+ if ( !($posts == 0 && $hide_empty) )
495
+ $return .= '<li>';
496
+ if ( $posts == 0 ) {
497
+ if ( !$hide_empty )
498
+ $link = $name;
499
+ } else {
500
+ $link = '<a href="' . get_author_posts_url($author->ID, $author->user_nicename) . '" title="' . sprintf(__("Posts by %s"), attribute_escape($author->display_name)) . '">' . $name . '</a>';
501
+
502
+ if ( (! empty($feed_image)) || (! empty($feed)) ) {
503
+ $link .= ' ';
504
+ if (empty($feed_image))
505
+ $link .= '(';
506
+ $link .= '<a href="' . get_author_rss_link(0, $author->ID, $author->user_nicename) . '"';
507
+
508
+ if ( !empty($feed) ) {
509
+ $title = ' title="' . $feed . '"';
510
+ $alt = ' alt="' . $feed . '"';
511
+ $name = $feed;
512
+ $link .= $title;
513
+ }
514
+
515
+ $link .= '>';
516
+
517
+ if ( !empty($feed_image) )
518
+ $link .= "<img src=\"$feed_image\" border=\"0\"$alt$title" . ' />';
519
+ else
520
+ $link .= $name;
521
+
522
+ $link .= '</a>';
523
+
524
+ if ( empty($feed_image) )
525
+ $link .= ')';
526
+ }
527
+
528
+ if ( $optioncount )
529
+ $link .= ' ('. $posts . ')';
530
+
531
+ }
532
+
533
+ if ( !($posts == 0 && $hide_empty) )
534
+ $return .= $link . '</li>';
535
+ }
536
+ if ( !$echo )
537
+ return $return;
538
+ echo $return;
539
+ }
540
+
541
+
542
+
543
+ add_action('admin_print_scripts', 'coauthor_js_admin_header' );
544
+
545
+ function coauthor_js_admin_header() {
546
+ //use JavaScript SACK library for Ajax
547
+ //wp_print_scripts( array( 'sack' ));
548
+
549
+ // Add suggest.js plugin
550
+ wp_enqueue_script( 'suggest' );
551
+
552
+ // Define custom JavaScript function
553
+ ?>
554
+ <script type="text/javascript">
555
+ //<![CDATA[
556
+ var coauthor_ajax_suggest_link = '<?php bloginfo( 'wpurl' ); ?>/wp-content/plugins/co-authors-plus/suggest.php';
557
+ //]]>
558
+ </script>
559
+ <?php
560
+ } // end of PHP function coauthor_js_admin_header
561
+
562
+ ?>
license.txt ADDED
@@ -0,0 +1,674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ them if you wish), that you receive source code or can get it if you
26
+ want it, that you can change the software or use pieces of it in new
27
+ free programs, and that you know you can do these things.
28
+
29
+ To protect your rights, we need to prevent others from denying you
30
+ these rights or asking you to surrender the rights. Therefore, you have
31
+ certain responsibilities if you distribute copies of the software, or if
32
+ you modify it: responsibilities to respect the freedom of others.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must pass on to the recipients the same
36
+ freedoms that you received. You must make sure that they, too, receive
37
+ or can get the source code. And you must show them these terms so they
38
+ know their rights.
39
+
40
+ Developers that use the GNU GPL protect your rights with two steps:
41
+ (1) assert copyright on the software, and (2) offer you this License
42
+ giving you legal permission to copy, distribute and/or modify it.
43
+
44
+ For the developers' and authors' protection, the GPL clearly explains
45
+ that there is no warranty for this free software. For both users' and
46
+ authors' sake, the GPL requires that modified versions be marked as
47
+ changed, so that their problems will not be attributed erroneously to
48
+ authors of previous versions.
49
+
50
+ Some devices are designed to deny users access to install or run
51
+ modified versions of the software inside them, although the manufacturer
52
+ can do so. This is fundamentally incompatible with the aim of
53
+ protecting users' freedom to change the software. The systematic
54
+ pattern of such abuse occurs in the area of products for individuals to
55
+ use, which is precisely where it is most unacceptable. Therefore, we
56
+ have designed this version of the GPL to prohibit the practice for those
57
+ products. If such problems arise substantially in other domains, we
58
+ stand ready to extend this provision to those domains in future versions
59
+ of the GPL, as needed to protect the freedom of users.
60
+
61
+ Finally, every program is threatened constantly by software patents.
62
+ States should not allow patents to restrict development and use of
63
+ software on general-purpose computers, but in those that do, we wish to
64
+ avoid the special danger that patents applied to a free program could
65
+ make it effectively proprietary. To prevent this, the GPL assures that
66
+ patents cannot be used to render the program non-free.
67
+
68
+ The precise terms and conditions for copying, distribution and
69
+ modification follow.
70
+
71
+ TERMS AND CONDITIONS
72
+
73
+ 0. Definitions.
74
+
75
+ "This License" refers to version 3 of the GNU General Public License.
76
+
77
+ "Copyright" also means copyright-like laws that apply to other kinds of
78
+ works, such as semiconductor masks.
79
+
80
+ "The Program" refers to any copyrightable work licensed under this
81
+ License. Each licensee is addressed as "you". "Licensees" and
82
+ "recipients" may be individuals or organizations.
83
+
84
+ To "modify" a work means to copy from or adapt all or part of the work
85
+ in a fashion requiring copyright permission, other than the making of an
86
+ exact copy. The resulting work is called a "modified version" of the
87
+ earlier work or a work "based on" the earlier work.
88
+
89
+ A "covered work" means either the unmodified Program or a work based
90
+ on the Program.
91
+
92
+ To "propagate" a work means to do anything with it that, without
93
+ permission, would make you directly or secondarily liable for
94
+ infringement under applicable copyright law, except executing it on a
95
+ computer or modifying a private copy. Propagation includes copying,
96
+ distribution (with or without modification), making available to the
97
+ public, and in some countries other activities as well.
98
+
99
+ To "convey" a work means any kind of propagation that enables other
100
+ parties to make or receive copies. Mere interaction with a user through
101
+ a computer network, with no transfer of a copy, is not conveying.
102
+
103
+ An interactive user interface displays "Appropriate Legal Notices"
104
+ to the extent that it includes a convenient and prominently visible
105
+ feature that (1) displays an appropriate copyright notice, and (2)
106
+ tells the user that there is no warranty for the work (except to the
107
+ extent that warranties are provided), that licensees may convey the
108
+ work under this License, and how to view a copy of this License. If
109
+ the interface presents a list of user commands or options, such as a
110
+ menu, a prominent item in the list meets this criterion.
111
+
112
+ 1. Source Code.
113
+
114
+ The "source code" for a work means the preferred form of the work
115
+ for making modifications to it. "Object code" means any non-source
116
+ form of a work.
117
+
118
+ A "Standard Interface" means an interface that either is an official
119
+ standard defined by a recognized standards body, or, in the case of
120
+ interfaces specified for a particular programming language, one that
121
+ is widely used among developers working in that language.
122
+
123
+ The "System Libraries" of an executable work include anything, other
124
+ than the work as a whole, that (a) is included in the normal form of
125
+ packaging a Major Component, but which is not part of that Major
126
+ Component, and (b) serves only to enable use of the work with that
127
+ Major Component, or to implement a Standard Interface for which an
128
+ implementation is available to the public in source code form. A
129
+ "Major Component", in this context, means a major essential component
130
+ (kernel, window system, and so on) of the specific operating system
131
+ (if any) on which the executable work runs, or a compiler used to
132
+ produce the work, or an object code interpreter used to run it.
133
+
134
+ The "Corresponding Source" for a work in object code form means all
135
+ the source code needed to generate, install, and (for an executable
136
+ work) run the object code and to modify the work, including scripts to
137
+ control those activities. However, it does not include the work's
138
+ System Libraries, or general-purpose tools or generally available free
139
+ programs which are used unmodified in performing those activities but
140
+ which are not part of the work. For example, Corresponding Source
141
+ includes interface definition files associated with source files for
142
+ the work, and the source code for shared libraries and dynamically
143
+ linked subprograms that the work is specifically designed to require,
144
+ such as by intimate data communication or control flow between those
145
+ subprograms and other parts of the work.
146
+
147
+ The Corresponding Source need not include anything that users
148
+ can regenerate automatically from other parts of the Corresponding
149
+ Source.
150
+
151
+ The Corresponding Source for a work in source code form is that
152
+ same work.
153
+
154
+ 2. Basic Permissions.
155
+
156
+ All rights granted under this License are granted for the term of
157
+ copyright on the Program, and are irrevocable provided the stated
158
+ conditions are met. This License explicitly affirms your unlimited
159
+ permission to run the unmodified Program. The output from running a
160
+ covered work is covered by this License only if the output, given its
161
+ content, constitutes a covered work. This License acknowledges your
162
+ rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+ You may make, run and propagate covered works that you do not
165
+ convey, without conditions so long as your license otherwise remains
166
+ in force. You may convey covered works to others for the sole purpose
167
+ of having them make modifications exclusively for you, or provide you
168
+ with facilities for running those works, provided that you comply with
169
+ the terms of this License in conveying all material for which you do
170
+ not control copyright. Those thus making or running the covered works
171
+ for you must do so exclusively on your behalf, under your direction
172
+ and control, on terms that prohibit them from making any copies of
173
+ your copyrighted material outside their relationship with you.
174
+
175
+ Conveying under any other circumstances is permitted solely under
176
+ the conditions stated below. Sublicensing is not allowed; section 10
177
+ makes it unnecessary.
178
+
179
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+ No covered work shall be deemed part of an effective technological
182
+ measure under any applicable law fulfilling obligations under article
183
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+ similar laws prohibiting or restricting circumvention of such
185
+ measures.
186
+
187
+ When you convey a covered work, you waive any legal power to forbid
188
+ circumvention of technological measures to the extent such circumvention
189
+ is effected by exercising rights under this License with respect to
190
+ the covered work, and you disclaim any intention to limit operation or
191
+ modification of the work as a means of enforcing, against the work's
192
+ users, your or third parties' legal rights to forbid circumvention of
193
+ technological measures.
194
+
195
+ 4. Conveying Verbatim Copies.
196
+
197
+ You may convey verbatim copies of the Program's source code as you
198
+ receive it, in any medium, provided that you conspicuously and
199
+ appropriately publish on each copy an appropriate copyright notice;
200
+ keep intact all notices stating that this License and any
201
+ non-permissive terms added in accord with section 7 apply to the code;
202
+ keep intact all notices of the absence of any warranty; and give all
203
+ recipients a copy of this License along with the Program.
204
+
205
+ You may charge any price or no price for each copy that you convey,
206
+ and you may offer support or warranty protection for a fee.
207
+
208
+ 5. Conveying Modified Source Versions.
209
+
210
+ You may convey a work based on the Program, or the modifications to
211
+ produce it from the Program, in the form of source code under the
212
+ terms of section 4, provided that you also meet all of these conditions:
213
+
214
+ a) The work must carry prominent notices stating that you modified
215
+ it, and giving a relevant date.
216
+
217
+ b) The work must carry prominent notices stating that it is
218
+ released under this License and any conditions added under section
219
+ 7. This requirement modifies the requirement in section 4 to
220
+ "keep intact all notices".
221
+
222
+ c) You must license the entire work, as a whole, under this
223
+ License to anyone who comes into possession of a copy. This
224
+ License will therefore apply, along with any applicable section 7
225
+ additional terms, to the whole of the work, and all its parts,
226
+ regardless of how they are packaged. This License gives no
227
+ permission to license the work in any other way, but it does not
228
+ invalidate such permission if you have separately received it.
229
+
230
+ d) If the work has interactive user interfaces, each must display
231
+ Appropriate Legal Notices; however, if the Program has interactive
232
+ interfaces that do not display Appropriate Legal Notices, your
233
+ work need not make them do so.
234
+
235
+ A compilation of a covered work with other separate and independent
236
+ works, which are not by their nature extensions of the covered work,
237
+ and which are not combined with it such as to form a larger program,
238
+ in or on a volume of a storage or distribution medium, is called an
239
+ "aggregate" if the compilation and its resulting copyright are not
240
+ used to limit the access or legal rights of the compilation's users
241
+ beyond what the individual works permit. Inclusion of a covered work
242
+ in an aggregate does not cause this License to apply to the other
243
+ parts of the aggregate.
244
+
245
+ 6. Conveying Non-Source Forms.
246
+
247
+ You may convey a covered work in object code form under the terms
248
+ of sections 4 and 5, provided that you also convey the
249
+ machine-readable Corresponding Source under the terms of this License,
250
+ in one of these ways:
251
+
252
+ a) Convey the object code in, or embodied in, a physical product
253
+ (including a physical distribution medium), accompanied by the
254
+ Corresponding Source fixed on a durable physical medium
255
+ customarily used for software interchange.
256
+
257
+ b) Convey the object code in, or embodied in, a physical product
258
+ (including a physical distribution medium), accompanied by a
259
+ written offer, valid for at least three years and valid for as
260
+ long as you offer spare parts or customer support for that product
261
+ model, to give anyone who possesses the object code either (1) a
262
+ copy of the Corresponding Source for all the software in the
263
+ product that is covered by this License, on a durable physical
264
+ medium customarily used for software interchange, for a price no
265
+ more than your reasonable cost of physically performing this
266
+ conveying of source, or (2) access to copy the
267
+ Corresponding Source from a network server at no charge.
268
+
269
+ c) Convey individual copies of the object code with a copy of the
270
+ written offer to provide the Corresponding Source. This
271
+ alternative is allowed only occasionally and noncommercially, and
272
+ only if you received the object code with such an offer, in accord
273
+ with subsection 6b.
274
+
275
+ d) Convey the object code by offering access from a designated
276
+ place (gratis or for a charge), and offer equivalent access to the
277
+ Corresponding Source in the same way through the same place at no
278
+ further charge. You need not require recipients to copy the
279
+ Corresponding Source along with the object code. If the place to
280
+ copy the object code is a network server, the Corresponding Source
281
+ may be on a different server (operated by you or a third party)
282
+ that supports equivalent copying facilities, provided you maintain
283
+ clear directions next to the object code saying where to find the
284
+ Corresponding Source. Regardless of what server hosts the
285
+ Corresponding Source, you remain obligated to ensure that it is
286
+ available for as long as needed to satisfy these requirements.
287
+
288
+ e) Convey the object code using peer-to-peer transmission, provided
289
+ you inform other peers where the object code and Corresponding
290
+ Source of the work are being offered to the general public at no
291
+ charge under subsection 6d.
292
+
293
+ A separable portion of the object code, whose source code is excluded
294
+ from the Corresponding Source as a System Library, need not be
295
+ included in conveying the object code work.
296
+
297
+ A "User Product" is either (1) a "consumer product", which means any
298
+ tangible personal property which is normally used for personal, family,
299
+ or household purposes, or (2) anything designed or sold for incorporation
300
+ into a dwelling. In determining whether a product is a consumer product,
301
+ doubtful cases shall be resolved in favor of coverage. For a particular
302
+ product received by a particular user, "normally used" refers to a
303
+ typical or common use of that class of product, regardless of the status
304
+ of the particular user or of the way in which the particular user
305
+ actually uses, or expects or is expected to use, the product. A product
306
+ is a consumer product regardless of whether the product has substantial
307
+ commercial, industrial or non-consumer uses, unless such uses represent
308
+ the only significant mode of use of the product.
309
+
310
+ "Installation Information" for a User Product means any methods,
311
+ procedures, authorization keys, or other information required to install
312
+ and execute modified versions of a covered work in that User Product from
313
+ a modified version of its Corresponding Source. The information must
314
+ suffice to ensure that the continued functioning of the modified object
315
+ code is in no case prevented or interfered with solely because
316
+ modification has been made.
317
+
318
+ If you convey an object code work under this section in, or with, or
319
+ specifically for use in, a User Product, and the conveying occurs as
320
+ part of a transaction in which the right of possession and use of the
321
+ User Product is transferred to the recipient in perpetuity or for a
322
+ fixed term (regardless of how the transaction is characterized), the
323
+ Corresponding Source conveyed under this section must be accompanied
324
+ by the Installation Information. But this requirement does not apply
325
+ if neither you nor any third party retains the ability to install
326
+ modified object code on the User Product (for example, the work has
327
+ been installed in ROM).
328
+
329
+ The requirement to provide Installation Information does not include a
330
+ requirement to continue to provide support service, warranty, or updates
331
+ for a work that has been modified or installed by the recipient, or for
332
+ the User Product in which it has been modified or installed. Access to a
333
+ network may be denied when the modification itself materially and
334
+ adversely affects the operation of the network or violates the rules and
335
+ protocols for communication across the network.
336
+
337
+ Corresponding Source conveyed, and Installation Information provided,
338
+ in accord with this section must be in a format that is publicly
339
+ documented (and with an implementation available to the public in
340
+ source code form), and must require no special password or key for
341
+ unpacking, reading or copying.
342
+
343
+ 7. Additional Terms.
344
+
345
+ "Additional permissions" are terms that supplement the terms of this
346
+ License by making exceptions from one or more of its conditions.
347
+ Additional permissions that are applicable to the entire Program shall
348
+ be treated as though they were included in this License, to the extent
349
+ that they are valid under applicable law. If additional permissions
350
+ apply only to part of the Program, that part may be used separately
351
+ under those permissions, but the entire Program remains governed by
352
+ this License without regard to the additional permissions.
353
+
354
+ When you convey a copy of a covered work, you may at your option
355
+ remove any additional permissions from that copy, or from any part of
356
+ it. (Additional permissions may be written to require their own
357
+ removal in certain cases when you modify the work.) You may place
358
+ additional permissions on material, added by you to a covered work,
359
+ for which you have or can give appropriate copyright permission.
360
+
361
+ Notwithstanding any other provision of this License, for material you
362
+ add to a covered work, you may (if authorized by the copyright holders of
363
+ that material) supplement the terms of this License with terms:
364
+
365
+ a) Disclaiming warranty or limiting liability differently from the
366
+ terms of sections 15 and 16 of this License; or
367
+
368
+ b) Requiring preservation of specified reasonable legal notices or
369
+ author attributions in that material or in the Appropriate Legal
370
+ Notices displayed by works containing it; or
371
+
372
+ c) Prohibiting misrepresentation of the origin of that material, or
373
+ requiring that modified versions of such material be marked in
374
+ reasonable ways as different from the original version; or
375
+
376
+ d) Limiting the use for publicity purposes of names of licensors or
377
+ authors of the material; or
378
+
379
+ e) Declining to grant rights under trademark law for use of some
380
+ trade names, trademarks, or service marks; or
381
+
382
+ f) Requiring indemnification of licensors and authors of that
383
+ material by anyone who conveys the material (or modified versions of
384
+ it) with contractual assumptions of liability to the recipient, for
385
+ any liability that these contractual assumptions directly impose on
386
+ those licensors and authors.
387
+
388
+ All other non-permissive additional terms are considered "further
389
+ restrictions" within the meaning of section 10. If the Program as you
390
+ received it, or any part of it, contains a notice stating that it is
391
+ governed by this License along with a term that is a further
392
+ restriction, you may remove that term. If a license document contains
393
+ a further restriction but permits relicensing or conveying under this
394
+ License, you may add to a covered work material governed by the terms
395
+ of that license document, provided that the further restriction does
396
+ not survive such relicensing or conveying.
397
+
398
+ If you add terms to a covered work in accord with this section, you
399
+ must place, in the relevant source files, a statement of the
400
+ additional terms that apply to those files, or a notice indicating
401
+ where to find the applicable terms.
402
+
403
+ Additional terms, permissive or non-permissive, may be stated in the
404
+ form of a separately written license, or stated as exceptions;
405
+ the above requirements apply either way.
406
+
407
+ 8. Termination.
408
+
409
+ You may not propagate or modify a covered work except as expressly
410
+ provided under this License. Any attempt otherwise to propagate or
411
+ modify it is void, and will automatically terminate your rights under
412
+ this License (including any patent licenses granted under the third
413
+ paragraph of section 11).
414
+
415
+ However, if you cease all violation of this License, then your
416
+ license from a particular copyright holder is reinstated (a)
417
+ provisionally, unless and until the copyright holder explicitly and
418
+ finally terminates your license, and (b) permanently, if the copyright
419
+ holder fails to notify you of the violation by some reasonable means
420
+ prior to 60 days after the cessation.
421
+
422
+ Moreover, your license from a particular copyright holder is
423
+ reinstated permanently if the copyright holder notifies you of the
424
+ violation by some reasonable means, this is the first time you have
425
+ received notice of violation of this License (for any work) from that
426
+ copyright holder, and you cure the violation prior to 30 days after
427
+ your receipt of the notice.
428
+
429
+ Termination of your rights under this section does not terminate the
430
+ licenses of parties who have received copies or rights from you under
431
+ this License. If your rights have been terminated and not permanently
432
+ reinstated, you do not qualify to receive new licenses for the same
433
+ material under section 10.
434
+
435
+ 9. Acceptance Not Required for Having Copies.
436
+
437
+ You are not required to accept this License in order to receive or
438
+ run a copy of the Program. Ancillary propagation of a covered work
439
+ occurring solely as a consequence of using peer-to-peer transmission
440
+ to receive a copy likewise does not require acceptance. However,
441
+ nothing other than this License grants you permission to propagate or
442
+ modify any covered work. These actions infringe copyright if you do
443
+ not accept this License. Therefore, by modifying or propagating a
444
+ covered work, you indicate your acceptance of this License to do so.
445
+
446
+ 10. Automatic Licensing of Downstream Recipients.
447
+
448
+ Each time you convey a covered work, the recipient automatically
449
+ receives a license from the original licensors, to run, modify and
450
+ propagate that work, subject to this License. You are not responsible
451
+ for enforcing compliance by third parties with this License.
452
+
453
+ An "entity transaction" is a transaction transferring control of an
454
+ organization, or substantially all assets of one, or subdividing an
455
+ organization, or merging organizations. If propagation of a covered
456
+ work results from an entity transaction, each party to that
457
+ transaction who receives a copy of the work also receives whatever
458
+ licenses to the work the party's predecessor in interest had or could
459
+ give under the previous paragraph, plus a right to possession of the
460
+ Corresponding Source of the work from the predecessor in interest, if
461
+ the predecessor has it or can get it with reasonable efforts.
462
+
463
+ You may not impose any further restrictions on the exercise of the
464
+ rights granted or affirmed under this License. For example, you may
465
+ not impose a license fee, royalty, or other charge for exercise of
466
+ rights granted under this License, and you may not initiate litigation
467
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
468
+ any patent claim is infringed by making, using, selling, offering for
469
+ sale, or importing the Program or any portion of it.
470
+
471
+ 11. Patents.
472
+
473
+ A "contributor" is a copyright holder who authorizes use under this
474
+ License of the Program or a work on which the Program is based. The
475
+ work thus licensed is called the contributor's "contributor version".
476
+
477
+ A contributor's "essential patent claims" are all patent claims
478
+ owned or controlled by the contributor, whether already acquired or
479
+ hereafter acquired, that would be infringed by some manner, permitted
480
+ by this License, of making, using, or selling its contributor version,
481
+ but do not include claims that would be infringed only as a
482
+ consequence of further modification of the contributor version. For
483
+ purposes of this definition, "control" includes the right to grant
484
+ patent sublicenses in a manner consistent with the requirements of
485
+ this License.
486
+
487
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+ patent license under the contributor's essential patent claims, to
489
+ make, use, sell, offer for sale, import and otherwise run, modify and
490
+ propagate the contents of its contributor version.
491
+
492
+ In the following three paragraphs, a "patent license" is any express
493
+ agreement or commitment, however denominated, not to enforce a patent
494
+ (such as an express permission to practice a patent or covenant not to
495
+ sue for patent infringement). To "grant" such a patent license to a
496
+ party means to make such an agreement or commitment not to enforce a
497
+ patent against the party.
498
+
499
+ If you convey a covered work, knowingly relying on a patent license,
500
+ and the Corresponding Source of the work is not available for anyone
501
+ to copy, free of charge and under the terms of this License, through a
502
+ publicly available network server or other readily accessible means,
503
+ then you must either (1) cause the Corresponding Source to be so
504
+ available, or (2) arrange to deprive yourself of the benefit of the
505
+ patent license for this particular work, or (3) arrange, in a manner
506
+ consistent with the requirements of this License, to extend the patent
507
+ license to downstream recipients. "Knowingly relying" means you have
508
+ actual knowledge that, but for the patent license, your conveying the
509
+ covered work in a country, or your recipient's use of the covered work
510
+ in a country, would infringe one or more identifiable patents in that
511
+ country that you have reason to believe are valid.
512
+
513
+ If, pursuant to or in connection with a single transaction or
514
+ arrangement, you convey, or propagate by procuring conveyance of, a
515
+ covered work, and grant a patent license to some of the parties
516
+ receiving the covered work authorizing them to use, propagate, modify
517
+ or convey a specific copy of the covered work, then the patent license
518
+ you grant is automatically extended to all recipients of the covered
519
+ work and works based on it.
520
+
521
+ A patent license is "discriminatory" if it does not include within
522
+ the scope of its coverage, prohibits the exercise of, or is
523
+ conditioned on the non-exercise of one or more of the rights that are
524
+ specifically granted under this License. You may not convey a covered
525
+ work if you are a party to an arrangement with a third party that is
526
+ in the business of distributing software, under which you make payment
527
+ to the third party based on the extent of your activity of conveying
528
+ the work, and under which the third party grants, to any of the
529
+ parties who would receive the covered work from you, a discriminatory
530
+ patent license (a) in connection with copies of the covered work
531
+ conveyed by you (or copies made from those copies), or (b) primarily
532
+ for and in connection with specific products or compilations that
533
+ contain the covered work, unless you entered into that arrangement,
534
+ or that patent license was granted, prior to 28 March 2007.
535
+
536
+ Nothing in this License shall be construed as excluding or limiting
537
+ any implied license or other defenses to infringement that may
538
+ otherwise be available to you under applicable patent law.
539
+
540
+ 12. No Surrender of Others' Freedom.
541
+
542
+ If conditions are imposed on you (whether by court order, agreement or
543
+ otherwise) that contradict the conditions of this License, they do not
544
+ excuse you from the conditions of this License. If you cannot convey a
545
+ covered work so as to satisfy simultaneously your obligations under this
546
+ License and any other pertinent obligations, then as a consequence you may
547
+ not convey it at all. For example, if you agree to terms that obligate you
548
+ to collect a royalty for further conveying from those to whom you convey
549
+ the Program, the only way you could satisfy both those terms and this
550
+ License would be to refrain entirely from conveying the Program.
551
+
552
+ 13. Use with the GNU Affero General Public License.
553
+
554
+ Notwithstanding any other provision of this License, you have
555
+ permission to link or combine any covered work with a work licensed
556
+ under version 3 of the GNU Affero General Public License into a single
557
+ combined work, and to convey the resulting work. The terms of this
558
+ License will continue to apply to the part which is the covered work,
559
+ but the special requirements of the GNU Affero General Public License,
560
+ section 13, concerning interaction through a network will apply to the
561
+ combination as such.
562
+
563
+ 14. Revised Versions of this License.
564
+
565
+ The Free Software Foundation may publish revised and/or new versions of
566
+ the GNU General Public License from time to time. Such new versions will
567
+ be similar in spirit to the present version, but may differ in detail to
568
+ address new problems or concerns.
569
+
570
+ Each version is given a distinguishing version number. If the
571
+ Program specifies that a certain numbered version of the GNU General
572
+ Public License "or any later version" applies to it, you have the
573
+ option of following the terms and conditions either of that numbered
574
+ version or of any later version published by the Free Software
575
+ Foundation. If the Program does not specify a version number of the
576
+ GNU General Public License, you may choose any version ever published
577
+ by the Free Software Foundation.
578
+
579
+ If the Program specifies that a proxy can decide which future
580
+ versions of the GNU General Public License can be used, that proxy's
581
+ public statement of acceptance of a version permanently authorizes you
582
+ to choose that version for the Program.
583
+
584
+ Later license versions may give you additional or different
585
+ permissions. However, no additional obligations are imposed on any
586
+ author or copyright holder as a result of your choosing to follow a
587
+ later version.
588
+
589
+ 15. Disclaimer of Warranty.
590
+
591
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+ 16. Limitation of Liability.
601
+
602
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+ SUCH DAMAGES.
611
+
612
+ 17. Interpretation of Sections 15 and 16.
613
+
614
+ If the disclaimer of warranty and limitation of liability provided
615
+ above cannot be given local legal effect according to their terms,
616
+ reviewing courts shall apply local law that most closely approximates
617
+ an absolute waiver of all civil liability in connection with the
618
+ Program, unless a warranty or assumption of liability accompanies a
619
+ copy of the Program in return for a fee.
620
+
621
+ END OF TERMS AND CONDITIONS
622
+
623
+ How to Apply These Terms to Your New Programs
624
+
625
+ If you develop a new program, and you want it to be of the greatest
626
+ possible use to the public, the best way to achieve this is to make it
627
+ free software which everyone can redistribute and change under these terms.
628
+
629
+ To do so, attach the following notices to the program. It is safest
630
+ to attach them to the start of each source file to most effectively
631
+ state the exclusion of warranty; and each file should have at least
632
+ the "copyright" line and a pointer to where the full notice is found.
633
+
634
+ <one line to give the program's name and a brief idea of what it does.>
635
+ Copyright (C) <year> <name of author>
636
+
637
+ This program is free software: you can redistribute it and/or modify
638
+ it under the terms of the GNU General Public License as published by
639
+ the Free Software Foundation, either version 3 of the License, or
640
+ (at your option) any later version.
641
+
642
+ This program is distributed in the hope that it will be useful,
643
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
644
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645
+ GNU General Public License for more details.
646
+
647
+ You should have received a copy of the GNU General Public License
648
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
649
+
650
+ Also add information on how to contact you by electronic and paper mail.
651
+
652
+ If the program does terminal interaction, make it output a short
653
+ notice like this when it starts in an interactive mode:
654
+
655
+ <program> Copyright (C) <year> <name of author>
656
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
+ This is free software, and you are welcome to redistribute it
658
+ under certain conditions; type `show c' for details.
659
+
660
+ The hypothetical commands `show w' and `show c' should show the appropriate
661
+ parts of the General Public License. Of course, your program's commands
662
+ might be different; for a GUI interface, you would use an "about box".
663
+
664
+ You should also get your employer (if you work as a programmer) or school,
665
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
666
+ For more information on this, and how to apply and follow the GNU GPL, see
667
+ <http://www.gnu.org/licenses/>.
668
+
669
+ The GNU General Public License does not permit incorporating your program
670
+ into proprietary programs. If your program is a subroutine library, you
671
+ may consider it more useful to permit linking proprietary applications with
672
+ the library. If this is what you want to do, use the GNU Lesser General
673
+ Public License instead of this License. But first, please read
674
+ <http://www.gnu.org/philosophy/why-not-lgpl.html>.
readme.txt ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Co-Authors ===
2
+ Contributors: batmoo
3
+ Donate link: http://digitalize.ca/donate
4
+ Tags: authors, users
5
+ Tested up to: 2.7.1
6
+ Requires at least: 2.6
7
+ Stable tag: 1.1.3
8
+
9
+ Allows multiple authors to be assigned to a Post or Page. Co-authored posts appear on a co-author's posts page and feed.
10
+
11
+ == Description ==
12
+
13
+ Allows multiple authors to be assigned to a Post or Page. Co-authored posts appear on a co-author's posts page and feed. New template tags allow listing of co-authors. Editors may assign co-authors to a post via the search-as-you-type inputs in the 'Post Author(s)' box. Additionally, co-authors may edit the posts they are associated with, and co-authors who are contributors may only edit posts if they have not been published (as is usual). Co-authored posts appear on a co-author's posts page and feed.
14
+
15
+ This plugin is an extended version of the Co-Authors plugin originally developed at [Shepherd Interactive](http://www.shepherd-interactive.com/ "Shepherd Interactive specializes in web design and development in Portland, Oregon") (2007). Their plugin was inspired by 'Multiple Authors' plugin by Mark Jaquith (2005).
16
+
17
+ The extended version is created by Mohammad Jangda, and incorporates search-as-you-type functionality for adding users, which aims to make easy the task of adding multiple users to posts and pages, especially when dealing with a system with hundreds of users (typical of newspaper and magazine sites).
18
+
19
+ New template tags enable listing of co-authors:
20
+
21
+ * <code>coauthors()</code>
22
+ * <code>coauthors_posts_links()</code>
23
+ * <code>coauthors_firstnames()</code>
24
+ * <code>coauthors_lastnames()</code>
25
+ * <code>coauthors_nicknames()</code>
26
+ * <code>coauthors_links()</code>
27
+ * <code>coauthors_IDs()</code>
28
+
29
+ These template tags correspond to their "<code>the_author*</code>" equivalents; take special note of the pluralization.
30
+ Each of these template tags accept four optional arguments:
31
+
32
+ 1. <code>between</code>: default ", "
33
+ 1. <code>betweenLast</code>: default " and "
34
+ 1. <code>before</code>: default ""
35
+ 1. <code>after</code>: default ""
36
+
37
+ To use them, simply modify the code surrounding all instances of <code>the_author*()</code> to something like as follows:
38
+
39
+ if(function_exists('coauthors_posts_links'))
40
+ coauthors_posts_links();
41
+ else
42
+ the_author_posts_link();
43
+
44
+ The result of this would be formatted like "John Smith, Jane Doe and Joe Public".
45
+
46
+ Note that as of this writing, WordPress does provide a means of extending <code>wp_list_authors()</code>, so
47
+ included in this plugin is the function <code>coauthors_wp_list_authors()</code> modified
48
+ to take into account co-authored posts; the same arguments are accepted.
49
+
50
+ Sometimes you may need fine-graned control over the display of a posts's authors, and in this case you may use
51
+ the <code>CoAuthorsIterator</code> class. This class may be instantiated anywhere you may place <code>the_author()</code>
52
+ or everywhere if the post ID is provided to the constructor. The instantiated class has the following methods:
53
+
54
+ 1. <code>iterate()</code>: advances <code>$authordata</code> to the next co-author; returns <code>false</code> and restores the original <code>$authordata</code> if there are no more authors to iterate.
55
+ 1. <code>get_position()</code>: returns the zero-based index of the current author; returns -1 if the iterator is invalid
56
+ 1. <code>is_last()</code>: returns <code>true</code> if the current author is the last
57
+ 1. <code>is_first()</code>: returns <code>true</code> if the current author is the first
58
+ 1. <code>count()</code>: returns the total number of authors
59
+ 1. <code>get_all()</code>: returns an array of all of the authors' user data
60
+
61
+ For example:
62
+
63
+ $i = new CoAuthorsIterator();
64
+ print $i->count() == 1 ? 'Author: ' : 'Authors: ';
65
+ $i->iterate();
66
+ the_author();
67
+ while($i->iterate()){
68
+ print $i->is_last() ? ' and ' : ', ';
69
+ the_author();
70
+ }
71
+
72
+
73
+ = Changelog =
74
+
75
+ *2009-04-23 / 1.1.3*
76
+
77
+ * Add blur event to disable input box
78
+ * Limit only one edit at a time.
79
+ * Checked basic cross-browser compatibility (Firefox 3 OS X, Safari 3 OS X, IE7 Vista).
80
+ * Add suggest javascript plugin to Edit Page.
81
+
82
+ *2009-04-19 / 1.1.2*
83
+
84
+ * Disabled form submit when enter pressed.
85
+
86
+ *2009-04-15 / 1.1.1*
87
+
88
+ * Changed SQL query to return only contributer-level and above users.
89
+
90
+ *2009-04-14: 1.1.0*
91
+
92
+ * Initial release.
93
+
94
+
95
+ == Installation ==
96
+
97
+ 1. Extract the coauthors-plus.zip file and upload its contents to the `/wp-content/plugins/` directory. Alternatively you can install directly from the Plugin directory within your WordPress Install.
98
+ 1. Activate the plugin through the 'Plugins' menu in WordPress.
99
+ 1. Place the appropriate coauthors template tags in your template.
100
+ 1. Add coauthors to your posts and pages.
101
+
102
+
103
+ == Frequently Asked Questions ==
104
+
105
+ = When will the "New Author" function be added? =
106
+
107
+ Hopefully soon.
108
+
109
+ = What happens to posts and pages when I delete a user assigned to a post or page as a coauthor? =
110
+
111
+ When a user is deleted from WordPress, they will be removed from all of posts for which they are co-authors, and if a replacement user is provided, their co-authored posts will instead be co-attributed to another user.
112
+
113
+ == Screenshots ==
114
+ 1. "Post Author(s)" box with multiple authors added
115
+ 2. Search-as-you-type input box that looks up authors as you type in their name.
screenshot-1.png ADDED
Binary file
screenshot-2.png ADDED
Binary file
suggest.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Bootstrap file for getting the ABSPATH constant to wp-load.php
4
+ * This is requried when a plugin requires access not via the admin screen.
5
+ *
6
+ * If the wp-load.php file is not found, then an error will be displayed
7
+ *
8
+ * @package WordPress
9
+ * @since Version 2.6
10
+ */
11
+
12
+ /** Define the server path to the file wp-config here, if you placed WP-CONTENT outside the classic file structure */
13
+
14
+ $path = ''; // It should be end with a trailing slash
15
+
16
+ /** That's all, stop editing from here **/
17
+
18
+ if ( !defined('WP_LOAD_PATH') ) {
19
+
20
+ /** classic root path if wp-content and plugins is below wp-config.php */
21
+ $classic_root = dirname(dirname(dirname(dirname(__FILE__)))) . '/' ;
22
+
23
+ if (file_exists( $classic_root . 'wp-load.php') )
24
+ define( 'WP_LOAD_PATH', $classic_root);
25
+ else
26
+ if (file_exists( $path . 'wp-load.php') )
27
+ define( 'WP_LOAD_PATH', $path);
28
+ else
29
+ exit("Could not find wp-load.php");
30
+ }
31
+
32
+ // let's load WordPress
33
+ require_once( WP_LOAD_PATH . 'wp-load.php');
34
+
35
+ function coauthor_ajax_suggest() {
36
+
37
+ global $wpdb;
38
+
39
+ $q = '%'.strtolower($_REQUEST["q"]).'%';
40
+ if (!$q) return;
41
+
42
+ //
43
+ $authors_query = $wpdb->prepare("SELECT ID, display_name, user_email
44
+ FROM $wpdb->users
45
+ WHERE ID = ANY (SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'wp_user_level' AND meta_value >= 1)
46
+ AND (user_login LIKE %s
47
+ OR user_nicename LIKE %s
48
+ OR display_name LIKE %s
49
+ OR user_email LIKE %s)",$q,$q,$q,$q
50
+ );
51
+
52
+ // $query = "SELECT * FROM $wpdb->users WHERE ID = ANY (SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'wp_capabilities' AND meta_value RLIKE $this_role) ORDER BY user_nicename ASC LIMIT 10000";
53
+
54
+
55
+ $authors = $wpdb->get_results($authors_query, ARRAY_A);
56
+
57
+ if(is_array($authors)) {
58
+ foreach ($authors as $author) {
59
+
60
+ echo $author['ID']." | ". $author['display_name'] ." | ".$author['user_email'] ."\n";
61
+ }
62
+ }
63
+ echo "New | Add new author: ".trim($q,'%')."\n";
64
+ }
65
+
66
+ // Make sure that user is logged in; we don't want to enable direct access
67
+ get_currentuserinfo();
68
+ global $user_level;
69
+ if ($user_level >= 7) coauthor_ajax_suggest();
trunk/admin.css ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #coauthors-table {
2
+
3
+ }
4
+ div.dbx-content #coauthors-table {
5
+ width:100%;
6
+ }
7
+ #coauthors-table td {
8
+ padding-left:0;
9
+ padding-right:0;
10
+ vertical-align: middle;
11
+ background: #F9F9F9;
12
+ }
13
+ #coauthors-table td.select select {
14
+ margin-top:0;
15
+ }
16
+ div.dbx-content #coauthors-table td.select select {
17
+ width:100%;
18
+ }
19
+
20
+ span.author-tag {
21
+ display:block;
22
+ padding: 5px 3px;
23
+ color: #21759B;
24
+ border-bottom: 1px solid #21759B;
25
+ cursor: text;
26
+ }
27
+ span.author-tag:hover {
28
+ cursor: text;
29
+ background: #EAF2FA ;
30
+ color:#D54E21;
31
+ }
32
+ input.coauthor-suggest {
33
+ margin:5px 0;
34
+ color:#888;
35
+ }
36
+ input.coauthor-suggest:focus {
37
+ color: #333;
38
+ }
39
+
40
+ span.delete-coauthor {
41
+ padding: 3px;
42
+ text-decoration: underline;
43
+ color:#FF0000;
44
+ font-size:11px;
45
+ }
46
+ span.delete-coauthor:hover {
47
+ cursor: pointer;
48
+ background: #FF0000;
49
+ color: #fff;
50
+ }
trunk/admin.js ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ (function(){
3
+
4
+ var coauthors_table = null;
5
+
6
+ var coauthorsTable = jQuery('#coauthors-table');
7
+ var editing = false;
8
+
9
+ /*
10
+ * Get an author's name from their ID
11
+ * Iterates through the coauthors-select input box until finds the entry with the associated ID
12
+ *
13
+ */
14
+ function coauthors_get_author_name( authorID ) {
15
+ var select = jQuery('#coauthors-select');
16
+
17
+ if(authorID){
18
+ //Find the provided author ID
19
+ var name = "";
20
+ select.find("option").each(function(i){
21
+ if(this.value == authorID) {
22
+ name = this.innerHTML;
23
+ return;
24
+ }
25
+
26
+ });
27
+ return name;
28
+ }
29
+ return false;
30
+
31
+ }
32
+
33
+
34
+ function coauthors_select_author( authorID, selectID ) {
35
+ if(!selectID) selectID = '#coauthors-select';
36
+
37
+ var select = jQuery(selectID);
38
+
39
+ if(authorID){
40
+ //Find the provided author ID
41
+ select.find("option").each(function(i){
42
+ if(this.value == authorID) {
43
+ jQuery(this).attr('selected','true')
44
+ return false;
45
+ }
46
+ });
47
+ }
48
+
49
+ }
50
+
51
+ function coauthors_remove_author( authorName ) {
52
+ var select = jQuery('#coauthors-select');
53
+ if(authorName){
54
+ //Find the provided author ID
55
+ select.find("option").each(function(i){
56
+ if(this.innerHTML == authorName) {
57
+ jQuery(this).removeAttr('selected');
58
+ return true;
59
+ }
60
+ });
61
+ }
62
+ }
63
+
64
+ // Old function not needed; though may be useful for duplicate validation
65
+ var coauthors_select_onchange = function(event){
66
+
67
+ };
68
+
69
+ var coauthors_delete_onclick = function(event){
70
+
71
+ if(confirm('Are you sure you want to delete this author?')) {
72
+ var tr = jQuery(this).parent().parent();
73
+ var name = tr.find('span.author-tag').text();
74
+ coauthors_remove_author(name);
75
+ tr.remove();
76
+
77
+ return true;
78
+ }
79
+ return false;
80
+ };
81
+
82
+ function coauthors_insert_author_edit_cells(tr){
83
+
84
+ var deleteBtn = jQuery('<span></span>')
85
+ .addClass('delete-coauthor')
86
+ .text('Delete')
87
+ .bind('click', coauthors_delete_onclick)
88
+ ;
89
+
90
+ var td = jQuery('<td></td>')
91
+ .addClass('delete')
92
+ ;
93
+ td.append(deleteBtn);
94
+ jQuery(tr).append(td);
95
+ return tr;
96
+
97
+ }
98
+
99
+ function coauthors_save_coauthor(authorID, authorName, co) {
100
+
101
+ coauthors_remove_author(co.next().text());
102
+
103
+ // get sibling <span>, update, and hide
104
+ co.next().html(authorName)
105
+ .show()
106
+ ;
107
+
108
+ // select new author
109
+ if(co.attr('name')=='coauthors-main') {
110
+ coauthors_select_author( authorID, '#post_author_override' );
111
+ } else {
112
+ coauthors_select_author( authorID )
113
+ }
114
+
115
+ editing = false;
116
+ }
117
+
118
+
119
+
120
+ function coauthors_add_coauthor(authorID, authorName, co, init){
121
+ var selectedIndex = -1;
122
+
123
+ if(editing) {
124
+ coauthors_save_coauthor(authorID, authorName, co)
125
+
126
+ } else {
127
+
128
+ if(!co) var co = coauthors_create_autosuggest(authorName)
129
+ var tag = coauthors_create_author_tag(authorName);
130
+
131
+ coauthors_add_to_table(co, tag);
132
+
133
+ // Add new author to <select>
134
+ coauthors_select_author( authorID )
135
+
136
+ if(!init) {
137
+ // Create new author-suggest and append it to a new row
138
+ var newCO = coauthors_create_autosuggest('', false);
139
+ coauthors_add_to_table(newCO);
140
+ }
141
+ }
142
+
143
+ co.bind('blur', coauthors_stop_editing);
144
+
145
+ // Set the value for the auto-suggest box to the Author's name and hide it
146
+ co.val(authorName)
147
+ .hide()
148
+ .unbind('focus')
149
+ ;
150
+
151
+ return true;
152
+ }
153
+
154
+
155
+ function coauthors_add_to_table( co, tag, del ) {
156
+ if(co) {
157
+ var td = jQuery('<td></td>');
158
+ td.className = 'suggest';
159
+ td.append(co);
160
+ td.append(tag);
161
+ var tr = jQuery('<tr></tr>');
162
+ tr.append(td);
163
+
164
+ //Add buttons to row
165
+ if(tag && !del) coauthors_insert_author_edit_cells(tr);
166
+
167
+ jQuery('#coauthors-table').append(tr);
168
+ }
169
+ }
170
+
171
+ function coauthors_create_autosuggest(authorName, inputName) {
172
+
173
+ if(!inputName) inputName = 'coauthors2[]';
174
+
175
+ var co = jQuery('<input/>')
176
+ .attr({
177
+ 'class': 'coauthor-suggest',
178
+ 'name': inputName
179
+ })
180
+ .appendTo(div)
181
+
182
+ .suggest(coauthor_ajax_suggest_link,{
183
+ onSelect:
184
+ function() {
185
+
186
+ var vals = this.value.split("|");
187
+
188
+ var id = jQuery.trim(vals[0]);
189
+ var name = jQuery.trim(vals[1]);
190
+
191
+ if(id=="New") {
192
+ alert('Eventually, this will allow you to add a new author right from here. But it\'s not ready yet. *sigh*');
193
+ } else {
194
+ coauthors_add_coauthor(id, name, co);
195
+ }
196
+ }
197
+ })
198
+ .keydown(function(e) {
199
+ if(e.keyCode == 13) {return false;}
200
+
201
+ })
202
+ ;
203
+
204
+ if(authorName)
205
+ co.attr('value', authorName);
206
+ else
207
+ co.attr('value', 'Search for an author')
208
+ .focus(function(){co.val('')})
209
+ .blur(function(){co.val('Search for an author')})
210
+ ;
211
+
212
+ return co;
213
+
214
+ }
215
+
216
+ function coauthors_stop_editing(event) {
217
+ var co = jQuery(event.target);
218
+ var tag = jQuery(co.next());
219
+
220
+ co.attr('value',tag.text());
221
+
222
+ co.hide();
223
+ tag.show();
224
+ editing = false;
225
+ }
226
+
227
+ function coauthors_create_author_tag (name) {
228
+ var tag = jQuery('<span></span>')
229
+ .html(name)
230
+ .attr('title', 'Click to edit')
231
+ .addClass('author-tag')
232
+ // Add Click event to edit
233
+ .click(function(){
234
+ if(!editing) {
235
+ editing = true;
236
+
237
+ var co = tag.prev();
238
+
239
+ tag.hide();
240
+ co.show()
241
+ .focus()
242
+ ;
243
+
244
+ co.previousAuthor = tag.text();
245
+ }
246
+
247
+ });
248
+
249
+ return tag;
250
+ }
251
+
252
+
253
+ if(document.getElementById('post_author_override')){
254
+ if(!coauthors_can_edit_others_posts){
255
+ jQuery('#authordiv, #pageauthordiv').remove();
256
+ return;
257
+ }
258
+
259
+ //Note that there can be co-authors (changes dbx title from "Post Author" to "Post Author(s)")
260
+ var h3 = jQuery('#authordiv :header, #pageauthordiv :header').html(
261
+ /page[^\/]+$/.test(window.location.href) ?
262
+ coauthors_dbx_page_title
263
+ :
264
+ coauthors_dbx_post_title
265
+ );
266
+
267
+ //Add the controls to add co-authors
268
+ var div = jQuery('#authordiv div, #pageauthordiv div').filter(function(){
269
+ if(jQuery(this).is('.inside') || jQuery(this).is('.dbx-content'))
270
+ return true;
271
+ return false;
272
+ })[0];
273
+
274
+ if(div){
275
+
276
+ var table = jQuery('<table></table>')
277
+ .attr('id', 'coauthors-table')
278
+ ;
279
+
280
+ var coauthors_table = jQuery('<tbody></tbody>')
281
+ .appendTo(table)
282
+ ;
283
+
284
+ var tr = jQuery('<tr></tr>');
285
+ var td = jQuery('<td></td>')
286
+ .addClass('select')
287
+ ;
288
+
289
+ var select = jQuery('#post_author_override')[0];
290
+
291
+ td.append(select);
292
+ tr.append(td);
293
+ coauthors_table.append(tr);
294
+ jQuery(div).append(table);
295
+
296
+ // Create input and span for first entry
297
+ var nameFirst = select[select.selectedIndex].innerHTML;
298
+ var coFirst = coauthors_create_autosuggest(nameFirst, 'coauthors-main')
299
+ coFirst.hide();
300
+ var tagFirst = coauthors_create_author_tag(nameFirst);
301
+ jQuery(select).after(tagFirst)
302
+ .after(coFirst)
303
+ ;
304
+ // Add blur event to suggest box
305
+ coFirst.bind('blur', coauthors_stop_editing);
306
+
307
+ // Create coauthors select box by cloning it from the drop-down
308
+ var coauthors = jQuery('#post_author_override').clone(true)
309
+ .attr('id', 'coauthors-select')
310
+ .attr('name', 'coauthors[]')
311
+ .attr({'multiple':'multiple', 'size':5})
312
+ .attr('style','height:10em')
313
+ .attr('selectedIndex', '-1')
314
+ ;
315
+ coauthors.insertAfter('#post_author_override');
316
+
317
+ // Hide both select boxes
318
+ jQuery('#post_author_override').hide();
319
+ coauthors.hide();
320
+
321
+ var help = jQuery('<p></p>').text('Click on an author to edit. Click on "Delete" to remove them.');
322
+ jQuery('#authordiv .inside').append(help);
323
+
324
+ var presenceInput;
325
+ try {
326
+ //For MSIE
327
+ presenceInput = document.createElement('<input name="coauthors_plugin_is_active" type="hidden" value="1" />');
328
+ if(!presenceInput || presenceInput.name != 'coauthors_plugin_is_active')
329
+ throw Error();
330
+ } catch(e){
331
+ presenceInput = document.createElement('input');
332
+ presenceInput.name = "coauthors_plugin_is_active";
333
+ presenceInput.value = 1;
334
+ presenceInput.type = 'hidden';
335
+ }
336
+ div.appendChild(presenceInput);
337
+ }
338
+
339
+ // Select authors already added to the post
340
+ var addedAlready = {};
341
+ jQuery('#the-list tr').each(function(){
342
+ var userID = jQuery(this).find('textarea').val();
343
+ if(jQuery(this).find("input[@value='_coauthor']").length && !addedAlready[userID]){
344
+ var authorName = coauthors_get_author_name(userID);
345
+ if(authorName) coauthors_add_coauthor(userID, authorName, undefined, true );
346
+ addedAlready[userID] = true;
347
+ }
348
+ });
349
+
350
+ // Create new author-suggest and append it to a new row
351
+ var newCO = coauthors_create_autosuggest('', false);
352
+ coauthors_add_to_table(newCO);
353
+
354
+ }
355
+
356
+ })();
trunk/co-authors.php ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Co-Authors Plus
4
+ Plugin URI: http://wordpress.org/extend/plugins/co-authors-plus/
5
+ Description: Allows multiple authors to be assigned to a post. Co-authored posts appear on a co-author's posts page and feed. New template tags allow listing of co-authors. Editors may assign co-authors to a post via the 'Post Author' box. <em>This plugin is an extended version of the Co-Authors plugin originally developed at [Shepherd Interactive](http://www.shepherd-interactive.com/ "Shepherd Interactive specializes in web design and development in Portland, Oregon") (2007). Their plugin was inspired by 'Multiple Authors' plugin by Mark Jaquith (2005).</em>
6
+ Version: 1.1.3
7
+ Author: Mohammad Jangda
8
+ Author URI: http://digitalize.ca
9
+ Copyright: Some parts (C) 2009, Mohammad; Other parts (C) 2008, Weston Ruter, Shepherd Interactive
10
+
11
+ GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
12
+ This program is free software; you can redistribute it and/or modify
13
+ it under the terms of the GNU General Public License as published by
14
+ the Free Software Foundation; either version 2 of the License, or
15
+ (at your option) any later version.
16
+
17
+ This program is distributed in the hope that it will be useful,
18
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ GNU General Public License for more details.
21
+
22
+ You should have received a copy of the GNU General Public License
23
+ along with this program; if not, write to the Free Software
24
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
+
26
+
27
+ ## Change Log ##
28
+
29
+ *2009-04-23 / 1.1.3*
30
+
31
+ * Add blur event to disable input box
32
+ * Limit only one edit at a time.
33
+ * Check Cross-browser compatibility (Firefox 3 OS X, Safari 3 OS X, IE7 Vista).
34
+ * Add suggest javascript plugin to Edit Page.
35
+
36
+ *2009-04-19 / 1.1.2*
37
+
38
+ * Disabled form submit when enter pressed.
39
+
40
+ *2009-04-15 / 1.1.1*
41
+
42
+ * Changed SQL query to return only contributer-level and above users.
43
+
44
+ *2009-04-14: 1.1.0*
45
+
46
+ @@ To do @@
47
+ - Setting to enable/disable co-authors for Pages
48
+ - Check Cross-browser compatibility
49
+ - admin.js: need to check to ensure that an author added is not a duplicate
50
+ - Display all coauthors in table on "Edit Posts" page
51
+
52
+ */
53
+
54
+ define('COAUTHORS_DEFAULT_BEFORE', '');
55
+ define('COAUTHORS_DEFAULT_BETWEEN', ', ');
56
+ define('COAUTHORS_DEFAULT_BETWEEN_LAST', ' and ');
57
+ define('COAUTHORS_DEFAULT_AFTER', '');
58
+ define('COAUTHORS_VERSION', '1.1.2');
59
+
60
+ if(floatval(get_option('coauthors_version')) < 1.0)
61
+ coauthors_updatedb();
62
+
63
+ add_option('coauthors_version', COAUTHORS_VERSION);
64
+
65
+ function coauthors_updatedb(){
66
+ global $wpdb;
67
+ //Update old versions of plugin to use new hidden meta key
68
+ $wpdb->query("UPDATE $wpdb->postmeta SET meta_key = '_coauthor' WHERE meta_key = 'coauthor';");
69
+ }
70
+ register_activation_hook(__FILE__, 'coauthors_updatedb');
71
+
72
+ # Load up the localization file if we're using WordPress in a different language
73
+ # Place l10n files named like "co-authors-[value in wp-config].mo" in the "localization" folder
74
+ load_plugin_textdomain('co-authors', PLUGINDIR . '/co-authors-plus/localization');
75
+
76
+ function coauthors_user_has_cap($allcaps, $caps, $args){
77
+ $current_user = wp_get_current_user();
78
+
79
+ $relatedCaps = array(
80
+ 'edit_post',
81
+ 'edit_others_posts',
82
+ 'publish_posts',
83
+ 'edit_page',
84
+ 'edit_others_pages',
85
+ 'publish_pages',
86
+ 'edit_pages',
87
+ 'edit_posts',
88
+ 'edit_published_pages',
89
+ 'edit_published_posts',
90
+ //delete_post
91
+ //delete_page
92
+ //moderate_comments
93
+ );
94
+
95
+ foreach($caps as $cap){
96
+ if(!in_array($cap, $relatedCaps))
97
+ return $allcaps;
98
+ }
99
+
100
+ //Get the post in question
101
+ $postID = $args[2] ? $args[2] : $_POST['ID'];
102
+ $post = get_post($postID);
103
+ $post_status = $_POST['post_status'] ? $_POST['post_status'] : $post->post_status;
104
+
105
+ //Disallow if post is published and they are a contributor
106
+ if(!in_array($post_status, array('draft','pending')) && (($post->post_type == 'post' && !$allcaps['edit_published_posts']) || ($post->post_type == 'page' && !$allcaps['edit_published_pages']))){
107
+ return $allcaps;
108
+ }
109
+
110
+ $coauthors = get_post_custom_values('_coauthor', $postID);
111
+ if(!empty($coauthors) && in_array($current_user->ID, $coauthors)){
112
+ foreach($relatedCaps as $cap){
113
+ $allcaps[$cap] = true;
114
+ }
115
+ }
116
+
117
+ return $allcaps;
118
+ }
119
+ add_filter('user_has_cap', 'coauthors_user_has_cap', 10, 3);
120
+
121
+
122
+ //Modify the author query posts SQL to include posts co-authored
123
+ function coauthors_posts_join_filter($join){
124
+ global $wpdb,$wp_query;
125
+ if(is_author()){
126
+ $join .= " LEFT JOIN $wpdb->postmeta ON $wpdb->postmeta.post_id = $wpdb->posts.id "
127
+ . "AND $wpdb->postmeta.meta_key = '_coauthor' "
128
+ . "AND $wpdb->postmeta.meta_value = '" . $wp_query->query_vars['author'] . "' "; //this condition removes need for DISTINCT
129
+ }
130
+ return $join;
131
+ }
132
+ add_filter('posts_join', 'coauthors_posts_join_filter');
133
+ function coauthors_posts_where_filter($where){
134
+ global $wpdb;
135
+ if(is_author())
136
+ $where = preg_replace('/(\b(?:' . $wpdb->posts . '\.)?post_author\s*=\s*(\d+))/', '($1 OR (' . $wpdb->postmeta . '.meta_value = \'$2\'))', $where, 1); #' . $wpdb->postmeta . '.meta_id IS NOT NULL AND
137
+ return $where;
138
+ }
139
+ add_filter('posts_where', 'coauthors_posts_where_filter');
140
+
141
+ //function coauthors_posts_query_filter($sql){ //this was needed when meta_value = query_vars[author] was not tested in the LEFT JOIN ON clause
142
+ // return preg_replace("{^(\s*SELECT\b(?!\s*DISTINCT))}i", '$1 DISTINCT', $sql);
143
+ //}
144
+ //add_filter('posts_request', 'coauthors_posts_query_filter');
145
+
146
+
147
+ class CoAuthorsIterator {
148
+ var $position = -1;
149
+ var $original_authordata;
150
+ var $authordata_array;
151
+ var $count;
152
+
153
+ function CoAuthorsIterator($postID = 0){
154
+ global $post, $authordata, $wpdb;
155
+ $postID = (int)$postID;
156
+ if(!$postID && $post)
157
+ $postID = (int)$post->ID;
158
+ if(!$postID)
159
+ trigger_error(__('No post ID provided for CoAuthorsIterator constructor. Are you not in a loop or is $post not set?', 'co-authors')); //return null;
160
+ if(empty($authordata))
161
+ $authordata = get_userdata($wpdb->get_var("SELECT post_author FROM $wpdb->posts WHERE ID = $postID;"));
162
+
163
+ //Gather all of the co-authors
164
+ $this->authordata_array = array($authordata);
165
+ $userids = get_post_meta($post->ID, '_coauthor', false);
166
+ if(!empty($userids)){
167
+ if(!is_array($userids))
168
+ $userids = array($userids);
169
+ foreach($userids as $user_id){
170
+ $a = get_userdata($user_id);
171
+ if(!empty($a)) //in case the user has been deleted while plugin was deactivated
172
+ $this->authordata_array[] = $a;
173
+ }
174
+ }
175
+ $this->count = count($this->authordata_array);
176
+ }
177
+
178
+ function iterate(){
179
+ global $authordata;
180
+ $this->position++;
181
+
182
+ //At the end of the loop
183
+ if($this->position > $this->count-1){
184
+ $authordata = $this->original_authordata;
185
+ $this->position = -1;
186
+ return false;
187
+ }
188
+
189
+ //At the beginning of the loop
190
+ if($this->position == 0 && !empty($authordata))
191
+ $this->original_authordata = $authordata;
192
+
193
+ $authordata = $this->authordata_array[$this->position];
194
+
195
+ return true;
196
+ }
197
+
198
+ function get_position(){
199
+ if($this->position === -1)
200
+ return false;
201
+ return $this->position;
202
+ }
203
+ function is_last(){
204
+ return $this->position === $this->count-1;
205
+ }
206
+ function is_first(){
207
+ return $this->position === 0;
208
+ }
209
+ function count(){
210
+ return $this->count;
211
+ }
212
+ function get_all(){
213
+ return $this->authordata_array;
214
+ }
215
+ }
216
+
217
+ //Helper function for the following new template tags
218
+ function coauthors__echo($tag, $between, $betweenLast, $before, $after){
219
+ $i = new CoAuthorsIterator();
220
+ echo $before;
221
+ if($i->iterate())
222
+ $tag();
223
+ while($i->iterate()){
224
+ echo $i->is_last() ? $betweenLast : $between;
225
+ $tag();
226
+ }
227
+ echo $after;
228
+ }
229
+
230
+ //Provide co-author equivalents to the existing author template tags
231
+ function coauthors($between = null, $betweenLast = null, $before = null, $after = null){
232
+ if($between === NULL)
233
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
234
+ if($betweenLast === NULL)
235
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
236
+ if($before === NULL)
237
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
238
+ if($after === NULL)
239
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
240
+ coauthors__echo('the_author', $between, $betweenLast, $before, $after);
241
+ }
242
+ function coauthors_posts_links($between = null, $betweenLast = null, $before = null, $after = null){
243
+ if($between === NULL)
244
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
245
+ if($betweenLast === NULL)
246
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
247
+ if($before === NULL)
248
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
249
+ if($after === NULL)
250
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
251
+ coauthors__echo('the_author_posts_link', $between, $betweenLast, $before, $after);
252
+ }
253
+ function coauthors_firstnames($between = null, $betweenLast = null, $before = null, $after = null){
254
+ if($between === NULL)
255
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
256
+ if($betweenLast === NULL)
257
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
258
+ if($before === NULL)
259
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
260
+ if($after === NULL)
261
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
262
+ coauthors__echo('the_author_firstname', $between, $betweenLast, $before, $after);
263
+ }
264
+ function coauthors_lastnames($between = null, $betweenLast = null, $before = null, $after = null){
265
+ if($between === NULL)
266
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
267
+ if($betweenLast === NULL)
268
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
269
+ if($before === NULL)
270
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
271
+ if($after === NULL)
272
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
273
+ coauthors__echo('the_author_lastname', $between, $betweenLast, $before, $after);
274
+ }
275
+ function coauthors_nicknames($between = null, $betweenLast = null, $before = null, $after = null){
276
+ if($between === NULL)
277
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
278
+ if($betweenLast === NULL)
279
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
280
+ if($before === NULL)
281
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
282
+ if($after === NULL)
283
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
284
+ coauthors__echo('the_author_nickname', $between, $betweenLast, $before, $after);
285
+ }
286
+ function coauthors_links($between = null, $betweenLast = null, $before = null, $after = null){
287
+ if($between === NULL)
288
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
289
+ if($betweenLast === NULL)
290
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
291
+ if($before === NULL)
292
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
293
+ if($after === NULL)
294
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
295
+ coauthors__echo('the_author_link', $between, $betweenLast, $before, $after);
296
+ }
297
+ function coauthors_IDs($between = null, $betweenLast = null, $before = null, $after = null){
298
+ if($between === NULL)
299
+ $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
300
+ if($betweenLast === NULL)
301
+ $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
302
+ if($before === NULL)
303
+ $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
304
+ if($after === NULL)
305
+ $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
306
+ coauthors__echo('the_author_ID', $between, $betweenLast, $before, $after);
307
+ }
308
+ //function coauthors_emails($between = null, $betweenLast = null, $before = null, $after = null){
309
+ // if($between === NULL)
310
+ // $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
311
+ // if($betweenLast === NULL)
312
+ // $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
313
+ // if($before === NULL)
314
+ // $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
315
+ // if($after === NULL)
316
+ // $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
317
+ // coauthors__echo('the_author_email', $between, $betweenLast, $before, $after);
318
+ //}
319
+ //function coauthors_urls($between = null, $betweenLast = null, $before = null, $after = null){
320
+ // if($between === NULL)
321
+ // $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
322
+ // if($betweenLast === NULL)
323
+ // $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
324
+ // if($before === NULL)
325
+ // $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
326
+ // if($after === NULL)
327
+ // $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
328
+ // coauthors__echo('the_author_url', $between, $betweenLast, $before, $after);
329
+ //}
330
+ //function coauthors_icq($between = null, $betweenLast = null, $before = null, $after = null){
331
+ // if($between === NULL)
332
+ // $between = __(COAUTHORS_DEFAULT_BETWEEN, 'co-authors');
333
+ // if($betweenLast === NULL)
334
+ // $betweenLast = __(COAUTHORS_DEFAULT_BETWEEN_LAST, 'co-authors');
335
+ // if($before === NULL)
336
+ // $before = COAUTHORS_DEFAULT_BEFORE; //__(COAUTHORS_DEFAULT_BEFORE, 'co-authors');
337
+ // if($after === NULL)
338
+ // $after = COAUTHORS_DEFAULT_AFTER; //__(COAUTHORS_DEFAULT_AFTER, 'co-authors');
339
+ // coauthors__echo('the_author_icq', $between, $betweenLast, $before, $after);
340
+ //}
341
+
342
+
343
+ function coauthors_init(){
344
+ if(is_admin())
345
+ wp_enqueue_script( 'jquery' );
346
+ }
347
+ add_action('init', 'coauthors_init');
348
+
349
+ function coauthors_add_stylesheet() {
350
+ global $current_user;
351
+ print '<link rel="stylesheet" type="text/css" href="../' . PLUGINDIR . '/co-authors-plus/admin.css" />';
352
+ }
353
+ add_action('admin_print_scripts', 'coauthors_add_stylesheet');
354
+
355
+ function coauthors_modify_post_sidebar(){
356
+ global $current_user;
357
+
358
+ print '<script type="text/javascript">';
359
+ print 'var coauthors_can_edit_others_posts = ' . ($current_user->has_cap('edit_others_posts') ? 'true' : 'false') . "\n";
360
+ print 'var coauthors_dbx_post_title = "' . __('Post Author(s)', 'co-authors') . '";';
361
+ print 'var coauthors_dbx_page_title = "' . __('Page Author(s)', 'co-authors') . '";';
362
+ print 'var coauthors_add_author_label = "' . __('+ Add author', 'co-authors') . '";';
363
+ print 'var coauthors_confirm_delete_label = "' . __('Are you sure you want to remove the user \u201C%s\u201D as an author?', 'co-authors') . '";';
364
+ #print 'var coauthors_moveUp_author_label = "' . __('+ Add author', 'co-authors') . '";';
365
+ #print 'var coauthors_moveDown_author_label = "' . __('+ Add author', 'co-authors') . '";';
366
+ #print 'var coauthors_delete_author_label = "' . __('+ Add author', 'co-authors') . '";';
367
+ print '</script>';
368
+
369
+ print '<script type="text/javascript" src="../' . PLUGINDIR . '/co-authors-plus/admin.js"></script>';
370
+
371
+
372
+ }
373
+ add_action('admin_footer', 'coauthors_modify_post_sidebar'); //dbx_post_sidebar,edit_form_advanced
374
+
375
+ //Update a post's co-authors
376
+ function coauthors_update_post($postID){
377
+ global $current_user, $wpdb;
378
+ if($current_user->has_cap('edit_others_posts') && @$_POST['coauthors_plugin_is_active']){
379
+ //Delete all existing co-authors from a post
380
+ delete_post_meta($postID, '_coauthor');
381
+
382
+ //Newly add each co-author to the post meta
383
+ if(is_array($_POST['coauthors'])){
384
+ foreach(array_unique($_POST['coauthors']) as $authorID){
385
+ if(is_numeric($authorID) && $wpdb->get_var("SELECT ID FROM $wpdb->users WHERE ID = $authorID")){
386
+ add_post_meta($postID, '_coauthor', (int)$authorID, false);
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ add_action('edit_post', 'coauthors_update_post');
393
+ add_action('save_post', 'coauthors_update_post');
394
+
395
+ function coauthors_delete_user_action($userID){
396
+ global $wpdb;
397
+ //$reassign = null;
398
+ ////Get $reassign parameter from calling wp_delete_user function
399
+ //if(function_exists('debug_backtrace')){
400
+ // $callstack = debug_backtrace();
401
+ // foreach($callstack as $caller){
402
+ // if($caller['function'] == 'wp_delete_user'){
403
+ // if(is_numeric($caller['args'][1/*reassign*/]))
404
+ // $reassign = (int)$caller['args'][1/*reassign*/];
405
+ // break;
406
+ // }
407
+ // }
408
+ //}
409
+ ////Otherwise, try to get the reassign user from POST data
410
+ //else if(@$_POST['delete_option'] == 'reassign' && is_numeric(@$_POST['reassign_user'])) {
411
+ // $reassign = (int)$_POST['reassign_user'];
412
+ //}
413
+
414
+ //Reassign all co-author post meta
415
+ //if($reassign){
416
+ // $postIDs = $wpdb->get_col("SELECT ID FROM $wpdb->posts p LEFT JOIN $wpdb->postmeta pm ON p.ID = pm.post_id AND p.post_type != 'revision' AND pm.meta_key = '_coauthor' AND pm.meta_value = '$reassign';");
417
+ // foreach($postIDs as $postID){
418
+ // //if the post's post_author != $reassign and there isn't a post meta coauthor which is $reassign
419
+ // if($wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts p
420
+ // LEFT JOIN $wpdb->postmeta pm
421
+ // ON p.ID = pm.post_id AND pm.meta_key = '_coauthor' AND pm.meta_value = '$reassign'
422
+ // WHERE p.ID = $postID AND p.post_type != 'revision' AND (p.post_author = '$reassign' OR pm.meta_value = '$reassign')") == 0)
423
+ // {
424
+ // update_post_meta($postID, '_coauthor', $reassign, $userID);
425
+ // }
426
+ // //the reassign author already exists for this post, so just delete the post meta
427
+ // else {
428
+ // delete_post_meta($postID, '_coauthor', $userID);
429
+ // }
430
+ // }
431
+ //}
432
+ ////Delete all co-author post meta
433
+ //else
434
+ $wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key = '_coauthor' AND meta_value = '$userID';");
435
+ }
436
+ add_action('delete_user', 'coauthors_delete_user_action');
437
+
438
+
439
+ //customized wp_list_authors() from WP core
440
+ /**
441
+ * List all the *co-authors* of the blog, with several options available.
442
+ * optioncount (boolean) (false): Show the count in parenthesis next to the author's name.
443
+ * exclude_admin (boolean) (true): Exclude the 'admin' user that is installed by default.
444
+ * show_fullname (boolean) (false): Show their full names.
445
+ * hide_empty (boolean) (true): Don't show authors without any posts.
446
+ * feed (string) (''): If isn't empty, show links to author's feeds.
447
+ * feed_image (string) (''): If isn't empty, use this image to link to feeds.
448
+ * echo (boolean) (true): Set to false to return the output, instead of echoing.
449
+ * @param array $args The argument array.
450
+ * @return null|string The output, if echo is set to false.
451
+ */
452
+ function coauthors_wp_list_authors($args = ''){
453
+ global $wpdb;
454
+
455
+ $defaults = array(
456
+ 'optioncount' => false, 'exclude_admin' => true,
457
+ 'show_fullname' => false, 'hide_empty' => true,
458
+ 'feed' => '', 'feed_image' => '', 'echo' => true
459
+ );
460
+
461
+ $r = wp_parse_args( $args, $defaults );
462
+ extract($r, EXTR_SKIP);
463
+
464
+ $return = '';
465
+
466
+ // TODO: Move select to get_authors().
467
+ $authors = $wpdb->get_results("SELECT ID, user_nicename from $wpdb->users " . ($exclude_admin ? "WHERE user_login <> 'admin' " : '') . "ORDER BY display_name");
468
+
469
+ $author_count = array();
470
+ $sql = "SELECT DISTINCT
471
+ p1.post_author,
472
+ (COUNT(ID)+(SELECT COUNT(*)
473
+ FROM $wpdb->posts p2, $wpdb->postmeta pm
474
+ WHERE p2.ID = pm.post_id
475
+ AND pm.meta_key = '_coauthor'
476
+ AND pm.meta_value = p1.post_author)
477
+ ) AS count
478
+ FROM $wpdb->posts p1
479
+ WHERE post_type = 'post' AND " . get_private_posts_cap_sql( 'post' ) . "
480
+ GROUP BY post_author";
481
+
482
+ foreach ((array) $wpdb->get_results($sql) as $row) {
483
+ $author_count[$row->post_author] = $row->count;
484
+ }
485
+
486
+ foreach ( (array) $authors as $author ) {
487
+ $author = get_userdata( $author->ID );
488
+ $posts = (isset($author_count[$author->ID])) ? $author_count[$author->ID] : 0;
489
+ $name = $author->display_name;
490
+
491
+ if ( $show_fullname && ($author->first_name != '' && $author->last_name != '') )
492
+ $name = "$author->first_name $author->last_name";
493
+
494
+ if ( !($posts == 0 && $hide_empty) )
495
+ $return .= '<li>';
496
+ if ( $posts == 0 ) {
497
+ if ( !$hide_empty )
498
+ $link = $name;
499
+ } else {
500
+ $link = '<a href="' . get_author_posts_url($author->ID, $author->user_nicename) . '" title="' . sprintf(__("Posts by %s"), attribute_escape($author->display_name)) . '">' . $name . '</a>';
501
+
502
+ if ( (! empty($feed_image)) || (! empty($feed)) ) {
503
+ $link .= ' ';
504
+ if (empty($feed_image))
505
+ $link .= '(';
506
+ $link .= '<a href="' . get_author_rss_link(0, $author->ID, $author->user_nicename) . '"';
507
+
508
+ if ( !empty($feed) ) {
509
+ $title = ' title="' . $feed . '"';
510
+ $alt = ' alt="' . $feed . '"';
511
+ $name = $feed;
512
+ $link .= $title;
513
+ }
514
+
515
+ $link .= '>';
516
+
517
+ if ( !empty($feed_image) )
518
+ $link .= "<img src=\"$feed_image\" border=\"0\"$alt$title" . ' />';
519
+ else
520
+ $link .= $name;
521
+
522
+ $link .= '</a>';
523
+
524
+ if ( empty($feed_image) )
525
+ $link .= ')';
526
+ }
527
+
528
+ if ( $optioncount )
529
+ $link .= ' ('. $posts . ')';
530
+
531
+ }
532
+
533
+ if ( !($posts == 0 && $hide_empty) )
534
+ $return .= $link . '</li>';
535
+ }
536
+ if ( !$echo )
537
+ return $return;
538
+ echo $return;
539
+ }
540
+
541
+
542
+
543
+ add_action('admin_print_scripts', 'coauthor_js_admin_header' );
544
+
545
+ function coauthor_js_admin_header() {
546
+ //use JavaScript SACK library for Ajax
547
+ //wp_print_scripts( array( 'sack' ));
548
+
549
+ // Add suggest.js plugin
550
+ wp_enqueue_script( 'suggest' );
551
+
552
+ // Define custom JavaScript function
553
+ ?>
554
+ <script type="text/javascript">
555
+ //<![CDATA[
556
+ var coauthor_ajax_suggest_link = '<?php bloginfo( 'wpurl' ); ?>/wp-content/plugins/co-authors-plus/suggest.php';
557
+ //]]>
558
+ </script>
559
+ <?php
560
+ } // end of PHP function coauthor_js_admin_header
561
+
562
+ ?>
trunk/license.txt ADDED
@@ -0,0 +1,674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ them if you wish), that you receive source code or can get it if you
26
+ want it, that you can change the software or use pieces of it in new
27
+ free programs, and that you know you can do these things.
28
+
29
+ To protect your rights, we need to prevent others from denying you
30
+ these rights or asking you to surrender the rights. Therefore, you have
31
+ certain responsibilities if you distribute copies of the software, or if
32
+ you modify it: responsibilities to respect the freedom of others.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must pass on to the recipients the same
36
+ freedoms that you received. You must make sure that they, too, receive
37
+ or can get the source code. And you must show them these terms so they
38
+ know their rights.
39
+
40
+ Developers that use the GNU GPL protect your rights with two steps:
41
+ (1) assert copyright on the software, and (2) offer you this License
42
+ giving you legal permission to copy, distribute and/or modify it.
43
+
44
+ For the developers' and authors' protection, the GPL clearly explains
45
+ that there is no warranty for this free software. For both users' and
46
+ authors' sake, the GPL requires that modified versions be marked as
47
+ changed, so that their problems will not be attributed erroneously to
48
+ authors of previous versions.
49
+
50
+ Some devices are designed to deny users access to install or run
51
+ modified versions of the software inside them, although the manufacturer
52
+ can do so. This is fundamentally incompatible with the aim of
53
+ protecting users' freedom to change the software. The systematic
54
+ pattern of such abuse occurs in the area of products for individuals to
55
+ use, which is precisely where it is most unacceptable. Therefore, we
56
+ have designed this version of the GPL to prohibit the practice for those
57
+ products. If such problems arise substantially in other domains, we
58
+ stand ready to extend this provision to those domains in future versions
59
+ of the GPL, as needed to protect the freedom of users.
60
+
61
+ Finally, every program is threatened constantly by software patents.
62
+ States should not allow patents to restrict development and use of
63
+ software on general-purpose computers, but in those that do, we wish to
64
+ avoid the special danger that patents applied to a free program could
65
+ make it effectively proprietary. To prevent this, the GPL assures that
66
+ patents cannot be used to render the program non-free.
67
+
68
+ The precise terms and conditions for copying, distribution and
69
+ modification follow.
70
+
71
+ TERMS AND CONDITIONS
72
+
73
+ 0. Definitions.
74
+
75
+ "This License" refers to version 3 of the GNU General Public License.
76
+
77
+ "Copyright" also means copyright-like laws that apply to other kinds of
78
+ works, such as semiconductor masks.
79
+
80
+ "The Program" refers to any copyrightable work licensed under this
81
+ License. Each licensee is addressed as "you". "Licensees" and
82
+ "recipients" may be individuals or organizations.
83
+
84
+ To "modify" a work means to copy from or adapt all or part of the work
85
+ in a fashion requiring copyright permission, other than the making of an
86
+ exact copy. The resulting work is called a "modified version" of the
87
+ earlier work or a work "based on" the earlier work.
88
+
89
+ A "covered work" means either the unmodified Program or a work based
90
+ on the Program.
91
+
92
+ To "propagate" a work means to do anything with it that, without
93
+ permission, would make you directly or secondarily liable for
94
+ infringement under applicable copyright law, except executing it on a
95
+ computer or modifying a private copy. Propagation includes copying,
96
+ distribution (with or without modification), making available to the
97
+ public, and in some countries other activities as well.
98
+
99
+ To "convey" a work means any kind of propagation that enables other
100
+ parties to make or receive copies. Mere interaction with a user through
101
+ a computer network, with no transfer of a copy, is not conveying.
102
+
103
+ An interactive user interface displays "Appropriate Legal Notices"
104
+ to the extent that it includes a convenient and prominently visible
105
+ feature that (1) displays an appropriate copyright notice, and (2)
106
+ tells the user that there is no warranty for the work (except to the
107
+ extent that warranties are provided), that licensees may convey the
108
+ work under this License, and how to view a copy of this License. If
109
+ the interface presents a list of user commands or options, such as a
110
+ menu, a prominent item in the list meets this criterion.
111
+
112
+ 1. Source Code.
113
+
114
+ The "source code" for a work means the preferred form of the work
115
+ for making modifications to it. "Object code" means any non-source
116
+ form of a work.
117
+
118
+ A "Standard Interface" means an interface that either is an official
119
+ standard defined by a recognized standards body, or, in the case of
120
+ interfaces specified for a particular programming language, one that
121
+ is widely used among developers working in that language.
122
+
123
+ The "System Libraries" of an executable work include anything, other
124
+ than the work as a whole, that (a) is included in the normal form of
125
+ packaging a Major Component, but which is not part of that Major
126
+ Component, and (b) serves only to enable use of the work with that
127
+ Major Component, or to implement a Standard Interface for which an
128
+ implementation is available to the public in source code form. A
129
+ "Major Component", in this context, means a major essential component
130
+ (kernel, window system, and so on) of the specific operating system
131
+ (if any) on which the executable work runs, or a compiler used to
132
+ produce the work, or an object code interpreter used to run it.
133
+
134
+ The "Corresponding Source" for a work in object code form means all
135
+ the source code needed to generate, install, and (for an executable
136
+ work) run the object code and to modify the work, including scripts to
137
+ control those activities. However, it does not include the work's
138
+ System Libraries, or general-purpose tools or generally available free
139
+ programs which are used unmodified in performing those activities but
140
+ which are not part of the work. For example, Corresponding Source
141
+ includes interface definition files associated with source files for
142
+ the work, and the source code for shared libraries and dynamically
143
+ linked subprograms that the work is specifically designed to require,
144
+ such as by intimate data communication or control flow between those
145
+ subprograms and other parts of the work.
146
+
147
+ The Corresponding Source need not include anything that users
148
+ can regenerate automatically from other parts of the Corresponding
149
+ Source.
150
+
151
+ The Corresponding Source for a work in source code form is that
152
+ same work.
153
+
154
+ 2. Basic Permissions.
155
+
156
+ All rights granted under this License are granted for the term of
157
+ copyright on the Program, and are irrevocable provided the stated
158
+ conditions are met. This License explicitly affirms your unlimited
159
+ permission to run the unmodified Program. The output from running a
160
+ covered work is covered by this License only if the output, given its
161
+ content, constitutes a covered work. This License acknowledges your
162
+ rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+ You may make, run and propagate covered works that you do not
165
+ convey, without conditions so long as your license otherwise remains
166
+ in force. You may convey covered works to others for the sole purpose
167
+ of having them make modifications exclusively for you, or provide you
168
+ with facilities for running those works, provided that you comply with
169
+ the terms of this License in conveying all material for which you do
170
+ not control copyright. Those thus making or running the covered works
171
+ for you must do so exclusively on your behalf, under your direction
172
+ and control, on terms that prohibit them from making any copies of
173
+ your copyrighted material outside their relationship with you.
174
+
175
+ Conveying under any other circumstances is permitted solely under
176
+ the conditions stated below. Sublicensing is not allowed; section 10
177
+ makes it unnecessary.
178
+
179
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+ No covered work shall be deemed part of an effective technological
182
+ measure under any applicable law fulfilling obligations under article
183
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+ similar laws prohibiting or restricting circumvention of such
185
+ measures.
186
+
187
+ When you convey a covered work, you waive any legal power to forbid
188
+ circumvention of technological measures to the extent such circumvention
189
+ is effected by exercising rights under this License with respect to
190
+ the covered work, and you disclaim any intention to limit operation or
191
+ modification of the work as a means of enforcing, against the work's
192
+ users, your or third parties' legal rights to forbid circumvention of
193
+ technological measures.
194
+
195
+ 4. Conveying Verbatim Copies.
196
+
197
+ You may convey verbatim copies of the Program's source code as you
198
+ receive it, in any medium, provided that you conspicuously and
199
+ appropriately publish on each copy an appropriate copyright notice;
200
+ keep intact all notices stating that this License and any
201
+ non-permissive terms added in accord with section 7 apply to the code;
202
+ keep intact all notices of the absence of any warranty; and give all
203
+ recipients a copy of this License along with the Program.
204
+
205
+ You may charge any price or no price for each copy that you convey,
206
+ and you may offer support or warranty protection for a fee.
207
+
208
+ 5. Conveying Modified Source Versions.
209
+
210
+ You may convey a work based on the Program, or the modifications to
211
+ produce it from the Program, in the form of source code under the
212
+ terms of section 4, provided that you also meet all of these conditions:
213
+
214
+ a) The work must carry prominent notices stating that you modified
215
+ it, and giving a relevant date.
216
+
217
+ b) The work must carry prominent notices stating that it is
218
+ released under this License and any conditions added under section
219
+ 7. This requirement modifies the requirement in section 4 to
220
+ "keep intact all notices".
221
+
222
+ c) You must license the entire work, as a whole, under this
223
+ License to anyone who comes into possession of a copy. This
224
+ License will therefore apply, along with any applicable section 7
225
+ additional terms, to the whole of the work, and all its parts,
226
+ regardless of how they are packaged. This License gives no
227
+ permission to license the work in any other way, but it does not
228
+ invalidate such permission if you have separately received it.
229
+
230
+ d) If the work has interactive user interfaces, each must display
231
+ Appropriate Legal Notices; however, if the Program has interactive
232
+ interfaces that do not display Appropriate Legal Notices, your
233
+ work need not make them do so.
234
+
235
+ A compilation of a covered work with other separate and independent
236
+ works, which are not by their nature extensions of the covered work,
237
+ and which are not combined with it such as to form a larger program,
238
+ in or on a volume of a storage or distribution medium, is called an
239
+ "aggregate" if the compilation and its resulting copyright are not
240
+ used to limit the access or legal rights of the compilation's users
241
+ beyond what the individual works permit. Inclusion of a covered work
242
+ in an aggregate does not cause this License to apply to the other
243
+ parts of the aggregate.
244
+
245
+ 6. Conveying Non-Source Forms.
246
+
247
+ You may convey a covered work in object code form under the terms
248
+ of sections 4 and 5, provided that you also convey the
249
+ machine-readable Corresponding Source under the terms of this License,
250
+ in one of these ways:
251
+
252
+ a) Convey the object code in, or embodied in, a physical product
253
+ (including a physical distribution medium), accompanied by the
254
+ Corresponding Source fixed on a durable physical medium
255
+ customarily used for software interchange.
256
+
257
+ b) Convey the object code in, or embodied in, a physical product
258
+ (including a physical distribution medium), accompanied by a
259
+ written offer, valid for at least three years and valid for as
260
+ long as you offer spare parts or customer support for that product
261
+ model, to give anyone who possesses the object code either (1) a
262
+ copy of the Corresponding Source for all the software in the
263
+ product that is covered by this License, on a durable physical
264
+ medium customarily used for software interchange, for a price no
265
+ more than your reasonable cost of physically performing this
266
+ conveying of source, or (2) access to copy the
267
+ Corresponding Source from a network server at no charge.
268
+
269
+ c) Convey individual copies of the object code with a copy of the
270
+ written offer to provide the Corresponding Source. This
271
+ alternative is allowed only occasionally and noncommercially, and
272
+ only if you received the object code with such an offer, in accord
273
+ with subsection 6b.
274
+
275
+ d) Convey the object code by offering access from a designated
276
+ place (gratis or for a charge), and offer equivalent access to the
277
+ Corresponding Source in the same way through the same place at no
278
+ further charge. You need not require recipients to copy the
279
+ Corresponding Source along with the object code. If the place to
280
+ copy the object code is a network server, the Corresponding Source
281
+ may be on a different server (operated by you or a third party)
282
+ that supports equivalent copying facilities, provided you maintain
283
+ clear directions next to the object code saying where to find the
284
+ Corresponding Source. Regardless of what server hosts the
285
+ Corresponding Source, you remain obligated to ensure that it is
286
+ available for as long as needed to satisfy these requirements.
287
+
288
+ e) Convey the object code using peer-to-peer transmission, provided
289
+ you inform other peers where the object code and Corresponding
290
+ Source of the work are being offered to the general public at no
291
+ charge under subsection 6d.
292
+
293
+ A separable portion of the object code, whose source code is excluded
294
+ from the Corresponding Source as a System Library, need not be
295
+ included in conveying the object code work.
296
+
297
+ A "User Product" is either (1) a "consumer product", which means any
298
+ tangible personal property which is normally used for personal, family,
299
+ or household purposes, or (2) anything designed or sold for incorporation
300
+ into a dwelling. In determining whether a product is a consumer product,
301
+ doubtful cases shall be resolved in favor of coverage. For a particular
302
+ product received by a particular user, "normally used" refers to a
303
+ typical or common use of that class of product, regardless of the status
304
+ of the particular user or of the way in which the particular user
305
+ actually uses, or expects or is expected to use, the product. A product
306
+ is a consumer product regardless of whether the product has substantial
307
+ commercial, industrial or non-consumer uses, unless such uses represent
308
+ the only significant mode of use of the product.
309
+
310
+ "Installation Information" for a User Product means any methods,
311
+ procedures, authorization keys, or other information required to install
312
+ and execute modified versions of a covered work in that User Product from
313
+ a modified version of its Corresponding Source. The information must
314
+ suffice to ensure that the continued functioning of the modified object
315
+ code is in no case prevented or interfered with solely because
316
+ modification has been made.
317
+
318
+ If you convey an object code work under this section in, or with, or
319
+ specifically for use in, a User Product, and the conveying occurs as
320
+ part of a transaction in which the right of possession and use of the
321
+ User Product is transferred to the recipient in perpetuity or for a
322
+ fixed term (regardless of how the transaction is characterized), the
323
+ Corresponding Source conveyed under this section must be accompanied
324
+ by the Installation Information. But this requirement does not apply
325
+ if neither you nor any third party retains the ability to install
326
+ modified object code on the User Product (for example, the work has
327
+ been installed in ROM).
328
+
329
+ The requirement to provide Installation Information does not include a
330
+ requirement to continue to provide support service, warranty, or updates
331
+ for a work that has been modified or installed by the recipient, or for
332
+ the User Product in which it has been modified or installed. Access to a
333
+ network may be denied when the modification itself materially and
334
+ adversely affects the operation of the network or violates the rules and
335
+ protocols for communication across the network.
336
+
337
+ Corresponding Source conveyed, and Installation Information provided,
338
+ in accord with this section must be in a format that is publicly
339
+ documented (and with an implementation available to the public in
340
+ source code form), and must require no special password or key for
341
+ unpacking, reading or copying.
342
+
343
+ 7. Additional Terms.
344
+
345
+ "Additional permissions" are terms that supplement the terms of this
346
+ License by making exceptions from one or more of its conditions.
347
+ Additional permissions that are applicable to the entire Program shall
348
+ be treated as though they were included in this License, to the extent
349
+ that they are valid under applicable law. If additional permissions
350
+ apply only to part of the Program, that part may be used separately
351
+ under those permissions, but the entire Program remains governed by
352
+ this License without regard to the additional permissions.
353
+
354
+ When you convey a copy of a covered work, you may at your option
355
+ remove any additional permissions from that copy, or from any part of
356
+ it. (Additional permissions may be written to require their own
357
+ removal in certain cases when you modify the work.) You may place
358
+ additional permissions on material, added by you to a covered work,
359
+ for which you have or can give appropriate copyright permission.
360
+
361
+ Notwithstanding any other provision of this License, for material you
362
+ add to a covered work, you may (if authorized by the copyright holders of
363
+ that material) supplement the terms of this License with terms:
364
+
365
+ a) Disclaiming warranty or limiting liability differently from the
366
+ terms of sections 15 and 16 of this License; or
367
+
368
+ b) Requiring preservation of specified reasonable legal notices or
369
+ author attributions in that material or in the Appropriate Legal
370
+ Notices displayed by works containing it; or
371
+
372
+ c) Prohibiting misrepresentation of the origin of that material, or
373
+ requiring that modified versions of such material be marked in
374
+ reasonable ways as different from the original version; or
375
+
376
+ d) Limiting the use for publicity purposes of names of licensors or
377
+ authors of the material; or
378
+
379
+ e) Declining to grant rights under trademark law for use of some
380
+ trade names, trademarks, or service marks; or
381
+
382
+ f) Requiring indemnification of licensors and authors of that
383
+ material by anyone who conveys the material (or modified versions of
384
+ it) with contractual assumptions of liability to the recipient, for
385
+ any liability that these contractual assumptions directly impose on
386
+ those licensors and authors.
387
+
388
+ All other non-permissive additional terms are considered "further
389
+ restrictions" within the meaning of section 10. If the Program as you
390
+ received it, or any part of it, contains a notice stating that it is
391
+ governed by this License along with a term that is a further
392
+ restriction, you may remove that term. If a license document contains
393
+ a further restriction but permits relicensing or conveying under this
394
+ License, you may add to a covered work material governed by the terms
395
+ of that license document, provided that the further restriction does
396
+ not survive such relicensing or conveying.
397
+
398
+ If you add terms to a covered work in accord with this section, you
399
+ must place, in the relevant source files, a statement of the
400
+ additional terms that apply to those files, or a notice indicating
401
+ where to find the applicable terms.
402
+
403
+ Additional terms, permissive or non-permissive, may be stated in the
404
+ form of a separately written license, or stated as exceptions;
405
+ the above requirements apply either way.
406
+
407
+ 8. Termination.
408
+
409
+ You may not propagate or modify a covered work except as expressly
410
+ provided under this License. Any attempt otherwise to propagate or
411
+ modify it is void, and will automatically terminate your rights under
412
+ this License (including any patent licenses granted under the third
413
+ paragraph of section 11).
414
+
415
+ However, if you cease all violation of this License, then your
416
+ license from a particular copyright holder is reinstated (a)
417
+ provisionally, unless and until the copyright holder explicitly and
418
+ finally terminates your license, and (b) permanently, if the copyright
419
+ holder fails to notify you of the violation by some reasonable means
420
+ prior to 60 days after the cessation.
421
+
422
+ Moreover, your license from a particular copyright holder is
423
+ reinstated permanently if the copyright holder notifies you of the
424
+ violation by some reasonable means, this is the first time you have
425
+ received notice of violation of this License (for any work) from that
426
+ copyright holder, and you cure the violation prior to 30 days after
427
+ your receipt of the notice.
428
+
429
+ Termination of your rights under this section does not terminate the
430
+ licenses of parties who have received copies or rights from you under
431
+ this License. If your rights have been terminated and not permanently
432
+ reinstated, you do not qualify to receive new licenses for the same
433
+ material under section 10.
434
+
435
+ 9. Acceptance Not Required for Having Copies.
436
+
437
+ You are not required to accept this License in order to receive or
438
+ run a copy of the Program. Ancillary propagation of a covered work
439
+ occurring solely as a consequence of using peer-to-peer transmission
440
+ to receive a copy likewise does not require acceptance. However,
441
+ nothing other than this License grants you permission to propagate or
442
+ modify any covered work. These actions infringe copyright if you do
443
+ not accept this License. Therefore, by modifying or propagating a
444
+ covered work, you indicate your acceptance of this License to do so.
445
+
446
+ 10. Automatic Licensing of Downstream Recipients.
447
+
448
+ Each time you convey a covered work, the recipient automatically
449
+ receives a license from the original licensors, to run, modify and
450
+ propagate that work, subject to this License. You are not responsible
451
+ for enforcing compliance by third parties with this License.
452
+
453
+ An "entity transaction" is a transaction transferring control of an
454
+ organization, or substantially all assets of one, or subdividing an
455
+ organization, or merging organizations. If propagation of a covered
456
+ work results from an entity transaction, each party to that
457
+ transaction who receives a copy of the work also receives whatever
458
+ licenses to the work the party's predecessor in interest had or could
459
+ give under the previous paragraph, plus a right to possession of the
460
+ Corresponding Source of the work from the predecessor in interest, if
461
+ the predecessor has it or can get it with reasonable efforts.
462
+
463
+ You may not impose any further restrictions on the exercise of the
464
+ rights granted or affirmed under this License. For example, you may
465
+ not impose a license fee, royalty, or other charge for exercise of
466
+ rights granted under this License, and you may not initiate litigation
467
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
468
+ any patent claim is infringed by making, using, selling, offering for
469
+ sale, or importing the Program or any portion of it.
470
+
471
+ 11. Patents.
472
+
473
+ A "contributor" is a copyright holder who authorizes use under this
474
+ License of the Program or a work on which the Program is based. The
475
+ work thus licensed is called the contributor's "contributor version".
476
+
477
+ A contributor's "essential patent claims" are all patent claims
478
+ owned or controlled by the contributor, whether already acquired or
479
+ hereafter acquired, that would be infringed by some manner, permitted
480
+ by this License, of making, using, or selling its contributor version,
481
+ but do not include claims that would be infringed only as a
482
+ consequence of further modification of the contributor version. For
483
+ purposes of this definition, "control" includes the right to grant
484
+ patent sublicenses in a manner consistent with the requirements of
485
+ this License.
486
+
487
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+ patent license under the contributor's essential patent claims, to
489
+ make, use, sell, offer for sale, import and otherwise run, modify and
490
+ propagate the contents of its contributor version.
491
+
492
+ In the following three paragraphs, a "patent license" is any express
493
+ agreement or commitment, however denominated, not to enforce a patent
494
+ (such as an express permission to practice a patent or covenant not to
495
+ sue for patent infringement). To "grant" such a patent license to a
496
+ party means to make such an agreement or commitment not to enforce a
497
+ patent against the party.
498
+
499
+ If you convey a covered work, knowingly relying on a patent license,
500
+ and the Corresponding Source of the work is not available for anyone
501
+ to copy, free of charge and under the terms of this License, through a
502
+ publicly available network server or other readily accessible means,
503
+ then you must either (1) cause the Corresponding Source to be so
504
+ available, or (2) arrange to deprive yourself of the benefit of the
505
+ patent license for this particular work, or (3) arrange, in a manner
506
+ consistent with the requirements of this License, to extend the patent
507
+ license to downstream recipients. "Knowingly relying" means you have
508
+ actual knowledge that, but for the patent license, your conveying the
509
+ covered work in a country, or your recipient's use of the covered work
510
+ in a country, would infringe one or more identifiable patents in that
511
+ country that you have reason to believe are valid.
512
+
513
+ If, pursuant to or in connection with a single transaction or
514
+ arrangement, you convey, or propagate by procuring conveyance of, a
515
+ covered work, and grant a patent license to some of the parties
516
+ receiving the covered work authorizing them to use, propagate, modify
517
+ or convey a specific copy of the covered work, then the patent license
518
+ you grant is automatically extended to all recipients of the covered
519
+ work and works based on it.
520
+
521
+ A patent license is "discriminatory" if it does not include within
522
+ the scope of its coverage, prohibits the exercise of, or is
523
+ conditioned on the non-exercise of one or more of the rights that are
524
+ specifically granted under this License. You may not convey a covered
525
+ work if you are a party to an arrangement with a third party that is
526
+ in the business of distributing software, under which you make payment
527
+ to the third party based on the extent of your activity of conveying
528
+ the work, and under which the third party grants, to any of the
529
+ parties who would receive the covered work from you, a discriminatory
530
+ patent license (a) in connection with copies of the covered work
531
+ conveyed by you (or copies made from those copies), or (b) primarily
532
+ for and in connection with specific products or compilations that
533
+ contain the covered work, unless you entered into that arrangement,
534
+ or that patent license was granted, prior to 28 March 2007.
535
+
536
+ Nothing in this License shall be construed as excluding or limiting
537
+ any implied license or other defenses to infringement that may
538
+ otherwise be available to you under applicable patent law.
539
+
540
+ 12. No Surrender of Others' Freedom.
541
+
542
+ If conditions are imposed on you (whether by court order, agreement or
543
+ otherwise) that contradict the conditions of this License, they do not
544
+ excuse you from the conditions of this License. If you cannot convey a
545
+ covered work so as to satisfy simultaneously your obligations under this
546
+ License and any other pertinent obligations, then as a consequence you may
547
+ not convey it at all. For example, if you agree to terms that obligate you
548
+ to collect a royalty for further conveying from those to whom you convey
549
+ the Program, the only way you could satisfy both those terms and this
550
+ License would be to refrain entirely from conveying the Program.
551
+
552
+ 13. Use with the GNU Affero General Public License.
553
+
554
+ Notwithstanding any other provision of this License, you have
555
+ permission to link or combine any covered work with a work licensed
556
+ under version 3 of the GNU Affero General Public License into a single
557
+ combined work, and to convey the resulting work. The terms of this
558
+ License will continue to apply to the part which is the covered work,
559
+ but the special requirements of the GNU Affero General Public License,
560
+ section 13, concerning interaction through a network will apply to the
561
+ combination as such.
562
+
563
+ 14. Revised Versions of this License.
564
+
565
+ The Free Software Foundation may publish revised and/or new versions of
566
+ the GNU General Public License from time to time. Such new versions will
567
+ be similar in spirit to the present version, but may differ in detail to
568
+ address new problems or concerns.
569
+
570
+ Each version is given a distinguishing version number. If the
571
+ Program specifies that a certain numbered version of the GNU General
572
+ Public License "or any later version" applies to it, you have the
573
+ option of following the terms and conditions either of that numbered
574
+ version or of any later version published by the Free Software
575
+ Foundation. If the Program does not specify a version number of the
576
+ GNU General Public License, you may choose any version ever published
577
+ by the Free Software Foundation.
578
+
579
+ If the Program specifies that a proxy can decide which future
580
+ versions of the GNU General Public License can be used, that proxy's
581
+ public statement of acceptance of a version permanently authorizes you
582
+ to choose that version for the Program.
583
+
584
+ Later license versions may give you additional or different
585
+ permissions. However, no additional obligations are imposed on any
586
+ author or copyright holder as a result of your choosing to follow a
587
+ later version.
588
+
589
+ 15. Disclaimer of Warranty.
590
+
591
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+ 16. Limitation of Liability.
601
+
602
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+ SUCH DAMAGES.
611
+
612
+ 17. Interpretation of Sections 15 and 16.
613
+
614
+ If the disclaimer of warranty and limitation of liability provided
615
+ above cannot be given local legal effect according to their terms,
616
+ reviewing courts shall apply local law that most closely approximates
617
+ an absolute waiver of all civil liability in connection with the
618
+ Program, unless a warranty or assumption of liability accompanies a
619
+ copy of the Program in return for a fee.
620
+
621
+ END OF TERMS AND CONDITIONS
622
+
623
+ How to Apply These Terms to Your New Programs
624
+
625
+ If you develop a new program, and you want it to be of the greatest
626
+ possible use to the public, the best way to achieve this is to make it
627
+ free software which everyone can redistribute and change under these terms.
628
+
629
+ To do so, attach the following notices to the program. It is safest
630
+ to attach them to the start of each source file to most effectively
631
+ state the exclusion of warranty; and each file should have at least
632
+ the "copyright" line and a pointer to where the full notice is found.
633
+
634
+ <one line to give the program's name and a brief idea of what it does.>
635
+ Copyright (C) <year> <name of author>
636
+
637
+ This program is free software: you can redistribute it and/or modify
638
+ it under the terms of the GNU General Public License as published by
639
+ the Free Software Foundation, either version 3 of the License, or
640
+ (at your option) any later version.
641
+
642
+ This program is distributed in the hope that it will be useful,
643
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
644
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645
+ GNU General Public License for more details.
646
+
647
+ You should have received a copy of the GNU General Public License
648
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
649
+
650
+ Also add information on how to contact you by electronic and paper mail.
651
+
652
+ If the program does terminal interaction, make it output a short
653
+ notice like this when it starts in an interactive mode:
654
+
655
+ <program> Copyright (C) <year> <name of author>
656
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
+ This is free software, and you are welcome to redistribute it
658
+ under certain conditions; type `show c' for details.
659
+
660
+ The hypothetical commands `show w' and `show c' should show the appropriate
661
+ parts of the General Public License. Of course, your program's commands
662
+ might be different; for a GUI interface, you would use an "about box".
663
+
664
+ You should also get your employer (if you work as a programmer) or school,
665
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
666
+ For more information on this, and how to apply and follow the GNU GPL, see
667
+ <http://www.gnu.org/licenses/>.
668
+
669
+ The GNU General Public License does not permit incorporating your program
670
+ into proprietary programs. If your program is a subroutine library, you
671
+ may consider it more useful to permit linking proprietary applications with
672
+ the library. If this is what you want to do, use the GNU Lesser General
673
+ Public License instead of this License. But first, please read
674
+ <http://www.gnu.org/philosophy/why-not-lgpl.html>.
trunk/readme.txt ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Co-Authors-Plus ===
2
+ Contributors: batmoo
3
+ Donate link: http://digitalize.ca/donate
4
+ Tags: authors, users
5
+ Tested up to: 2.7.1
6
+ Requires at least: 2.6
7
+ Stable tag: 1.1.3
8
+
9
+ Allows multiple authors to be assigned to a Post or Page. Co-authored posts appear on a co-author's posts page and feed.
10
+
11
+ == Description ==
12
+
13
+ Allows multiple authors to be assigned to a Post or Page. Co-authored posts appear on a co-author's posts page and feed. New template tags allow listing of co-authors. Editors may assign co-authors to a post via the search-as-you-type inputs in the 'Post Author(s)' box. Additionally, co-authors may edit the posts they are associated with, and co-authors who are contributors may only edit posts if they have not been published (as is usual). Co-authored posts appear on a co-author's posts page and feed.
14
+
15
+ This plugin is an extended version of the Co-Authors plugin originally developed at [Shepherd Interactive](http://www.shepherd-interactive.com/ "Shepherd Interactive specializes in web design and development in Portland, Oregon") (2007). Their plugin was inspired by 'Multiple Authors' plugin by Mark Jaquith (2005).
16
+
17
+ The extended version is created by Mohammad Jangda, and incorporates search-as-you-type functionality for adding users, which aims to make easy the task of adding multiple users to posts and pages, especially when dealing with a system with hundreds of users (typical of newspaper and magazine sites).
18
+
19
+ New template tags enable listing of co-authors:
20
+
21
+ * <code>coauthors()</code>
22
+ * <code>coauthors_posts_links()</code>
23
+ * <code>coauthors_firstnames()</code>
24
+ * <code>coauthors_lastnames()</code>
25
+ * <code>coauthors_nicknames()</code>
26
+ * <code>coauthors_links()</code>
27
+ * <code>coauthors_IDs()</code>
28
+
29
+ These template tags correspond to their "<code>the_author*</code>" equivalents; take special note of the pluralization.
30
+ Each of these template tags accept four optional arguments:
31
+
32
+ 1. <code>between</code>: default ", "
33
+ 1. <code>betweenLast</code>: default " and "
34
+ 1. <code>before</code>: default ""
35
+ 1. <code>after</code>: default ""
36
+
37
+ To use them, simply modify the code surrounding all instances of <code>the_author*()</code> to something like as follows:
38
+
39
+ if(function_exists('coauthors_posts_links'))
40
+ coauthors_posts_links();
41
+ else
42
+ the_author_posts_link();
43
+
44
+ The result of this would be formatted like "John Smith, Jane Doe and Joe Public".
45
+
46
+ Note that as of this writing, WordPress does provide a means of extending <code>wp_list_authors()</code>, so
47
+ included in this plugin is the function <code>coauthors_wp_list_authors()</code> modified
48
+ to take into account co-authored posts; the same arguments are accepted.
49
+
50
+ Sometimes you may need fine-graned control over the display of a posts's authors, and in this case you may use
51
+ the <code>CoAuthorsIterator</code> class. This class may be instantiated anywhere you may place <code>the_author()</code>
52
+ or everywhere if the post ID is provided to the constructor. The instantiated class has the following methods:
53
+
54
+ 1. <code>iterate()</code>: advances <code>$authordata</code> to the next co-author; returns <code>false</code> and restores the original <code>$authordata</code> if there are no more authors to iterate.
55
+ 1. <code>get_position()</code>: returns the zero-based index of the current author; returns -1 if the iterator is invalid
56
+ 1. <code>is_last()</code>: returns <code>true</code> if the current author is the last
57
+ 1. <code>is_first()</code>: returns <code>true</code> if the current author is the first
58
+ 1. <code>count()</code>: returns the total number of authors
59
+ 1. <code>get_all()</code>: returns an array of all of the authors' user data
60
+
61
+ For example:
62
+
63
+ $i = new CoAuthorsIterator();
64
+ print $i->count() == 1 ? 'Author: ' : 'Authors: ';
65
+ $i->iterate();
66
+ the_author();
67
+ while($i->iterate()){
68
+ print $i->is_last() ? ' and ' : ', ';
69
+ the_author();
70
+ }
71
+
72
+
73
+ = Changelog =
74
+
75
+ *2009-04-23 / 1.1.3*
76
+
77
+ * Add blur event to disable input box
78
+ * Limit only one edit at a time.
79
+ * Checked basic cross-browser compatibility (Firefox 3 OS X, Safari 3 OS X, IE7 Vista).
80
+ * Add suggest javascript plugin to Edit Page.
81
+
82
+ *2009-04-19 / 1.1.2*
83
+
84
+ * Disabled form submit when enter pressed.
85
+
86
+ *2009-04-15 / 1.1.1*
87
+
88
+ * Changed SQL query to return only contributer-level and above users.
89
+
90
+ *2009-04-14: 1.1.0*
91
+
92
+ * Initial release.
93
+
94
+
95
+ == Installation ==
96
+
97
+ 1. Extract the coauthors-plus.zip file and upload its contents to the `/wp-content/plugins/` directory. Alternatively you can install directly from the Plugin directory within your WordPress Install.
98
+ 1. Activate the plugin through the 'Plugins' menu in WordPress.
99
+ 1. Place the appropriate coauthors template tags in your template.
100
+ 1. Add coauthors to your posts and pages.
101
+
102
+
103
+ == Frequently Asked Questions ==
104
+
105
+ = When will the "New Author" function be added? =
106
+
107
+ Hopefully soon.
108
+
109
+ = What happens to posts and pages when I delete a user assigned to a post or page as a coauthor? =
110
+
111
+ When a user is deleted from WordPress, they will be removed from all of posts for which they are co-authors, and if a replacement user is provided, their co-authored posts will instead be co-attributed to another user.
112
+
113
+ == Screenshots ==
114
+ 1. "Post Author(s)" box with multiple authors added
115
+ 2. Search-as-you-type input box that looks up authors as you type in their name.
trunk/screenshot-1.png ADDED
Binary file
trunk/screenshot-2.png ADDED
Binary file
trunk/suggest.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Bootstrap file for getting the ABSPATH constant to wp-load.php
4
+ * This is requried when a plugin requires access not via the admin screen.
5
+ *
6
+ * If the wp-load.php file is not found, then an error will be displayed
7
+ *
8
+ * @package WordPress
9
+ * @since Version 2.6
10
+ */
11
+
12
+ /** Define the server path to the file wp-config here, if you placed WP-CONTENT outside the classic file structure */
13
+
14
+ $path = ''; // It should be end with a trailing slash
15
+
16
+ /** That's all, stop editing from here **/
17
+
18
+ if ( !defined('WP_LOAD_PATH') ) {
19
+
20
+ /** classic root path if wp-content and plugins is below wp-config.php */
21
+ $classic_root = dirname(dirname(dirname(dirname(__FILE__)))) . '/' ;
22
+
23
+ if (file_exists( $classic_root . 'wp-load.php') )
24
+ define( 'WP_LOAD_PATH', $classic_root);
25
+ else
26
+ if (file_exists( $path . 'wp-load.php') )
27
+ define( 'WP_LOAD_PATH', $path);
28
+ else
29
+ exit("Could not find wp-load.php");
30
+ }
31
+
32
+ // let's load WordPress
33
+ require_once( WP_LOAD_PATH . 'wp-load.php');
34
+
35
+ function coauthor_ajax_suggest() {
36
+
37
+ global $wpdb;
38
+
39
+ $q = '%'.strtolower($_REQUEST["q"]).'%';
40
+ if (!$q) return;
41
+
42
+ //
43
+ $authors_query = $wpdb->prepare("SELECT ID, display_name, user_email
44
+ FROM $wpdb->users
45
+ WHERE ID = ANY (SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'wp_user_level' AND meta_value >= 1)
46
+ AND (user_login LIKE %s
47
+ OR user_nicename LIKE %s
48
+ OR display_name LIKE %s
49
+ OR user_email LIKE %s)",$q,$q,$q,$q
50
+ );
51
+
52
+ // $query = "SELECT * FROM $wpdb->users WHERE ID = ANY (SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'wp_capabilities' AND meta_value RLIKE $this_role) ORDER BY user_nicename ASC LIMIT 10000";
53
+
54
+
55
+ $authors = $wpdb->get_results($authors_query, ARRAY_A);
56
+
57
+ if(is_array($authors)) {
58
+ foreach ($authors as $author) {
59
+
60
+ echo $author['ID']." | ". $author['display_name'] ." | ".$author['user_email'] ."\n";
61
+ }
62
+ }
63
+ echo "New | Add new author: ".trim($q,'%')."\n";
64
+ }
65
+
66
+ // Make sure that user is logged in; we don't want to enable direct access
67
+ get_currentuserinfo();
68
+ global $user_level;
69
+ if ($user_level >= 7) coauthor_ajax_suggest();