Opened 15 years ago
Last modified 11 years ago
#9310 new enhancement
Allow cookies be set for textarea heights upon resize and restore upon document load
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | normal | Milestone: | next-major-releases |
Component: | general | Version: | 0.12dev |
Severity: | trivial | Keywords: | |
Cc: | Jun Omae | Branch: | |
Release Notes: | |||
API Changes: | |||
Internal Changes: |
Description
This basically involves incorporating the jquery plugin for handling cookies.
The patch is rather simple. See the attached jquery_cookies.js which must be included with trac/htdocs/js/.
Here is the original project page for reference:
http://plugins.jquery.com/project/cookie
-
htdocs/js/resizer.js
5 5 var textarea = $(this); 6 6 var offset = null; 7 7 8 function getCookieName(textarea) { 9 if (textarea.attr("id")) { 10 return "trac." + textarea.attr("id"); 11 } 12 else if (textarea.attr("name")) { 13 return "trac." + textarea.attr("name"); 14 } 15 } 16 8 17 function beginDrag(e) { 9 18 offset = textarea.height() - e.pageY; 10 19 textarea.blur(); … … 18 27 } 19 28 20 29 function endDrag(e) { 30 // set cookie for permanently storing information 31 // on the height of the resizable, if possible 32 name = getCookieName(textarea); 33 if (name) { 34 $.cookie(name, textarea.height(), ( new Date() ).getTime() + 1000000); 35 } 21 36 textarea.focus(); 22 37 $(document).unbind('mousemove', dragging).unbind('mouseup', endDrag); 23 38 } … … 27 42 .parent().append(grip); 28 43 grip.style.marginLeft = (this.offsetLeft - grip.offsetLeft) + 'px'; 29 44 grip.style.marginRight = (grip.offsetWidth - this.offsetWidth) +'px'; 45 46 // restore height from cookie, if avail 47 var height = 0; 48 var name = getCookieName(textarea); 49 if (name) 50 { 51 height = $.cookie(name) 52 } 53 textarea.height(Math.max(32, height)); 30 54 }); 31 55 }); 56 -
web/chrome.py
522 522 add_link(req, 'help', req.href.wiki('TracGuide')) 523 523 add_stylesheet(req, 'common/css/trac.css') 524 524 add_script(req, 'common/js/jquery.js') 525 add_script(req, 'common/js/jquery_cookies.js') 525 526 # Only activate noConflict mode if requested to by the handler 526 527 if handler is not None and \ 527 528 getattr(handler.__class__, 'jquery_noconflict', False):
BTW Thanks for incorporating this, it makes using trac a lot more easier.
Attachments (1)
Change History (27)
by , 15 years ago
Attachment: | jquery_cookies.js added |
---|
comment:1 by , 15 years ago
Issues might be raised on non secure cookies set by the above provided patch. So additional tests must be run in order to make it work under all conditions, e.g. ie8+ requires secure cookie domains and so on.
comment:2 by , 15 years ago
*Sigh*, the patch is missing a semicolon in line 51 on height = $.cookie(name). However, since it is the sole statement in that block it eventually works just fine. Feel free to add missing punctuation at your own expense ;)
comment:3 by , 15 years ago
Milestone: | → 0.12.1 |
---|---|
Owner: | set to |
Good idea! It would be great if you could complete and test the implementation according to your concerns in comment:1.
Also, you don't really need getCookieName()
. Just calculate the name once at the top level and store the result in a local, the same as textarea
. And the expires
argument to $.cookie()
can be a number of days, so you don't have to make the calculation yourself. Finally, I would add the jquery_cookies.js
script in Chrome.add_textarea_grips()
instead of including it unconditionally.
follow-up: 8 comment:4 by , 15 years ago
Nice of you. I will look further into this. As of now, all cookies established by the above patch are still session bound, so that the setting will be lost on user agent exit.
I will revise the patch according to your input.
Apart from that, I would rather see the cookies plugin be available on a general basis, and not just on add_text_area_grips(), because that would add extra functionality to 3rd party plugins, don't you think?
Besides, providing a compressed version of the plugin would reduce overall bandwidth, also.
follow-up: 7 comment:5 by , 15 years ago
Reconsidering this, perhaps make this an additional call to the chrome api, e.g. add_cookies_support() or something like that.
comment:6 by , 15 years ago
regarding comment:1 - i do not have nor run windows except for gaming purposes ;)
comment:7 by , 15 years ago
Replying to Carsten Klein <carsten.klein@…>:
Reconsidering this, perhaps make this an additional call to the chrome api, e.g. add_cookies_support() or something like that.
Macros would definitely require this, i presume. So, the cookies should be available by default, since AFAIK the macros cannot instruct chrome to add support for cookies, or am I wrong?
comment:8 by , 15 years ago
Replying to Carsten Klein <carsten.klein@…>:
Apart from that, I would rather see the cookies plugin be available on a general basis, and not just on add_text_area_grips(), because that would add extra functionality to 3rd party plugins, don't you think?
Plugins are free to add_script(req, 'common/js/jquery_cookies.js')
if they need it. jQuery (core) is only included unconditionally because virtually all pages need it.
comment:9 by , 14 years ago
How many days would be appropriate for the cookie to remain valid?
Or should the cookie be refreshed on every load of the page so that it will remain valid for at least 365 days, and if the user once again opens the page, it will be refreshed so that it will remain valid for the next 365 days?
comment:10 by , 14 years ago
Here is a corrected version of the patch. It will automatically refresh existing cookies so that on page load the lifetime of the cookie will be extended even if the user does not alter the height property of the textareas on that page.
In addition, only those request handlers that require the jquery_cookies.js plugin to be present will include it. Basically this could be done on the template level, also. However, since genshi processing overhead is still subject to discussion, it is included directly in the respective request handler's handle_request() methods.
The naming of the individual cookies is subject to discussion, since the data must be transferred to the server and back shorter names would actually make sense here.
-
trac/ticket/web_ui.py
163 163 return True 164 164 165 165 def process_request(self, req): 166 167 add_script(req, 'common/js/jquery_cookies.js') 168 166 169 if 'id' in req.args: 167 170 if req.path_info == '/newticket': 168 171 raise TracError(_("id can't be set for a new ticket request.")) -
trac/ticket/roadmap.py
581 582 milestone.name = milestone_id 582 583 action = 'edit' # rather than 'new' so that it works for POST/save 583 584 585 add_script(req, 'common/js/jquery_cookies.js') 586 584 587 if req.method == 'POST': 585 588 if req.args.has_key('cancel'): 586 589 if milestone.exists: -
trac/htdocs/js/resizer.js
4 4 $('textarea.trac-resizable').each(function() { 5 5 var textarea = $(this); 6 6 var offset = null; 7 7 var stateCookieName = null; 8 9 if (textarea.attr("id")) { 10 stateCookieName = "trac_ui.textarea." + textarea.attr("id") + ".height"; 11 } 12 else if (textarea.attr("name")) { 13 stateCookieName = "trac_ui.textarea." + textarea.attr("name") + ".height"; 14 } 15 8 16 function beginDrag(e) { 9 17 offset = textarea.height() - e.pageY; 10 18 textarea.blur(); … … 18 26 } 19 27 20 28 function endDrag(e) { 29 // set cookie for permanently storing information 30 // on the height of the resizable, if possible 31 if (stateCookieName) { 32 $.cookie(stateCookieName, textarea.height(), { expires: 365 }); 33 } 21 34 textarea.focus(); 22 35 $(document).unbind('mousemove', dragging).unbind('mouseup', endDrag); 23 36 } … … 27 40 .parent().append(grip); 28 41 grip.style.marginLeft = (this.offsetLeft - grip.offsetLeft) + 'px'; 29 42 grip.style.marginRight = (grip.offsetWidth - this.offsetWidth) +'px'; 43 44 // restore height from cookie, if avail 45 // and refresh cookie so that it stays valid 46 var height = Math.max(32, textarea.height()); 47 if (stateCookieName) { 48 height = $.cookie(stateCookieName); 49 $.cookie(stateCookieName, height, { expires: 365 }); 50 } 51 52 textarea.height(height + 'px'); 30 53 }); 31 54 }); 55 -
trac/admin/web_ui.py
30 30 from trac.util.text import exception_to_unicode 31 31 from trac.util.translation import _, ngettext 32 32 from trac.web import HTTPNotFound, IRequestHandler 33 from trac.web.chrome import add_notice, add_stylesheet, \33 from trac.web.chrome import add_notice, add_stylesheet, add_script, \ 34 34 add_warning, Chrome, INavigationContributor, \ 35 35 ITemplateProvider 36 36 … … 141 141 }) 142 142 143 143 add_stylesheet(req, 'common/css/admin.css') 144 add_script(req, 'common/js/jquery_cookies.js') 145 144 146 return template, data, None 145 147 146 148 # ITemplateProvider methods -
trac/wiki/web_ui.py
126 126 num=version, name=page.name)) 127 127 128 128 add_stylesheet(req, 'common/css/wiki.css') 129 add_script(req, 'common/js/jquery_cookies.js') 129 130 130 131 if req.method == 'POST': 131 132 if action == 'edit':
comment:11 by , 14 years ago
Still untested on IE, though. If someone would step in and test this on IE…
comment:12 by , 14 years ago
Works on
- FireFox 3.5.8+
- Konqueror 4.3.5+
Could someone please test
- Safari (Windows/Mac)
- IE (7/8/9)
- Chrome
- Opera >9
Thanks!
comment:13 by , 14 years ago
Another issue still remains: the number of cookies is restricted by some user agents, with the least denominator being 20 per domain set forth by the original HTTP specification.
So if a user has multiple plugins installed that all include templates that would render resizables, then that number can be exceeded easily, provably resulting in javascript errors.
See http://www.nczonline.net/blog/2009/05/05/http-cookies-explained/ for more information.
In addition to that, each cookie can only be up to 4 KiB in size.
So that leaves us with the question on how we would deal with that.
My proposal would be to either use local storage when available, as is supported by most modern user agents, or implement a wrapper to a cookie store that then would persist user interface settings so that
a) will join multiple cookies using the subcookie approach into one, and b) will distribute cookie data across multiple cookies, so that c) the maximum size of a cookie never exceeds 4 KiB, and
E.g. there exists a "virtual" cookie named "trac.ui.settings", which then is automatically distributed across multiple "trac.ui.settings.0" … "trac.ui.settings.N" cookies. When accessing trac.ui.settings and querying or setting a value in it, the cookie store will instantiate a hash from all instances of "trac.ui.settings.*", and, when persisting information again, it will automatically distribute the data across multiple "trac.ui.settings.*" instances.
For when is 12.1 being scheduled? Maybe we should move this to a later milestone?
follow-up: 15 comment:14 by , 14 years ago
Another option would be to store on the server side, and to update the value on release through an XMLHttpRequest
. This would also allow propagating the stored values when using different browsers / machines.
follow-up: 16 comment:15 by , 14 years ago
Replying to rblank:
Another option would be to store on the server side, and to update the value on release through an
XMLHttpRequest
. This would also allow propagating the stored values when using different browsers / machines.
Well, are you really sure this is a good idea at all? To me, the benefit (if any) doesn't seem worth the trouble of bundling a new dependency and the extra complexity (the user settings would be spread partly in the session, partly in cookies).
follow-ups: 17 18 comment:16 by , 14 years ago
Replying to cboos:
Well, are you really sure this is a good idea at all? To me, the benefit (if any) doesn't seem worth the trouble of bundling a new dependency and the extra complexity (the user settings would be spread partly in the session, partly in cookies).
Actually, I meant dropping the cookie idea altogether and only relying on session data. Use the session data for the initial field heights on page load, and update the setting through xhr on mouse release.
comment:17 by , 14 years ago
Milestone: | 0.12.1 → next-major-0.1X |
---|
Replying to rblank:
Actually, I meant dropping the cookie idea altogether and only relying on session data. Use the session data for the initial field heights on page load,
OK
and update the setting through xhr on mouse release.
That still sounds overkill, only sending the value during a real submit (preview or save) seems good enough.
Anyway, this is not appropriate for 0.12.x, I think.
follow-up: 19 comment:18 by , 14 years ago
Replying to rblank:
Actually, I meant dropping the cookie idea altogether and only relying on session data. Use the session data for the initial field heights on page load, and update the setting through xhr on mouse release.
This is an excellent idea. We could make a request handler for this, e.g. SessionStateHandler which would provide an xhr api to the client for storing and, if required, also for getting session state from the server.
I will look into this during the upcoming weekend and provide a patch.
follow-up: 20 comment:19 by , 14 years ago
Replying to Carsten Klein <carsten.klein@…>:
Problems with such a generic service are:
- cross site scripting attacks (not that much of a problem with simple int values being stored,
but in the long run one might expect other data to be stored as well, once it becomes available)
- data spoofing attacks
- data / script injection attacks
In order to overcome this problem, each XHR request must be guarded using a token. This token could be that of the parent form, provided that this will not invalidate the form token.
Would this be okay with you?
follow-up: 21 comment:20 by , 14 years ago
Replying to Carsten Klein <carsten.klein@…>:
Dunno, but is such a token available on every form in order to prevent XSS?
follow-up: 22 comment:21 by , 14 years ago
Replying to Carsten Klein <carsten.klein@…>:
Dunno, but is such a token available on every form in order to prevent XSS?
Yes, it is. Look for __FORM_TOKEN
. We already pass that for the automatic preview in the wiki and ticket comments.
comment:22 by , 14 years ago
Replying to rblank:
Replying to Carsten Klein <carsten.klein@…>:
Dunno, but is such a token available on every form in order to prevent XSS?
Yes, it is. Look for
__FORM_TOKEN
. We already pass that for the automatic preview in the wiki and ticket comments.
Thanks for the hint.
As far as I can see, form token handling seems ok, but I can see possible attack vectors, thus I will also revise existing form token handling.
comment:23 by , 14 years ago
Long time no input on my behalf. I set this to a low priority for now, since I need to learn more on behalf on both trac+xhr requests. Besides that I got carried away with cookies, so to say. Will definitely look into this in a few weeks.
comment:25 by , 11 years ago
I say we should close this issue and instead focus on using newer technologies than cookies, for example browser integrated SQLite storages and so on.
This, of course, will break with older browser versions, but who cares?
comment:26 by , 11 years ago
Cc: | added |
---|
The jquery cookies plugin