<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[1957] sites/trunk: Trac: Add autocomplete for usernames and attachments.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/1957">1957</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/1957","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>ocean90</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-10-10 21:25:06 +0000 (Sat, 10 Oct 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Trac: Add autocomplete for usernames and attachments.

For now the list of usernames includes users who have commented to the ticket. Core Trac includes also committers.

Props helen, johnbillion, DrewAPicture, ocean90.
See <a href="http://meta.trac.wordpress.org/ticket/830">#830</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunktracwordpressorgtemplatescoresitespecifichtml">sites/trunk/trac.wordpress.org/templates/core/site-specific.html</a></li>
<li><a href="#sitestrunktracwordpressorgtemplatessitehtml">sites/trunk/trac.wordpress.org/templates/site.html</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlstyletracwptraccss">sites/trunk/wordpress.org/public_html/style/trac/wp-trac.css</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlstyletracwptracjs">sites/trunk/wordpress.org/public_html/style/trac/wp-trac.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunktracwordpressorgtemplatescoresitespecifichtml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/trac.wordpress.org/templates/core/site-specific.html</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/trac.wordpress.org/templates/core/site-specific.html  2015-10-10 21:20:35 UTC (rev 1956)
+++ sites/trunk/trac.wordpress.org/templates/core/site-specific.html    2015-10-10 21:25:06 UTC (rev 1957)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50,6 +50,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">        duck_: 'Core Committer'
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+var wpTracAutoCompleteUsers = {
+       include: $.map( wpTracContributorLabels, function( v, k ) { return k } ),
+       exclude: [
+               'slackbot',
+               'ircbot',
+       ]
+};
+
</ins><span class="cx" style="display: block; padding: 0 10px"> </script>
</span><span class="cx" style="display: block; padding: 0 10px"> </body>
</span><span class="cx" style="display: block; padding: 0 10px"> </html>
</span></span></pre></div>
<a id="sitestrunktracwordpressorgtemplatessitehtml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/trac.wordpress.org/templates/site.html</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/trac.wordpress.org/templates/site.html        2015-10-10 21:20:35 UTC (rev 1956)
+++ sites/trunk/trac.wordpress.org/templates/site.html  2015-10-10 21:25:06 UTC (rev 1957)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -299,7 +299,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">        var wpBugGardener = true;
</span><span class="cx" style="display: block; padding: 0 10px">        </script>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script py:if="req.authname">
+       var wpTracCurrentUser = "${req.authname}";
+       </script>
+
</ins><span class="cx" style="display: block; padding: 0 10px">         <!--! JavaScript -->
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script src="//s.w.org/style/trac/jquery.caret.min.js?ver=2015-02-01"></script>
+       <script src="//s.w.org/style/trac/jquery.atwho.min.js?ver=1.0.1"></script>
</ins><span class="cx" style="display: block; padding: 0 10px">         <script src="//s.w.org/style/trac/wp-trac.js?${scripts_version}"></script>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <!--! Check for security buzzwords on new tickets -->
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlstyletracwptraccss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/style/trac/wp-trac.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/style/trac/wp-trac.css      2015-10-10 21:20:35 UTC (rev 1956)
+++ sites/trunk/wordpress.org/public_html/style/trac/wp-trac.css        2015-10-10 21:25:06 UTC (rev 1957)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1648,6 +1648,73 @@
</span><span class="cx" style="display: block; padding: 0 10px">        display: none;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * Autocomplete via At.js.
+ */
+
+.atwho-container {
+       font-size: 1.3em
+}
+
+.atwho-view {
+       position: absolute;
+       top: 0;
+       left: 0;
+       display: none;
+       margin-top: 18px;
+       background: #fff;
+       color: black;
+       border: 1px solid #ccc;
+       box-shadow: 0 1px 2px rgba(0,0,0,0.1);
+       min-width: 120px;
+       max-height: 200px;
+       overflow: auto;
+       z-index: 11110 !important;
+}
+
+.atwho-view .cur {
+       background: #0073aa;
+       color: #fff;
+}
+
+.atwho-view .cur small {
+       color: #fff;
+}
+
+.atwho-view strong {
+       color: #0073aa;
+}
+
+.atwho-view .cur strong {
+       color: #fff;
+       font: bold;
+}
+
+.atwho-view ul {
+       /* width: 100px; */
+       list-style: none;
+       padding: 0;
+       margin: auto;
+}
+
+.atwho-view ul li {
+       display: block;
+       padding: 5px 10px;
+       border-bottom: 1px solid #ccc;
+       cursor: pointer;
+}
+
+.atwho-view ul li:last-child {
+       border-bottom: 0;
+}
+
+.atwho-view small {
+       font-size: smaller;
+       color: #777;
+       font-weight: normal;
+}
+
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /* =Responsive / Mobile
</span><span class="cx" style="display: block; padding: 0 10px"> ----------------------------------------------- */
</span><span class="cx" style="display: block; padding: 0 10px"> @media (max-width: 770px) {
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlstyletracwptracjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/style/trac/wp-trac.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/style/trac/wp-trac.js       2015-10-10 21:20:35 UTC (rev 1956)
+++ sites/trunk/wordpress.org/public_html/style/trac/wp-trac.js 2015-10-10 21:25:06 UTC (rev 1957)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43,6 +43,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        wpTrac = {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                gardener: typeof wpBugGardener !== 'undefined',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                currentUser: wpTracCurrentUser,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                init: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        wpTrac.hacks();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -54,6 +55,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                wpTrac.showContributorLabels( wpTracContributorLabels );
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        wpTrac.autocomplete.init();
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         if ( ! $(document.body).hasClass( 'plugins' ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                wpTrac.workflow.init();
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( $(document.body).hasClass( 'core' ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -73,6 +76,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // These ticket hacks need to be re-run after ticket previews.
</span><span class="cx" style="display: block; padding: 0 10px">                postPreviewHacks: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        // Automatically preview images.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -411,6 +415,89 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                autocomplete: (function() {
+                       var users,
+                               attachments,
+                               settings = {};
+
+                       return {
+                               init: function() {
+                                       if ( ! $( '#comment' ).length ) {
+                                               return;
+                                       }
+
+                                       if ( 'undefined' !== typeof wpTracAutoCompleteUsers ) {
+                                               settings = wpTracAutoCompleteUsers;
+                                       }
+
+                                       users = this.getUsers();
+                                       attachments  = this.getAttachments();
+
+                                       $( '#comment' ).atwho({
+                                               at:  '@',
+                                               data: users
+                                       }).atwho({
+                                               at: '[att',
+                                               insertTpl: '${atwho-at}achment:${name}]',
+                                               displayTpl: '<li>${display}</li>',
+                                               data: attachments
+                                       });
+                               },
+
+                               getUsers: function() {
+                                       var users  = [], exclude = [];
+
+                                       if ( 'undefined' !== settings.exclude ) {
+                                               exclude = settings.exclude;
+                                       }
+
+                                       // Most recent should show up first.
+                                       $( $( '.change .username' ).get().reverse() ).each( function() {
+                                               var username = $(this).data( 'username' );
+                                               if (
+                                                       typeof username !== 'undefined' &&
+                                                       -1 === $.inArray( username, users ) &&
+                                                       -1 === $.inArray( username, exclude )
+                                               ) {
+                                                       users.push( $(this).data( 'username' ) );
+                                               }
+                                       });
+
+                                       // Add additional users.
+                                       if ( 'undefined' !== typeof settings.include ) {
+                                               $.each( settings.include, function( k, username ) {
+                                                       if ( -1 === $.inArray( username, users ) ) {
+                                                               users.push( username );
+                                                       }
+                                               });
+                                       }
+
+                                       // Exclude current user.
+                                       if ( 'undefined' !== wpTrac.currentUser ) {
+                                               users = $.grep( users, function( user ) {
+                                                       return user != wpTrac.currentUser;
+                                               });
+                                       }
+
+                                       return users;
+                               },
+
+                               getAttachments: function() {
+                                       var attachments = [];
+
+                                       // Most recent should show up first.
+                                       $ ($( 'dl.attachments dt' ).get().reverse() ).each( function() {
+                                               attachments.push({
+                                                       display: $( this ).text(),
+                                                       name: $( this ).find( 'a[title="View attachment"]' ).text()
+                                               });
+                                       });
+
+                                       return attachments;
+                               }
+                       };
+               }()),
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 workflow: (function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var keywords = {},
</span><span class="cx" style="display: block; padding: 0 10px">                                originalKeywords = {},
</span></span></pre>
</div>
</div>

</body>
</html>