That's a good question. Given your requirements, I don't see much choices left on how to proceed. As ThatBlairGuy suggested, a bit map seems to be the way to go. Your 300 choices translate to 300 bits. Now I personally would stick to use only 6 bits per byte, to make a quick and easy translation to base64, for storage purpose. 300 / 6 = 50 characters for the values coming from the drop-down.
The value of any preference has to be hardcoded for good though, you can't remove or add any in the middle: Any new preference will have to be added at the end of the bit map, or use a bit that is no longer used somewhere in the map.
Edit: Given the comments re. bit map, I will flesh out what I had in mind for the implementation. Assuming a bit, each corresponding to a off-on switch of a particular option (an entry in the drop-box):
this.bitmap = [];
this.customBase64code="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-";
...
// index=index of bit within bit map, on=state of the bit
this.setOption=function(index,on) {
var islot = Math.floor(index / 6);
var ibit = index % 6;
if ( this.bitmap[islot] === undefined ) {
while ( this.bitmap.length <= islot ) {
this.bitmap.push(0);
}
}
if (on) {
this.bitmap[islot] |= (1 << ibit);
}
else {
this.bitmap[islot] &= ~(1 << ibit);
}
};
this.getOption=function(index) {
var islot = Math.floor(index / 6);
if ( this.bitmap[islot] === undefined ) {
return 0;
}
return this.bitmap[islot] & (1 << (index % 6));
};
this.getStringFromOptions=function() {
var bitmap64 = [];
var encoder64 = customBase64code.split('');
var n = this.bitmap.length;
for ( var i = 0; i < n; i++ ) {
bitmap64.push(encoder64[this.bitmap[i]]);
}
return bitmap64.join('');
};
this.getOptionsFromString=function(s) {
var bitmap64 = s.split('');
var decoder64 = this.customBase64code;
var n = bitmap64.length;
for ( var i = 0; i < n; i++ ) {
this.bitmap.push(decoder64.indexOf(bitmap64[i]));
}
};
Disclaimer: I didn't test any of the above.