105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
118 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/lib/jquery.ui.resizable.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery UI 1.8pre
3 | *
4 | * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
5 | * Dual licensed under the MIT (MIT-LICENSE.txt)
6 | * and GPL (GPL-LICENSE.txt) licenses.
7 | *
8 | * http://docs.jquery.com/UI
9 | */
10 | (function(c){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.after(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement);return this},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return !this.options.disabled&&f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,e,d){if(this.options.reverseXAxis){var f=this.originalSize,h=this.originalPosition;return{left:h.left-e,width:f.width+e}}else{return{width:this.originalSize.width+e}}},w:function(g,e,d){if(this.options.reverseXAxis){return{width:this.originalSize.width-e}}else{var f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}}},n:function(g,e,d){if(this.options.reverseYAxis){return{height:this.originalSize.height-d}}else{var f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}}},s:function(g,e,d){if(this.options.reverseYAxis){var f=this.originalSize,h=this.originalPosition;return{top:h.top-d,height:f.height+d}}else{return{height:this.originalSize.height+d}}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8pre"});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),h=d.options;var g=function(i){c(i).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(h.alsoResize)=="object"&&!h.alsoResize.parentNode){if(h.alsoResize.length){h.alsoResize=h.alsoResize[0];g(h.alsoResize)}else{c.each(h.alsoResize,function(i,j){g(i)})}}else{g(h.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);
--------------------------------------------------------------------------------
/lib/json2.js:
--------------------------------------------------------------------------------
1 | /*
2 | http://www.JSON.org/json2.js
3 | 2010-03-20
4 |
5 | Public Domain.
6 |
7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8 |
9 | See http://www.JSON.org/js.html
10 |
11 |
12 | This code should be minified before deployment.
13 | See http://javascript.crockford.com/jsmin.html
14 |
15 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
16 | NOT CONTROL.
17 |
18 |
19 | This file creates a global JSON object containing two methods: stringify
20 | and parse.
21 |
22 | JSON.stringify(value, replacer, space)
23 | value any JavaScript value, usually an object or array.
24 |
25 | replacer an optional parameter that determines how object
26 | values are stringified for objects. It can be a
27 | function or an array of strings.
28 |
29 | space an optional parameter that specifies the indentation
30 | of nested structures. If it is omitted, the text will
31 | be packed without extra whitespace. If it is a number,
32 | it will specify the number of spaces to indent at each
33 | level. If it is a string (such as '\t' or ' '),
34 | it contains the characters used to indent at each level.
35 |
36 | This method produces a JSON text from a JavaScript value.
37 |
38 | When an object value is found, if the object contains a toJSON
39 | method, its toJSON method will be called and the result will be
40 | stringified. A toJSON method does not serialize: it returns the
41 | value represented by the name/value pair that should be serialized,
42 | or undefined if nothing should be serialized. The toJSON method
43 | will be passed the key associated with the value, and this will be
44 | bound to the value
45 |
46 | For example, this would serialize Dates as ISO strings.
47 |
48 | Date.prototype.toJSON = function (key) {
49 | function f(n) {
50 | // Format integers to have at least two digits.
51 | return n < 10 ? '0' + n : n;
52 | }
53 |
54 | return this.getUTCFullYear() + '-' +
55 | f(this.getUTCMonth() + 1) + '-' +
56 | f(this.getUTCDate()) + 'T' +
57 | f(this.getUTCHours()) + ':' +
58 | f(this.getUTCMinutes()) + ':' +
59 | f(this.getUTCSeconds()) + 'Z';
60 | };
61 |
62 | You can provide an optional replacer method. It will be passed the
63 | key and value of each member, with this bound to the containing
64 | object. The value that is returned from your method will be
65 | serialized. If your method returns undefined, then the member will
66 | be excluded from the serialization.
67 |
68 | If the replacer parameter is an array of strings, then it will be
69 | used to select the members to be serialized. It filters the results
70 | such that only members with keys listed in the replacer array are
71 | stringified.
72 |
73 | Values that do not have JSON representations, such as undefined or
74 | functions, will not be serialized. Such values in objects will be
75 | dropped; in arrays they will be replaced with null. You can use
76 | a replacer function to replace those with JSON values.
77 | JSON.stringify(undefined) returns undefined.
78 |
79 | The optional space parameter produces a stringification of the
80 | value that is filled with line breaks and indentation to make it
81 | easier to read.
82 |
83 | If the space parameter is a non-empty string, then that string will
84 | be used for indentation. If the space parameter is a number, then
85 | the indentation will be that many spaces.
86 |
87 | Example:
88 |
89 | text = JSON.stringify(['e', {pluribus: 'unum'}]);
90 | // text is '["e",{"pluribus":"unum"}]'
91 |
92 |
93 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
94 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
95 |
96 | text = JSON.stringify([new Date()], function (key, value) {
97 | return this[key] instanceof Date ?
98 | 'Date(' + this[key] + ')' : value;
99 | });
100 | // text is '["Date(---current time---)"]'
101 |
102 |
103 | JSON.parse(text, reviver)
104 | This method parses a JSON text to produce an object or array.
105 | It can throw a SyntaxError exception.
106 |
107 | The optional reviver parameter is a function that can filter and
108 | transform the results. It receives each of the keys and values,
109 | and its return value is used instead of the original value.
110 | If it returns what it received, then the structure is not modified.
111 | If it returns undefined then the member is deleted.
112 |
113 | Example:
114 |
115 | // Parse the text. Values that look like ISO date strings will
116 | // be converted to Date objects.
117 |
118 | myData = JSON.parse(text, function (key, value) {
119 | var a;
120 | if (typeof value === 'string') {
121 | a =
122 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
123 | if (a) {
124 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
125 | +a[5], +a[6]));
126 | }
127 | }
128 | return value;
129 | });
130 |
131 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
132 | var d;
133 | if (typeof value === 'string' &&
134 | value.slice(0, 5) === 'Date(' &&
135 | value.slice(-1) === ')') {
136 | d = new Date(value.slice(5, -1));
137 | if (d) {
138 | return d;
139 | }
140 | }
141 | return value;
142 | });
143 |
144 |
145 | This is a reference implementation. You are free to copy, modify, or
146 | redistribute.
147 | */
148 |
149 | /*jslint evil: true, strict: false */
150 |
151 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
152 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
153 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
154 | lastIndex, length, parse, prototype, push, replace, slice, stringify,
155 | test, toJSON, toString, valueOf
156 | */
157 |
158 |
159 | // Create a JSON object only if one does not already exist. We create the
160 | // methods in a closure to avoid creating global variables.
161 |
162 | if (!this.JSON) {
163 | this.JSON = {};
164 | }
165 |
166 | (function () {
167 |
168 | function f(n) {
169 | // Format integers to have at least two digits.
170 | return n < 10 ? '0' + n : n;
171 | }
172 |
173 | if (typeof Date.prototype.toJSON !== 'function') {
174 |
175 | Date.prototype.toJSON = function (key) {
176 |
177 | return isFinite(this.valueOf()) ?
178 | this.getUTCFullYear() + '-' +
179 | f(this.getUTCMonth() + 1) + '-' +
180 | f(this.getUTCDate()) + 'T' +
181 | f(this.getUTCHours()) + ':' +
182 | f(this.getUTCMinutes()) + ':' +
183 | f(this.getUTCSeconds()) + 'Z' : null;
184 | };
185 |
186 | String.prototype.toJSON =
187 | Number.prototype.toJSON =
188 | Boolean.prototype.toJSON = function (key) {
189 | return this.valueOf();
190 | };
191 | }
192 |
193 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
194 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
195 | gap,
196 | indent,
197 | meta = { // table of character substitutions
198 | '\b': '\\b',
199 | '\t': '\\t',
200 | '\n': '\\n',
201 | '\f': '\\f',
202 | '\r': '\\r',
203 | '"' : '\\"',
204 | '\\': '\\\\'
205 | },
206 | rep;
207 |
208 |
209 | function quote(string) {
210 |
211 | // If the string contains no control characters, no quote characters, and no
212 | // backslash characters, then we can safely slap some quotes around it.
213 | // Otherwise we must also replace the offending characters with safe escape
214 | // sequences.
215 |
216 | escapable.lastIndex = 0;
217 | return escapable.test(string) ?
218 | '"' + string.replace(escapable, function (a) {
219 | var c = meta[a];
220 | return typeof c === 'string' ? c :
221 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
222 | }) + '"' :
223 | '"' + string + '"';
224 | }
225 |
226 |
227 | function str(key, holder) {
228 |
229 | // Produce a string from holder[key].
230 |
231 | var i, // The loop counter.
232 | k, // The member key.
233 | v, // The member value.
234 | length,
235 | mind = gap,
236 | partial,
237 | value = holder[key];
238 |
239 | // If the value has a toJSON method, call it to obtain a replacement value.
240 |
241 | if (value && typeof value === 'object' &&
242 | typeof value.toJSON === 'function') {
243 | value = value.toJSON(key);
244 | }
245 |
246 | // If we were called with a replacer function, then call the replacer to
247 | // obtain a replacement value.
248 |
249 | if (typeof rep === 'function') {
250 | value = rep.call(holder, key, value);
251 | }
252 |
253 | // What happens next depends on the value's type.
254 |
255 | switch (typeof value) {
256 | case 'string':
257 | return quote(value);
258 |
259 | case 'number':
260 |
261 | // JSON numbers must be finite. Encode non-finite numbers as null.
262 |
263 | return isFinite(value) ? String(value) : 'null';
264 |
265 | case 'boolean':
266 | case 'null':
267 |
268 | // If the value is a boolean or null, convert it to a string. Note:
269 | // typeof null does not produce 'null'. The case is included here in
270 | // the remote chance that this gets fixed someday.
271 |
272 | return String(value);
273 |
274 | // If the type is 'object', we might be dealing with an object or an array or
275 | // null.
276 |
277 | case 'object':
278 |
279 | // Due to a specification blunder in ECMAScript, typeof null is 'object',
280 | // so watch out for that case.
281 |
282 | if (!value) {
283 | return 'null';
284 | }
285 |
286 | // Make an array to hold the partial results of stringifying this object value.
287 |
288 | gap += indent;
289 | partial = [];
290 |
291 | // Is the value an array?
292 |
293 | if (Object.prototype.toString.apply(value) === '[object Array]') {
294 |
295 | // The value is an array. Stringify every element. Use null as a placeholder
296 | // for non-JSON values.
297 |
298 | length = value.length;
299 | for (i = 0; i < length; i += 1) {
300 | partial[i] = str(i, value) || 'null';
301 | }
302 |
303 | // Join all of the elements together, separated with commas, and wrap them in
304 | // brackets.
305 |
306 | v = partial.length === 0 ? '[]' :
307 | gap ? '[\n' + gap +
308 | partial.join(',\n' + gap) + '\n' +
309 | mind + ']' :
310 | '[' + partial.join(',') + ']';
311 | gap = mind;
312 | return v;
313 | }
314 |
315 | // If the replacer is an array, use it to select the members to be stringified.
316 |
317 | if (rep && typeof rep === 'object') {
318 | length = rep.length;
319 | for (i = 0; i < length; i += 1) {
320 | k = rep[i];
321 | if (typeof k === 'string') {
322 | v = str(k, value);
323 | if (v) {
324 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
325 | }
326 | }
327 | }
328 | } else {
329 |
330 | // Otherwise, iterate through all of the keys in the object.
331 |
332 | for (k in value) {
333 | if (Object.hasOwnProperty.call(value, k)) {
334 | v = str(k, value);
335 | if (v) {
336 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
337 | }
338 | }
339 | }
340 | }
341 |
342 | // Join all of the member texts together, separated with commas,
343 | // and wrap them in braces.
344 |
345 | v = partial.length === 0 ? '{}' :
346 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
347 | mind + '}' : '{' + partial.join(',') + '}';
348 | gap = mind;
349 | return v;
350 | }
351 | }
352 |
353 | // If the JSON object does not yet have a stringify method, give it one.
354 |
355 | if (typeof JSON.stringify !== 'function') {
356 | JSON.stringify = function (value, replacer, space) {
357 |
358 | // The stringify method takes a value and an optional replacer, and an optional
359 | // space parameter, and returns a JSON text. The replacer can be a function
360 | // that can replace values, or an array of strings that will select the keys.
361 | // A default replacer method can be provided. Use of the space parameter can
362 | // produce text that is more easily readable.
363 |
364 | var i;
365 | gap = '';
366 | indent = '';
367 |
368 | // If the space parameter is a number, make an indent string containing that
369 | // many spaces.
370 |
371 | if (typeof space === 'number') {
372 | for (i = 0; i < space; i += 1) {
373 | indent += ' ';
374 | }
375 |
376 | // If the space parameter is a string, it will be used as the indent string.
377 |
378 | } else if (typeof space === 'string') {
379 | indent = space;
380 | }
381 |
382 | // If there is a replacer, it must be a function or an array.
383 | // Otherwise, throw an error.
384 |
385 | rep = replacer;
386 | if (replacer && typeof replacer !== 'function' &&
387 | (typeof replacer !== 'object' ||
388 | typeof replacer.length !== 'number')) {
389 | throw new Error('JSON.stringify');
390 | }
391 |
392 | // Make a fake root object containing our value under the key of ''.
393 | // Return the result of stringifying the value.
394 |
395 | return str('', {'': value});
396 | };
397 | }
398 |
399 |
400 | // If the JSON object does not yet have a parse method, give it one.
401 |
402 | if (typeof JSON.parse !== 'function') {
403 | JSON.parse = function (text, reviver) {
404 |
405 | // The parse method takes a text and an optional reviver function, and returns
406 | // a JavaScript value if the text is a valid JSON text.
407 |
408 | var j;
409 |
410 | function walk(holder, key) {
411 |
412 | // The walk method is used to recursively walk the resulting structure so
413 | // that modifications can be made.
414 |
415 | var k, v, value = holder[key];
416 | if (value && typeof value === 'object') {
417 | for (k in value) {
418 | if (Object.hasOwnProperty.call(value, k)) {
419 | v = walk(value, k);
420 | if (v !== undefined) {
421 | value[k] = v;
422 | } else {
423 | delete value[k];
424 | }
425 | }
426 | }
427 | }
428 | return reviver.call(holder, key, value);
429 | }
430 |
431 |
432 | // Parsing happens in four stages. In the first stage, we replace certain
433 | // Unicode characters with escape sequences. JavaScript handles many characters
434 | // incorrectly, either silently deleting them, or treating them as line endings.
435 |
436 | text = String(text);
437 | cx.lastIndex = 0;
438 | if (cx.test(text)) {
439 | text = text.replace(cx, function (a) {
440 | return '\\u' +
441 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
442 | });
443 | }
444 |
445 | // In the second stage, we run the text against regular expressions that look
446 | // for non-JSON patterns. We are especially concerned with '()' and 'new'
447 | // because they can cause invocation, and '=' because it can cause mutation.
448 | // But just to be safe, we want to reject all unexpected forms.
449 |
450 | // We split the second stage into 4 regexp operations in order to work around
451 | // crippling inefficiencies in IE's and Safari's regexp engines. First we
452 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
453 | // replace all simple value tokens with ']' characters. Third, we delete all
454 | // open brackets that follow a colon or comma or that begin the text. Finally,
455 | // we look to see that the remaining characters are only whitespace or ']' or
456 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
457 |
458 | if (/^[\],:{}\s]*$/.
459 | test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
460 | replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
461 | replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
462 |
463 | // In the third stage we use the eval function to compile the text into a
464 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
465 | // in JavaScript: it can begin a block or an object literal. We wrap the text
466 | // in parens to eliminate the ambiguity.
467 |
468 | j = eval('(' + text + ')');
469 |
470 | // In the optional fourth stage, we recursively walk the new structure, passing
471 | // each name/value pair to a reviver function for possible transformation.
472 |
473 | return typeof reviver === 'function' ?
474 | walk({'': j}, '') : j;
475 | }
476 |
477 | // If the text is not JSON parseable, then a SyntaxError is thrown.
478 |
479 | throw new SyntaxError('JSON.parse');
480 | };
481 | }
482 | }());
483 |
--------------------------------------------------------------------------------
/lib/user-image-cache/user-image-cache.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2010-2011 Kevin Decker (http://www.incaseofstairs.com/)
3 | * See LICENSE for license information
4 | */
5 | // Specs in use:
6 | // http://www.w3.org/TR/FileAPI/
7 | // http://www.w3.org/TR/webstorage/
8 | var UserImageCache;
9 | (function() {
10 | var curEntry,
11 | remoteProxyUrl,
12 | image;
13 |
14 | // Check for browser support of session storage and that it is accessible
15 | // This may be inaccessible under certain contexts such as file://
16 | function supportsSessionStorage() {
17 | try {
18 | return !!window.sessionStorage;
19 | } catch (err) {
20 | return false;
21 | }
22 | }
23 | var localDataBinding = (function() {
24 | if (supportsSessionStorage()) {
25 | // If they support FileReader they really should support storage... but who knows (With the exception of file://)
26 | return {
27 | count: function() {
28 | return parseInt(sessionStorage.getItem("imageList-count"), 10)||0;
29 | },
30 | lru: function(set) {
31 | if (set) {
32 | sessionStorage.setItem("imageList-lru", set.join(","));
33 | } else {
34 | var lru = sessionStorage.getItem("imageList-lru")||"";
35 | if (!lru) {
36 | return [];
37 | } else {
38 | return lru.split(",");
39 | }
40 | }
41 | },
42 | reset: function() {
43 | var len = this.count()+1;
44 | while (--len) {
45 | sessionStorage.removeItem("imageList-src-" + len);
46 | sessionStorage.removeItem("imageList-display-" + len);
47 | }
48 | sessionStorage.removeItem("imageList-lru");
49 | sessionStorage.removeItem("imageList-count");
50 | },
51 | storeImage: function(name, data) {
52 | var count = this.count(),
53 | entryId = count+1,
54 | lru;
55 |
56 | do {
57 | try {
58 | sessionStorage.setItem("imageList-src-" + entryId, data);
59 | sessionStorage.setItem("imageList-display-" + entryId, name);
60 |
61 | lru = this.lru();
62 | lru.push(entryId);
63 | this.lru(lru);
64 |
65 | break;
66 | } catch (err) {
67 | // Cache filled, remove the least recently used
68 | lru = this.lru();
69 | sessionStorage.removeItem("imageList-src-" + lru[0]);
70 | sessionStorage.removeItem("imageList-display-" + lru[0]);
71 | lru.shift();
72 | this.lru(lru);
73 |
74 | // Also cleanup any data that may have made it in
75 | sessionStorage.removeItem("imageList-src-" + entryId);
76 | sessionStorage.removeItem("imageList-display-" + entryId);
77 |
78 | count--;
79 | }
80 | } while (count > 0);
81 |
82 | sessionStorage.setItem("imageList-count", entryId);
83 | return entryId;
84 | },
85 | getImage: function(entryId) {
86 | var ret = {
87 | src: sessionStorage.getItem("imageList-src-" + entryId),
88 | displayName: sessionStorage.getItem("imageList-display-" + entryId)
89 | };
90 |
91 | var lru = this.lru().filter(function(a) {
92 | return a != entryId;
93 | });
94 | if (ret.src) {
95 | lru.push(entryId);
96 | }
97 | this.lru(lru);
98 |
99 | return ret;
100 | }
101 | };
102 | } else {
103 | // Fail over to plain js structures, meaing that refresh, etc will cause failures.
104 | var cache = [];
105 | return {
106 | reset: function() {
107 | cache = [];
108 | },
109 | storeImage: function(name, data) {
110 | cache.push({ src: data, displayName: name });
111 | return cache.length;
112 | },
113 | getImage: function(entryId) {
114 | return cache[entryId-1];
115 | }
116 | };
117 | }
118 | })();
119 |
120 | UserImageCache = {
121 | NOT_FOUND: "not_found",
122 | UNKNOWN_TYPE: "unknown_type",
123 |
124 | /**
125 | * Determines if local file reads are possible in the current execution environment.
126 | */
127 | isLocalSupported: function() {
128 | try {
129 | return !!window.FileReader;
130 | } catch (err) {
131 | return false;
132 | }
133 | },
134 |
135 | /**
136 | * Retrieves the entry id for the current entry, if one is defined.
137 | * This value may be passed to the load method to reload the image
138 | * if it is still cached.
139 | */
140 | getEntryId: function() { return curEntry && curEntry.entryId; },
141 |
142 | /**
143 | * Retrieves the display name for the current entry, if one is defined.
144 | */
145 | getDisplayName: function() { return curEntry && curEntry.displayName; },
146 |
147 | /**
148 | * Retrieves the src URI for the current entry, if one is defined.
149 | */
150 | getSrc: function() { return curEntry && curEntry.src; },
151 |
152 | /**
153 | * Sets the element that images will be loaded into.
154 | */
155 | setImageEl: function(el) {
156 | image = el;
157 | },
158 |
159 | /*
160 | * Sets the URL of the proxy server for loading remote URLs. On load the
161 | * file href URL will be appended to the remote proxy url, if defined.
162 | */
163 | setRemoteProxy: function(proxyUrl) {
164 | remoteProxyUrl = proxyUrl;
165 | },
166 |
167 | /**
168 | * Loads a given image.
169 | *
170 | * @param file may be one of:
171 | * - File object (if supported)
172 | * - Image URI
173 | * - Entry ID returned by getEntryId for a previous image
174 | *
175 | * @param onError(error) optional callback that is executed if the image can not be loaded
176 | * Errors include:
177 | * - UserImageCache.NOT_FOUND : Unable to lookup cached image element.
178 | * - UserImageCache.UNKNOWN_TYPE : File is unknown type
179 | * - Result of FileReader.error
180 | */
181 | load: function(file, onError) {
182 | if (!image) {
183 | throw new Error("Must call setImageEl prior to attempting to load an image");
184 | }
185 |
186 | // the file from the session store if that is the case
187 | if (typeof file === "string") {
188 | var match = /^page-store:\/\/(.*)$/.exec(file);
189 | if (this.isLocalSupported() && match) {
190 | var loadEntry = localDataBinding.getImage(match[1]);
191 | if (!loadEntry || !loadEntry.src) {
192 | // We could not find the cache data. This could be due to a refresh in the local case,
193 | // or due to someone attempting to paste a URL that uses a local reference.
194 | onError && onError(UserImageCache.NOT_FOUND);
195 | return;
196 | }
197 | loadEntry.entryId = "page-store://" + match[1];
198 | curEntry = loadEntry;
199 | } else {
200 | var srcUrl = file;
201 | if (remoteProxyUrl && /https?:\/\/.*/.test(file)) {
202 | srcUrl = remoteProxyUrl + encodeURIComponent(file);
203 | }
204 | curEntry = { entryId: file, src: srcUrl, displayName: file };
205 | }
206 | image.src = UserImageCache.getSrc();
207 | } else if (this.isLocalSupported() && file instanceof File) {
208 | var reader = new FileReader();
209 | reader.onload = function(event) {
210 | var entryId = localDataBinding.storeImage(file.name || file.fileName, reader.result); // std || impl to be safe
211 | curEntry = localDataBinding.getImage(entryId);
212 | if (!curEntry || !curEntry.src) {
213 | // The file is too large for the remaining data
214 | curEntry = {src: reader.result, displayName: file.name || file.fileName};
215 | }
216 | curEntry.entryId = "page-store://" + entryId;
217 | image.src = UserImageCache.getSrc();
218 | };
219 | reader.onerror = function(event) {
220 | onError && onError(reader.error);
221 | };
222 | reader.readAsDataURL(file);
223 | } else {
224 | onError && onError(UserImageCache.UNKNOWN_TYPE);
225 | }
226 | },
227 |
228 | reset: function() {
229 | localDataBinding.reset();
230 | image = undefined;
231 | curEntry = undefined;
232 | remoteProxyUrl = undefined;
233 | }
234 | };
235 | })();
236 |
--------------------------------------------------------------------------------