diff --git a/css/style.css b/css/style.css index 6fd0162..6c28d37 100644 --- a/css/style.css +++ b/css/style.css @@ -360,8 +360,9 @@ button.follow:hover, button.unfollow:hover, .following-list button.private:hover top: 45px; right: 10px; width: 250px; - box-shadow: 0 2px 5px #65686f; border: solid 1px rgba( 69, 71, 77, .1 ); + border-right: solid 6px rgba( 227, 79, 66, .82 ); + box-shadow: 8px 10px 15px 0px rgba(0,0,0, .3); } .dialog-modal:after { @@ -393,7 +394,7 @@ button.follow:hover, button.unfollow:hover, .following-list button.private:hover .userMenu-search-sugestions a:hover, .userMenu-search-profiles li:hover a { - background: #fefef1; + background: #fefedf; } .userMenu-search-profiles button { @@ -618,6 +619,11 @@ button.follow:hover, button.unfollow:hover, .following-list button.private:hover padding: 4px; font-size: 13px; } + +.post-area-new textarea:focus { + border: solid 1px rgba( 227, 79, 66, .5 ); +} + .mini-profile .post-area-new { padding: 9px; @@ -630,8 +636,6 @@ button.follow:hover, button.unfollow:hover, .following-list button.private:hover .post-area-new.open textarea { height: 80px; - border: solid 1px rgba( 227, 79, 66, .5 ); - box-shadow: 0 0 10px rgba(0, 0, 0, .3 ); } textarea.splited-post { box-shadow: none!important; @@ -903,19 +907,17 @@ ol.toptrends-list { width: 5px; /*right: -5px;*/ } -.post:hover, -.post .post -{ - background: #fefef1; -} + .post:hover { + background: #fefedf; cursor: pointer; } -.post.open:hover -{ - background: #fff; + +.post .expanded-post .original { + background: #fefedf; } + .post-photo, .mini-profile-photo { @@ -1351,7 +1353,7 @@ ol.toptrends-list { left: 50%; height: 80%; margin-left: -290px; - box-shadow: 0 0 30px rgba( 0, 0, 0, .6 ); + box-shadow: 10px 12px 18px 0px rgba(0,0,0, .3); background: rgba( 255, 255,255, 1.0 ); z-index: 3; } @@ -1645,8 +1647,8 @@ ol.toptrends-list { position: fixed; top: 50%; left: 50%; - background: rgba( 255, 255,255, 1.0 ); - box-shadow: 0 0 30px rgba( 0, 0, 0, .6 ); + background: #fff; + box-shadow: 10px 12px 18px 0px rgba(0,0,0, .3); z-index: 5; width: 600px; margin-left:-300px; @@ -2011,44 +2013,31 @@ ol.toptrends-list { right: 8px; } -/* Autocomplite*/ -.textcomplete-wrapper textarea { - display: inline; -} +/************************************* +*********** AUTOCOMPLETING *********** +**************************************/ + ul.dropdown-menu { - position: absolute; - top: 23px; - left: 170px; - z-index: 100; - display: block; - float: left; min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; + padding: 0; + margin: 0; list-style: none; background-color: #fff; - border: 1px solid rgba(0,0,0, .2); - border-radius: 6px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0,0,0, .2); - -moz-box-shadow: 0 5px 10px rgba(0,0,0, .2); - box-shadow: 0 5px 10px rgba(0,0,0, .2); - + border-radius: 0px; + border: solid 1px rgba( 69, 71, 77, .1 ); + border-right: solid 4px rgba( 227, 79, 66, .82 ); + box-shadow: 8px 10px 10px 0px rgba(0,0,0, .2); } -ul.dropdown-menu li { - line-height: 20px; -} -ul.dropdown-menu > li > a { - display: block; +ul.dropdown-menu li { padding: 3px 20px; - clear: both; font: 13px/20px "Open Sans", sans-serif; white-space: nowrap; - -webkit-transition: all 200ms; - -moz-transition: all 200ms; - -ms-transition: all 200ms; - -o-transition: all 200ms; - transition: all 200ms; +} + +ul.dropdown-menu li:hover, +ul.dropdown-menu .active, ul.dropdown-menu .active a { + background-color: #fefedf; + text-decoration: none; + cursor: pointer; } diff --git a/following.html b/following.html index a0f8ec9..72d50c1 100644 --- a/following.html +++ b/following.html @@ -25,6 +25,7 @@ + - + + changeStyle(); + diff --git a/js/calm.js b/js/calm.js index 17e33e3..bfa261a 100644 --- a/js/calm.js +++ b/js/calm.js @@ -28,8 +28,3 @@ $(function(){ }; setTimeout(dhtIndicatorBg, 300); setTimeout(function() {setInterval(dhtIndicatorBg, 2000)}, 400); - - -function homeIntInit () { - setTimeout(mensAutocomplete, 800); -} diff --git a/js/interface_common.js b/js/interface_common.js index 028c180..897df8c 100644 --- a/js/interface_common.js +++ b/js/interface_common.js @@ -798,7 +798,7 @@ function replyTextKeypress(e) { $oldta.on("blur", replyTextKeypress); $oldta.addClass('splited-post'); - tweetForm.find(".textcomplete-wrapper").append($newta); + tweetForm.find(".textcomplete-wrapper").append($newta); // FIXME come find textcomplete-wrapper anywhere in code $newta.val(cp.substr(ci)); $newta.focus(); if ($newta[0].setSelectionRange) @@ -1393,7 +1393,6 @@ function changeStyle() { style = 'theme_nin/css/style.css'; profile = 'theme_nin/css/profile.css'; $.getScript('theme_nin/js/theme_option.js'); - } if(theme == 'calm') @@ -1416,29 +1415,30 @@ function changeStyle() { setTimeout(function(){$(menu).removeAttr('style')}, 0); } -function mensAutocomplete() { - var suggests = []; - - for(var i = 0; i < followingUsers.length; i++){ - if(followingUsers[i] == localStorage.defaultScreenName) continue; - suggests.push(followingUsers[i]); - } - suggests.reverse(); - $('textarea').textcomplete([ - { // html - mentions: suggests, - match: /\B@(\w*)$/, - search: function (term, callback) { - callback($.map(this.mentions, function (mention) { - return mention.indexOf(term) === 0 ? mention : null; - })); - }, - index: 1, - replace: function (mention) { - return '@' + mention + ' '; +function getMentionsForAutoComplete() { + if (defaultScreenName && typeof(followingUsers) !== 'undefined') { + var suggests = followingUsers.slice(); + + if (suggests.indexOf(defaultScreenName) > -1) + suggests.splice(suggests.indexOf(defaultScreenName), 1); + if (suggests.length > 0) { + suggests.sort(); + + return [{ + mentions: suggests, + match: /\B@(\w*)$/, + search: function (term, callback) { + callback($.map(this.mentions, function (mention) { + return mention.indexOf(term) === 0 ? mention : null; + })); + }, + index: 1, + replace: function (mention) { + return '@'+mention+' '; + } + }]; } } -]) } function replaceDashboards() { @@ -1485,10 +1485,6 @@ function initInterfaceCommon() { }); */ - $('.dropdown-menu').on('keydown', function(e){ - e = event || window.event; - e.stopPropagation(); - }) $('.post-text').on('click', 'a', function(e){ e.stopPropagation(); }); @@ -1529,4 +1525,42 @@ function initInterfaceCommon() { $('.bitmessage-ctc').on('click', function(){ window.prompt(polyglot.t('copy_to_clipboard'), $(this).attr('data')) }); + + if (typeof($.fn.textcomplete) === 'function') { + $('textarea') + .on('focus', function () { + var element = this; + // Cursor has not set yet. And wait 100ms to skip global click event. + setTimeout(function () { + // Cursor is ready. + $(element).textcomplete(getMentionsForAutoComplete(), { + 'appendTo': ($(element).parents('.dashboard').length > 0) ? $(element).parent() : $('body'), + 'listPosition': setTextcompleteDropdownListPos + }); + }, 100); + }) + .on('focusout', function () { + $(this).textcomplete('destroy'); + }) + ; + } +} + + +// following workaround function is for calls from $.fn.textcomplete only +// we need this because currently implementation of caret position detection is way too imperfect + +function setTextcompleteDropdownListPos(position) { + position = this._applyPlacement(position); + + if (this.option.appendTo.parents('.dashboard').length > 0) { + position['position'] = 'fixed'; + position['top'] = (parseFloat(position['top']) - window.pageYOffset).toString()+'px'; + } else { + position['position'] = 'absolute'; + } + + this.$el.css(position); + + return this; } diff --git a/js/jquery.textcomplete.js b/js/jquery.textcomplete.js deleted file mode 100644 index 66bed0f..0000000 --- a/js/jquery.textcomplete.js +++ /dev/null @@ -1,554 +0,0 @@ -/*! - * jQuery.textcomplete.js - * - * Repositiory: https://github.com/yuku-t/jquery-textcomplete - * License: MIT - * Author: Yuku Takahashi - */ - -;(function ($) { - - 'use strict'; - - /** - * Exclusive execution control utility. - */ - var lock = function (func) { - var free, locked; - free = function () { locked = false; }; - return function () { - var args; - if (locked) return; - locked = true; - args = toArray(arguments); - args.unshift(free); - func.apply(this, args); - }; - }; - - /** - * Convert arguments into a real array. - */ - var toArray = function (args) { - var result; - result = Array.prototype.slice.call(args); - return result; - }; - - /** - * Get the styles of any element from property names. - */ - var getStyles = (function () { - var color; - color = $('
').css(['color']).color; - if (typeof color !== 'undefined') { - return function ($el, properties) { - return $el.css(properties); - }; - } else { // for jQuery 1.8 or below - return function ($el, properties) { - var styles; - styles = {}; - $.each(properties, function (i, property) { - styles[property] = $el.css(property); - }); - return styles; - }; - } - })(); - - /** - * Default template function. - */ - var identity = function (obj) { return obj; }; - - /** - * Memoize a search function. - */ - var memoize = function (func) { - var memo = {}; - return function (term, callback) { - if (memo[term]) { - callback(memo[term]); - } else { - func.call(this, term, function (data) { - memo[term] = (memo[term] || []).concat(data); - callback.apply(null, arguments); - }); - } - }; - }; - - /** - * Determine if the array contains a given value. - */ - var include = function (array, value) { - var i, l; - if (array.indexOf) return array.indexOf(value) != -1; - for (i = 0, l = array.length; i < l; i++) { - if (array[i] === value) return true; - } - return false; - }; - - /** - * Textarea manager class. - */ - var Completer = (function () { - var html, css, $baseWrapper, $baseList, _id; - - html = { - wrapper: '', - list: ' ' - }; - css = { - wrapper: { - position: 'relative' - }, - list: { - position: 'absolute', - top: 0, - left: 0, - zIndex: '100', - display: 'none' - } - }; - $baseWrapper = $(html.wrapper).css(css.wrapper); - $baseList = $(html.list).css(css.list); - _id = 0; - - function Completer($el) { - var focus; - this.el = $el.get(0); // textarea element - focus = this.el === document.activeElement; - // Cannot wrap $el at initialize method lazily due to Firefox's behavior. - this.$el = wrapElement($el); // Focus is lost - this.id = 'textComplete' + _id++; - this.strategies = []; - if (focus) { - this.initialize(); - this.$el.focus(); - } else { - this.$el.one('focus.textComplete', $.proxy(this.initialize, this)); - } - } - - /** - * Completer's public methods - */ - $.extend(Completer.prototype, { - - /** - * Prepare ListView and bind events. - */ - initialize: function () { - var $list, globalEvents; - $list = $baseList.clone(); - this.listView = new ListView($list, this); - this.$el - .before($list) - .on({ - 'keyup.textComplete': $.proxy(this.onKeyup, this), - 'keydown.textComplete': $.proxy(this.listView.onKeydown, - this.listView) - }); - globalEvents = {}; - globalEvents['click.' + this.id] = $.proxy(this.onClickDocument, this); - globalEvents['keyup.' + this.id] = $.proxy(this.onKeyupDocument, this); - $(document).on(globalEvents); - }, - - /** - * Register strategies to the completer. - */ - register: function (strategies) { - this.strategies = this.strategies.concat(strategies); - }, - - /** - * Show autocomplete list next to the caret. - */ - renderList: function (data) { - if (this.clearAtNext) { - this.listView.clear(); - this.clearAtNext = false; - } - if (data.length) { - if (!this.listView.shown) { - this.listView - .setPosition(this.getCaretPosition()) - .clear() - .activate(); - this.listView.strategy = this.strategy; - } - data = data.slice(0, this.strategy.maxCount); - this.listView.render(data); - } - - if (!this.listView.data.length && this.listView.shown) { - this.listView.deactivate(); - } - }, - - searchCallbackFactory: function (free) { - var self = this; - return function (data, keep) { - self.renderList(data); - if (!keep) { - // This is the last callback for this search. - free(); - self.clearAtNext = true; - } - }; - }, - - /** - * Keyup event handler. - */ - onKeyup: function (e) { - var searchQuery, term; - if (this.skipSearch(e)) { return; } - - searchQuery = this.extractSearchQuery(this.getTextFromHeadToCaret()); - if (searchQuery.length) { - term = searchQuery[1]; - if (this.term === term) return; // Ignore shift-key or something. - this.term = term; - this.search(searchQuery); - } else { - this.term = null; - this.listView.deactivate(); - } - }, - - /** - * Suppress searching if it returns true. - */ - skipSearch: function (e) { - if (this.skipNextKeyup) { - this.skipNextKeyup = false; - return true; - } - switch (e.keyCode) { - case 40: - case 38: - return true; - } - }, - - onSelect: function (value) { - var pre, post, newSubStr; - pre = this.getTextFromHeadToCaret(); - post = this.el.value.substring(this.el.selectionEnd); - - newSubStr = this.strategy.replace(value); - if ($.isArray(newSubStr)) { - post = newSubStr[1] + post; - newSubStr = newSubStr[0]; - } - pre = pre.replace(this.strategy.match, newSubStr); - this.$el.val(pre + post) - .trigger('change') - .trigger('textComplete:select', value); - this.el.focus(); - this.el.selectionStart = this.el.selectionEnd = pre.length; - this.skipNextKeyup = true; - }, - - /** - * Global click event handler. - */ - onClickDocument: function (e) { - if (e.originalEvent && !e.originalEvent.keepTextCompleteDropdown) { - this.listView.deactivate(); - } - }, - - /** - * Global keyup event handler. - */ - onKeyupDocument: function (e) { - if (this.listView.shown && e.keyCode === 27) { // ESC - this.listView.deactivate(); - this.$el.focus(); - } - }, - - /** - * Remove all event handlers and the wrapper element. - */ - destroy: function () { - var $wrapper; - this.$el.off('.textComplete'); - $(document).off('.' + this.id); - if (this.listView) { this.listView.destroy(); } - $wrapper = this.$el.parent(); - $wrapper.after(this.$el).remove(); - this.$el.data('textComplete', void 0); - this.$el = null; - }, - - // Helper methods - // ============== - - /** - * Returns caret's relative coordinates from textarea's left top corner. - */ - getCaretPosition: function () { - // Browser native API does not provide the way to know the position of - // caret in pixels, so that here we use a kind of hack to accomplish - // the aim. First of all it puts a div element and completely copies - // the textarea's style to the element, then it inserts the text and a - // span element into the textarea. - // Consequently, the span element's position is the thing what we want. - - if (this.el.selectionEnd === 0) return; - var properties, css, $div, $span, position, dir; - - dir = this.$el.attr('dir') || this.$el.css('direction'); - properties = ['border-width', 'font-family', 'font-size', 'font-style', - 'font-variant', 'font-weight', 'height', 'letter-spacing', - 'word-spacing', 'line-height', 'text-decoration', 'text-align', - 'width', 'padding-top', 'padding-right', 'padding-bottom', - 'padding-left', 'margin-top', 'margin-right', 'margin-bottom', - 'margin-left' - ]; - css = $.extend({ - position: 'absolute', - overflow: 'auto', - 'white-space': 'pre-wrap', - top: 0, - left: -9999, - direction: dir - }, getStyles(this.$el, properties)); - - $div = $('').css(css).text(this.getTextFromHeadToCaret()); - $span = $('').text('.').appendTo($div); - this.$el.before($div); - position = $span.position(); - position.top += $span.height() - this.$el.scrollTop(); - if (dir === 'rtl') { position.left -= this.listView.$el.width(); } - $div.remove(); - return position; - }, - - getTextFromHeadToCaret: function () { - var text, selectionEnd, range; - selectionEnd = this.el.selectionEnd; - if (typeof selectionEnd === 'number') { - text = this.el.value.substring(0, selectionEnd); - } else if (document.selection) { - range = this.el.createTextRange(); - range.moveStart('character', 0); - range.moveEnd('textedit'); - text = range.text; - } - return text; - }, - - /** - * Parse the value of textarea and extract search query. - */ - extractSearchQuery: function (text) { - // If a search query found, it returns used strategy and the query - // term. If the caret is currently in a code block or search query does - // not found, it returns an empty array. - - var i, l, strategy, match; - for (i = 0, l = this.strategies.length; i < l; i++) { - strategy = this.strategies[i]; - match = text.match(strategy.match); - if (match) { return [strategy, match[strategy.index]]; } - } - return []; - }, - - search: lock(function (free, searchQuery) { - var term; - this.strategy = searchQuery[0]; - term = searchQuery[1]; - this.strategy.search(term, this.searchCallbackFactory(free)); - }) - }); - - /** - * Completer's private functions - */ - var wrapElement = function ($el) { - return $el.wrap($baseWrapper.clone().css('display', $el.css('display'))); - }; - - return Completer; - })(); - - /** - * Dropdown menu manager class. - */ - var ListView = (function () { - - function ListView($el, completer) { - this.data = []; - this.$el = $el; - this.index = 0; - this.completer = completer; - - this.$el.on('click.textComplete', 'li.textcomplete-item', - $.proxy(this.onClick, this)); - } - - $.extend(ListView.prototype, { - shown: false, - - render: function (data) { - var html, i, l, index, val; - - html = ''; - for (i = 0, l = data.length; i < l; i++) { - val = data[i]; - if (include(this.data, val)) continue; - index = this.data.length; - this.data.push(val); - html += '