diff --git a/README b/README index 12846a17..f5535b09 100644 --- a/README +++ b/README @@ -10,15 +10,16 @@ A. How to get (and contribute) JMVC http://github.com/jupiterjs/steal and http://github.com/jupiterjs/jquerymx - 3. Add steal and javascriptmvc as submodules of your project... + 3. Add steal and jquerymx as submodules of your project... git submodule add git@github.com:_YOU_/steal.git steal git submodule add git@github.com:_YOU_/jquerymx.git jquery - * Notice javascriptmvc is under the jquery folder + * Notice jquerymx is under the jquery folder 4. Learn a little more about submodules ... http://johnleach.co.uk/words/archives/2008/10/12/323/git-submodules-in-n-easy-steps - 5. Make changes in steal or jmvc, and push them back to your fork. + 5. Make changes in steal or jquerymx, and push them back to your fork. 6. Make a pull request to your fork. + diff --git a/build.js b/build.js index 80e4bd62..1d840746 100644 --- a/build.js +++ b/build.js @@ -40,14 +40,6 @@ var i, fileName, cmd, "dom/within", "dom/cur_styles", "model", - { - plugin: "model/associations", - exclude: ["jquery/class/class.js", - "jquery/lang/lang.js", - "jquery/event/destroyed/destroyed.js", - "jquery/lang/openajax/openajax.js", - "jquery/model/model.js"] - }, { plugin: "model/backup", exclude: ["jquery/class/class.js", @@ -98,6 +90,7 @@ var i, fileName, cmd, ] +steal.File('jquery/dist').mkdir(); steal('steal/build/pluginify').then( function(s){ var plugin, exclude, fileDest, fileName; for(i=0; i< stl.dependencies.length; d++) { + var depend = stl.dependencies[d]; + if (depend.options.rootSrc !== "jquery/jquery.js") { + dependencies.push(depend.options.rootSrc); + } + } + } + }) + + s.File("jquery/dist/standalone").mkdirs(); + s.File("jquery/dist/standalone/dependencies.json").save($.toJSON(files)); + //get each file ... + print("Creating jquery/dist/standalone/") + var compressor = s.build.builders.scripts.compressors[ "localClosure"]() + for(var path in files){ + if(path == "jquery/jquery.js"){ + continue; + } + var content = readFile(path); + var funcContent = s.build.pluginify.getFunction(content); + if(typeof funcContent == "undefined"){ + content = ""; + } else { + content = "("+s.build.pluginify.getFunction(content)+")(jQuery);"; + } + var out = path.replace(/\/\w+\.js/,"").replace(/\//g,"."); + content = s.build.builders.scripts.clean(content); + print(" "+out+""); + content = s.build.builders.scripts.clean(content); + s.File("jquery/dist/standalone/"+out+".js").save(content); + s.File("jquery/dist/standalone/"+out+".min.js").save(compressor(content)); + } + + }) + + /* var pageSteal = steal.build.open("steal/rhino/empty.html").steal, steals = pageSteal.total, - //hash of names to steals + files = {}, depends = function(stl, steals){ if(stl.dependencies){ @@ -75,31 +122,9 @@ steal('steal/build/pluginify','steal/build/apps','steal/build/scripts').then( fu } } } - }) + })*/ + - steal.File("jquery/dist/standalone").mkdir(); - steal.File("jquery/dist/standalone/dependencies.json").save($.toJSON(files)); - //get each file ... - print("Creating jquery/dist/standalone/") - var compressor = steal.build.builders.scripts.compressors[ "localClosure"]() - for(var path in files){ - if(path == "jquery/jquery.js"){ - continue; - } - var content = readFile(path); - var funcContent = s.build.pluginify.getFunction(content); - if(typeof funcContent == "undefined"){ - content = ""; - } else { - content = "("+s.build.pluginify.getFunction(content)+")(jQuery);"; - } - var out = path.replace(/\/\w+\.js/,"").replace(/\//g,"."); - content = steal.build.builders.scripts.clean(content); - print(" "+out+""); - content = steal.build.builders.scripts.clean(content); - s.File("jquery/dist/standalone/"+out+".js").save(content); - s.File("jquery/dist/standalone/"+out+".min.js").save(compressor(content)); - } }) \ No newline at end of file diff --git a/class/class.html b/class/class.html index a7027986..ef16143d 100644 --- a/class/class.html +++ b/class/class.html @@ -62,8 +62,8 @@

History Tabs

+ + + \ No newline at end of file diff --git a/controller/history/history.html b/controller/history/history.html deleted file mode 100644 index a529b6ba..00000000 --- a/controller/history/history.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - hover - - - -
- First - Second - Third - Fourth - Fifth - Sixth -
- - - - diff --git a/controller/history/history.js b/controller/history/history.js deleted file mode 100644 index e4f6f9ab..00000000 --- a/controller/history/history.js +++ /dev/null @@ -1,187 +0,0 @@ -steal('jquery/controller/subscribe', - 'jquery/event/hashchange', - 'jquery/lang/deparam').then(function($){ - -/** - * @page jquery.controller.history History Events - * @parent jQuery.Controller - * @plugin jquery/controller/history - * The jquery/controller/history plugin adds - * browser hash (#) based history support. - * - * It allows you to listen to hashchange events with OpenAjax.hub. - * - * Typically you subscribe to a history event in your controllers: - * - * $.Controller("MyHistory",{ - * "history.pagename subscribe" : function(called, data){ - * //called when hash = #pagename - * } - * }) - * - * ## Event Names - * - * When a history event happens, an OpenAjax message is produced that - * starts with "history.". The remainder of the message name depends on the - * value of the "hash". - * - * The following shows hash values and - * the corresponding published message and data. - * - * "#foo=bar" -> "history.index" {foo: bar} - * "#foo/bar" -> "history.foo.bar" {} - * "#foo&bar=baz" -> "history.foo" {bar: baz} - * - * Essentially, if the hash starts with something like #foo/bar, this gets - * added to the message name as "foo.bar". Once "&" is found, it adds the remainder - * as name-value pairs to the message data. - * - * ## Controller Helper Functions - * - * The methods on the left are added to Controller.prototype and make it easier to - * make changes to history. - * - */ - -var keyBreaker = /([^\[\]]+)|(\[\])/g; - -$.Controller.History = { - /** - * @hide - * returns the pathname part - * - * // if the url is "#foo/bar&foo=bar" - * $.Controller.History.pathname() -> 'foo/bar' - * - */ - pathname : function(path) { - var parts = path.match(/#([^&]*)/); - return parts ? parts[1] : null - }, - /** - * @hide - * returns the search part, but without the first & - * - * // if the url is "#foo/bar&foo=bar" - * $.Controller.History.search() -> 'foo=bar' - */ - search : function(path) { - var parts = path.match(/#[^&]*&(.*)/); - return parts ? parts[1] : null - }, - /** - * @hide - * Returns the data - * @param {Object} path - */ - getData: function(path) { - var search = $.Controller.History.search(path), - digitTest = /^\d+$/; - if(! search || ! search.match(/([^?#]*)(#.*)?$/) ) { - return {}; - } - - // Support the legacy format that used MVC.Object.to_query_string that used %20 for - // spaces and not the '+' sign; - search = search.replace(/\+/g,"%20") - return $.String.deparam(search); - } -}; - - - - - -jQuery(function($) { - $(window).bind('hashchange',function() { - var data = $.Controller.History.getData(location.href), - folders = $.Controller.History.pathname(location.href) || 'index', - hasSlash = (folders.indexOf('/') != -1); - - if( !hasSlash && folders != 'index' ) { - folders += '/index'; - } - - OpenAjax.hub.publish("history."+folders.replace("/","."), data); - }); - - setTimeout(function(){ - $(window).trigger('hashchange') - },1) //immediately after ready -}) -/** - * @add jQuery.Controller.prototype - */ - -$.extend($.Controller.prototype, { - /** - * @parent jquery.controller.history - * Redirects to another page. - * @plugin 'dom/history' - * @param {Object} options an object that will turned into a url like #controller/action¶m1=value1 - */ - redirectTo: function(options){ - var point = this._get_history_point(options); - location.hash = point; - }, - /** - * @parent jquery.controller.history - * Redirects to another page by replacing current URL with the given one. This - * call will not create a new entry in the history. - * @plugin 'dom/history' - * @param {Object} options an object that will turned into a url like #controller/action¶m1=value1 - */ - replaceWith: function(options){ - var point = this._get_history_point(options); - location.replace(location.href.split('#')[0] + point); - }, - /** - * @parent jquery.controller.history - * Adds history point to browser history. - * @plugin 'dom/history' - * @param {Object} options an object that will turned into a url like #controller/action¶m1=value1 - * @param {Object} data extra data saved in history -- NO LONGER SUPPORTED - */ - historyAdd : function(options, data) { - var point = this._get_history_point(options); - location.hash = point; - }, - /** - * @hide - * @parent jquery.controller.history - * Creates a history point from given options. Resultant history point is like #controller/action¶m1=value1 - * @plugin 'dom/history' - * @param {Object} options an object that will turned into history point - */ - _get_history_point: function(options) { - var controller_name = options.controller || this.Class.underscoreName; - var action_name = options.action || 'index'; - - /* Convert the options to parameters (removing controller and action if needed) */ - if(options.controller) - delete options.controller; - if(options.action) - delete options.action; - - var paramString = (options) ? $.param(options) : ''; - if(paramString.length) - paramString = '&' + paramString; - - return '#' + controller_name + '/' + action_name + paramString; - }, - - /** - * @parent jquery.controller.history - * Provides current window.location parameters as object properties. - * @plugin 'dom/history' - */ - pathData :function() { - return $.Controller.History.getData(location.href); - } -}); - - - - - -}); \ No newline at end of file diff --git a/controller/history/history_test.js b/controller/history/history_test.js deleted file mode 100644 index edb6d812..00000000 --- a/controller/history/history_test.js +++ /dev/null @@ -1,38 +0,0 @@ -steal('funcunit/qunit','jquery/controller/history').then(function($){ - -module("jquery/controller/history",{ - setup: function(){ - - } -}) - -test("Basic getData",function(){ - - var data = $.Controller.History.getData("#foo/bar&a=b"); - equals(data.a,"b") - - var data = $.Controller.History.getData("#foo/bar&a=b&c=d"); - equals(data.a,"b") - equals(data.c,"d") -}) -test("Nested getData",function(){ - - var data = $.Controller.History.getData("#foo/bar&a[b]=1&a[c]=2"); - equals(data.a.b,1) - equals(data.a.c,2) - - var data = $.Controller.History.getData("#foo/bar&a[]=1&a[]=2"); - equals(data.a[0],1) - equals(data.a[1],2) - - var data = $.Controller.History.getData("#foo/bar&a[b][]=1&a[b][]=2"); - equals(data.a.b[0],1) - equals(data.a.b[1],2) - - var data = $.Controller.History.getData("#foo/bar&a[0]=1&a[1]=2"); - equals(data.a[0],1) - equals(data.a[1],2) -}) - - -}) diff --git a/controller/history/html5/html5.js b/controller/history/html5/html5.js deleted file mode 100644 index 241b26b8..00000000 --- a/controller/history/html5/html5.js +++ /dev/null @@ -1,31 +0,0 @@ -steal('jquery/controller/subscribe').then(function($){ - - var hasHistoryManagementSupport = !!(window.history && history.pushState); - - if (hasHistoryManagementSupport) { - steal.dev.log("WARNING: The current browser does not support HTML5 History Management."); - } else { - window.onpopstate = function(event) { - OpenAjax.hub.publish("history."+location.href, (event && event.state) || {}); - }; - - setTimeout(function(){ - window.onpopstate(); - }, 1); // immediately after ready - - $.extend($.Controller.prototype, { - redirectTo: function(url, data, title) { - data = data || {}; - window.history.pushState(data, title, url); - this.publish("history." + url, data); - } - }); - - $.Controller.processors["windowpopstate"] = function(el, event, selector, cb) { - $(window).bind("popstate", cb); - return function(){ - $(window).unbind("popstate", cb); - } - }; - } -}) diff --git a/controller/history/html5/qunit.html b/controller/history/html5/qunit.html deleted file mode 100644 index 7274e702..00000000 --- a/controller/history/html5/qunit.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - -

HTML5 History Test Suite

-

-
-

-
-
    -
    - - diff --git a/controller/history/html5/qunit/qunit.js b/controller/history/html5/qunit/qunit.js deleted file mode 100755 index d8960d14..00000000 --- a/controller/history/html5/qunit/qunit.js +++ /dev/null @@ -1,82 +0,0 @@ -steal("funcunit/qunit", "jquery/controller/history/html5").then(function($){ - -module("jquery/controller/history/html5",{ - setup: function(){ - - } -}) - - -$.Controller.extend("HTML5HistoryTestController", { -}, -{ - "history.** subscribe": function(event_name, params) { - this["gotHistory"](event_name.replace("history.", ""), params); - }, - - gotHistory: $.noop, - - "window windowpopstate": function(ev) { - this["gotPopState"](location.href, (ev.originalEvent && ev.originalEvent.state) || {}); - }, - - gotPopState: $.noop -}); - -var originalLocation = location.href; - -asyncTest("Controller redirect should work", function(){ - expect(1); - var testController = new HTML5HistoryTestController($("
    ").get(0)); - - var testLocation = "/test/location"; - testController["gotHistory"] = function(location, state) { - start(); - equals(location, testLocation); - testController["gotHistory"] = $.noop; - testController.redirectTo(originalLocation); - }; - - stop(); - testController.redirectTo(testLocation); -}); - -asyncTest("State data should persist", function(){ - expect(1); - var testController = new HTML5HistoryTestController($("
    ").get(0)); - - testController["gotHistory"] = function(location, state) { - start(); - equals(state.hi, "mom"); - testController["gotHistory"] = $.noop; - testController.redirectTo(originalLocation); - }; - - stop(); - testController.redirectTo("/test/location", { hi: "mom" }); -}); - -asyncTest("Should listen to windowpopstate", function(){ - expect(2); - var testController = new HTML5HistoryTestController($("
    ").get(0)); - - testController["gotPopState"] = function(location, state) { - start(); - ok(location.indexOf("/test/location") !== -1); - equals(state.hi, "mom"); - testController["gotPopState"] = $.noop; - testController.redirectTo(originalLocation); - }; - - stop(); - testController.redirectTo("/test/location", { hi: "mom" }); - - testController["gotHistory"] = function(location, state) { - testController["gotHistory"] = $.noop; - window.history.back(); - }; - - testController.redirectTo("/test/location2", { hi: "mom2" }); -}); - -}); diff --git a/controller/pages/document.md b/controller/pages/document.md deleted file mode 100644 index 5ad53576..00000000 --- a/controller/pages/document.md +++ /dev/null @@ -1,62 +0,0 @@ -@page jquery.controller.documentcontrollers Document Controllers -@parent jQuery.Controller - -Document Controllers delegate on the -documentElement. You don't have to attach an instance as this will be done -for you when the controller class is created. Document Controllers, with the -exception of MainControllers, -add an implicit '#CONTROLLERNAME' before every selector. - -To create a document controller, you just have to set -the controller's [jQuery.Controller.static.onDocument static onDocument] -property to true. - -@codestart -$.Controller.extend('TodosController', -{onDocument: true}, -{ - ".todo mouseover" : function( el, ev ) { //matches #todos .todo - el.css("backgroundColor","red") - }, - ".todo mouseout" : function( el, ev ) { //matches #todos .todo - el.css("backgroundColor","") - }, - ".create click" : function() { //matches #todos .create - this.find("ol").append("<li class='todo'>New Todo</li>"); - } -}) -@codeend - -DocumentControllers should be used sparingly. They are not very reusable. -They should only be used for glueing together other controllers and page -layout. - -Often, a Document Controller's "ready" event will be used to create -necessary Element Controllers. - -@codestart -$.Controller.extend('SidebarController', -{onDocument: true}, -{ - ready : function() { - $(".slider").slider() - }, - "a.tag click" : function() {..} -}) -@codeend - -## MainControllers - -MainControllers are documentControllers that do not add '#CONTROLLERNAME' before every selector. This controller -should only be used for page wide functionality and setup. - -@codestart -$.Controller.extend("MainController",{ - hasActiveElement : document.activeElement || false -},{ - focus : funtion(el){ - if(!this.Class.hasActiveElement) - document.activeElement = el[0] //tracks active element - } -}) -@codeend \ No newline at end of file diff --git a/controller/pages/listening.md b/controller/pages/listening.md index 684c1c46..c27ab175 100644 --- a/controller/pages/listening.md +++ b/controller/pages/listening.md @@ -41,7 +41,7 @@ But to correct for this, you just need to add the function to the [jQuery.Controller.static.listensTo listensTo] property. Here's how: - $.Controller.extend("MyShow",{ + $.Controller("MyShow",{ listensTo: ["show"] },{ show: function( el, ev ) { diff --git a/controller/history/qunit.html b/controller/route/qunit.html similarity index 65% rename from controller/history/qunit.html rename to controller/route/qunit.html index 99652e3e..25edc491 100644 --- a/controller/history/qunit.html +++ b/controller/route/qunit.html @@ -1,16 +1,13 @@ + - - + route QUnit Test + -

    Model Store Cookie Test Suite

    +

    route Test Suite

    diff --git a/controller/route/route.html b/controller/route/route.html new file mode 100644 index 00000000..178af929 --- /dev/null +++ b/controller/route/route.html @@ -0,0 +1,35 @@ + + + + route + + + +

    route Demo

    + foo/bar + foo/car + empty + + + + \ No newline at end of file diff --git a/controller/route/route.js b/controller/route/route.js new file mode 100644 index 00000000..bc0f1c67 --- /dev/null +++ b/controller/route/route.js @@ -0,0 +1,31 @@ +steal('jquery/dom/route','jquery/controller', function(){ + /** + * + * ":type route" // + * + * @param {Object} el + * @param {Object} event + * @param {Object} selector + * @param {Object} cb + */ + jQuery.Controller.processors.route = function(el, event, selector, funcName, controller){ + $.route(selector||"") + var batchNum; + var check = function(ev, attr, how){ + if($.route.attr('route') === (selector||"") && + (ev.batchNum === undefined || ev.batchNum !== batchNum ) ){ + + batchNum = ev.batchNum; + + var d = $.route.attrs(); + delete d.route; + + controller[funcName](d) + } + } + $.route.bind('change',check); + return function(){ + $.route.unbind('change',check) + } + } +}) diff --git a/controller/route/route_test.js b/controller/route/route_test.js new file mode 100644 index 00000000..6a140d6b --- /dev/null +++ b/controller/route/route_test.js @@ -0,0 +1,10 @@ +steal('funcunit/qunit','./route',function(){ + +module("route"); + +test("route testing works", function(){ + ok(true,"an assert is run"); +}); + + +}); \ No newline at end of file diff --git a/controller/subscribe/subscribe.html b/controller/subscribe/subscribe.html index ebabb0c5..a26d72d5 100644 --- a/controller/subscribe/subscribe.html +++ b/controller/subscribe/subscribe.html @@ -32,7 +32,7 @@

    Turn OFF Above

    \ No newline at end of file diff --git a/dom/range/range.js b/dom/range/range.js index fde74f06..7f3db253 100644 --- a/dom/range/range.js +++ b/dom/range/range.js @@ -4,8 +4,11 @@ steal('jquery','jquery/dom/compare').then(function($){ /** * @function jQuery.fn.range + * @parent $.Range * - * Returns a jQuery.Range. + * Returns a jQuery.Range for the element selected. + * + * $('#content').range() */ $.fn.range = function(){ return $.Range(this[0]) @@ -36,7 +39,25 @@ support = {}; * @parent dom * @tag alpha * - * Provides text range helpers for creating, moving, and comparing ranges. + * Provides text range helpers for creating, moving, + * and comparing ranges cross browser. + * + * ## Examples + * + * // Get the current range + * var range = $.Range.current() + * + * // move the end of the range 2 characters right + * range.end("+2") + * + * // get the startOffset of the range and the container + * range.start() //-> { offset: 2, container: HTMLELement } + * + * //get the most common ancestor element + * var parent = range.parent() + * + * //select the parent + * var range2 = new $.Range(parent) * * @constructor * @@ -220,12 +241,19 @@ $.extend($.Range.prototype, * * @param {Boolean} [toStart] true if to the start of the range, false if to the * end. Defaults to false. - * @return {Range} returns the range for chaining. + * @return {jQuery.Range} returns the range for chaining. */ collapse : function(toStart){ this.range.collapse(toStart === undefined ? true : toStart); return this; }, + /** + * Returns the text of the range. + * + * currentText = $.Range.current().toString() + * + * @return {String} the text of the range + */ toString : function(){ return typeof this.range.text == "string" ? this.range.text : this.range.toString(); }, @@ -289,7 +317,8 @@ $.extend($.Range.prototype, }, /** - * Sets or gets the end of the range. It takes similar options as [jQuery.Range.prototype.get]. + * Sets or gets the end of the range. + * It takes similar options as [jQuery.Range.prototype.start]. * @param {Object} [set] */ end : function(set){ @@ -326,6 +355,8 @@ $.extend($.Range.prototype, * Returns the most common ancestor element of * the endpoints in the range. This will return text elements if the range is * within a text element. + * @return {HTMLNode} the TextNode or HTMLElement + * that fully contains the range */ parent : function(){ if(this.range.commonAncestorContainer){ @@ -421,13 +452,36 @@ $.extend($.Range.prototype, /** * @function compare - * Compares one range to another range. This is different from the spec b/c the spec is confusing. + * Compares one range to another range. + * + * ## Example + * + * // compare the highlight element's start position + * // to the start of the current range + * $('#highlight') + * .range() + * .compare('START_TO_START', $.Range.current()) * - * source.compare("START_TO_END", toRange); * - * This returns -1 if source's start is before toRange's end. - * @param {Object} type - * @param {Object} range + * + * @param {Object} type Specifies the boundry of the + * range and the compareRange to compare. + * + * - START\_TO\_START - the start of the range and the start of compareRange + * - START\_TO\_END - the start of the range and the end of compareRange + * - END\_TO\_END - the end of the range and the end of compareRange + * - END\_TO\_START - the end of the range and the start of compareRange + * + * @param {$.Range} compareRange The other range + * to compare against. + * @return {Number} a number indicating if the range + * boundary is before, + * after, or equal to compareRange's + * boundary where: + * + * - -1 - the range boundary comes before the compareRange boundary + * - 0 - the boundaries are equal + * - 1 - the range boundary comes after the compareRange boundary */ fn.compare = range.compareBoundaryPoints ? function(type, range){ @@ -439,9 +493,24 @@ $.extend($.Range.prototype, /** * @function move - * Move the endpoints of a range - * @param {Object} type - * @param {Object} range + * Move the endpoints of a range relative to another range. + * + * // Move the current selection's end to the + * // end of the #highlight element + * $.Range.current().move('END_TO_END', + * $('#highlight').range() ) + * + * + * @param {String} type a string indicating the ranges boundary point + * to move to which referenceRange boundary point where: + * + * - START\_TO\_START - the start of the range moves to the start of referenceRange + * - START\_TO\_END - the start of the range move to the end of referenceRange + * - END\_TO\_END - the end of the range moves to the end of referenceRange + * - END\_TO\_START - the end of the range moves to the start of referenceRange + * + * @param {jQuery.Range} referenceRange + * @return {jQuery.Range} the original range for chaining */ fn.move = range.setStart ? function(type, range){ @@ -473,7 +542,10 @@ $.extend($.Range.prototype, fn. /** - * Clones the range and returns a new $.Range object. + * Clones the range and returns a new $.Range + * object. + * + * @return {jQuery.Range} returns the range as a $.Range. */ clone = function(){ return $.Range( this.range[cloneFunc]() ); @@ -481,12 +553,15 @@ $.extend($.Range.prototype, fn. /** - * Selects an element with this range. If nothing is provided, makes the current + * @function + * Selects an element with this range. If nothing + * is provided, makes the current * range appear as if the user has selected it. * * This works with text nodes. * - * @param {HTMLElement} el + * @param {HTMLElement} [el] + * @return {jQuery.Range} the range for chaining. */ select = range.selectNodeContents ? function(el){ if(!el){ diff --git a/dom/route/route.html b/dom/route/route.html index a77f7de9..84071408 100644 --- a/dom/route/route.html +++ b/dom/route/route.html @@ -1,23 +1,116 @@ - + Jquery.Dom.Route -

    Jquery.Dom.Route Demo

    -
    - +

    $.Route Demo

    +
    View qunit test results
    +
    +
    +
    + Use these links to modify the hash or change it directly in the address bar: +

    + URLs with a registered path: + #!pages/val1/val2/val3 + #!pages/val1// + #!pages/// + #!/val1/val2 +
    + URLs without paths: + #!pages// + #!/// +
    + Empty hash: + #! +
    +

    Hash update events:

    +
    +
    +
    +
    +
    + Value1:
    + Value2:
    + Value3: + +
    +
    +

    Data update events:

    +
    +
    + + - + \ No newline at end of file diff --git a/dom/route/route.js b/dom/route/route.js index 045fd6c6..4159adec 100644 --- a/dom/route/route.js +++ b/dom/route/route.js @@ -1,146 +1,390 @@ -steal('jquery/lang/observe', 'jquery/event/hashchange', 'jquery/lang/deparam', 'jquery/lang/observe/delegate', function( $ ) { +steal('jquery/lang/observe', 'jquery/event/hashchange', 'jquery/lang/string/deparam', +function( $ ) { - var globalDefaults, matcher = /\:([\w\.]+)/g, + // Helper methods used for matching routes. + var + // RegEx used to match route variables of the type ':name'. + // Any word character or a period is matched. + matcher = /\:([\w\.]+)/g, + // Regular expression for identifying &key=value lists. + paramsMatcher = /^(?:&[^=]+=[^&]*)+/, + // Converts a JS Object into a list of parameters that can be + // inserted into an html element tag. makeProps = function( props ) { var html = [], name, val; - for ( name in props ) { - val = props[name] + each(props, function(name, val){ if ( name === 'className' ) { name = 'class' } - val && html.push(name, "=\"", escapeHTML(val), "\" "); - } + val && html.push(escapeHTML(name), "=\"", escapeHTML(val), "\" "); + }) return html.join("") }, + // Escapes ' and " for safe insertion into html tag parameters. escapeHTML = function( content ) { return content.replace(/"/g, '"').replace(/'/g, "'"); - }; + }, + // Checks if a route matches the data provided. If any route variable + // is not present in the data the route does not match. If all route + // variables are present in the data the number of matches is returned + // to allow discerning between general and more specific routes. + matchesData = function(route, data) { + var count = 0; + for ( var i = 0; i < route.names.length; i++ ) { + if (!data.hasOwnProperty(route.names[i]) ) { + return -1; + } + count++; + } + return count; + }, + // + onready = true, + location = window.location, + encode = encodeURIComponent, + decode = decodeURIComponent, + each = $.each, + extend = $.extend; /** - * @parent dom * @class jQuery.route + * @inherits jQuery.Observe + * @plugin jquery/dom/route + * @parent dom * @tag 3.2 * - * jQuery.route helps manage browser history by + * jQuery.route helps manage browser history (and + * client state) by * synchronizing the window.location.hash with - * [jQuery.route.data]. + * an [jQuery.Observe]. + * + * ## Background Information + * + * To support the browser's back button and bookmarking + * in an Ajax application, most applications use + * the window.location.hash. By + * changing the hash (via a link or JavaScript), + * one is able to add to the browser's history + * without changing the page. The [jQuery.event.special.hashchange event] allows + * you to listen to when the hash is changed. + * + * Combined, this provides the basics needed to + * create history enabled Ajax websites. However, + * jQuery.Route addresses several other needs such as: + * + * - Pretty Routes + * - Keeping routes independent of application code + * - Listening to specific parts of the history changing + * - Setup / Teardown of widgets. + * + * ## How it works + * + * $.route is a [jQuery.Observe $.Observe] that represents the + * window.location.hash as an + * object. For example, if the hash looks like: + * + * #!type=videos&id=5 + * + * the data in $.route would look like: + * + * { type: 'videos', id: 5 } + * + * + * $.route keeps the state of the hash in-sync with the data in + * $.route. + * + * ## $.Observe + * + * $.route is a [jQuery.Observe $.Observe]. Understanding + * $.Observe is essential for using $.route correctly. + * + * You can + * listen to changes in an Observe with bind and + * delegate and change $.route's properties with + * attr and attrs. + * + * ### Listening to changes in an Observable + * + * Listen to changes in history + * by [jQuery.Observe.prototype.bind bind]ing to + * changes in $.route like: + * + * $.route.bind('change', function(ev, attr, how, newVal, oldVal) { + * + * }) + * + * - attr - the name of the changed attribute + * - how - the type of Observe change event (add, set or remove) + * - newVal/oldVal - the new and old values of the attribute + * + * You can also listen to specific changes + * with [jQuery.Observe.prototype.delegate delegate]: + * + * $.route.delegate('id','change', function(){ ... }) + * + * Observe lets you listen to the following events: + * + * - change - any change to the object + * - add - a property is added + * - set - a property value is added or changed + * - remove - a property is removed + * + * Listening for add is useful for widget setup + * behavior, remove is useful for teardown. + * + * ### Updating an observable * * Create changes in the route data like: * - * $.route.data.attr('type','video'); + * $.route.attr('type','images'); * - * Listen to changes in the route data like + * Or change multiple properties at once with + * [jQuery.Observe.prototype.attrs attrs]: * - * $.route.data.delegate('type','add',function(ev, newVal, oldVal){ + * $.route.attr({type: 'pages', id: 5}, true) * - * }) + * When you make changes to $.route, they will automatically + * change the hash. * * ## Creating a Route * - * $.route("", {type: "videos"}); - * $.route(":type",{type: "videos"}); + * Use $.route(url, defaults) to create a + * route. A route is a mapping from a url to + * an object (that is the $.route's state). + * + * If no routes are added, or no route is matched, + * $.route's data is updated with the [jQuery.String.deparam deparamed] + * hash. + * + * location.hash = "#!type=videos"; + * // $.route -> {type : "videos"} + * + * Once routes are added and the hash changes, + * $.route looks for matching routes and uses them + * to update $.route's data. + * + * $.route( "content/:type" ); + * location.hash = "#!content/images"; + * // $.route -> {type : "images"} + * + * Default values can also be added: * - * @param {String} url - * @param {Object} [defaults] + * $.route("content/:type",{type: "videos" }); + * location.hash = "#!content/" + * // $.route -> {type : "videos"} + * + * ## Delay setting $.route + * + * By default, $.route sets its initial data + * on document ready. Sometimes, you want to wait to set + * this data. To wait, call: + * + * $.route.ready(false); + * + * and when ready, call: + * + * $.route.ready(true); + * + * ## Changing the route. + * + * Typically, you never want to set location.hash + * directly. Instead, you can change properties on $.route + * like: + * + * $.route.attr('type', 'videos') + * + * This will automatically look up the appropriate + * route and update the hash. + * + * Often, you want to create links. $.route provides + * the [jQuery.route.link] and [jQuery.route.url] helpers to make this + * easy: + * + * $.route.link("Videos", {type: 'videos'}) + * + * @param {String} url the fragment identifier to match. + * @param {Object} [defaults] an object of default values + * @return {jQuery.route} */ - var $route = $.route = function( url, defaults ) { - // add route in a form that can be easily figured out - // + $.route = function( url, defaults ) { + // Extract the variable names and replace with regEx that will match an atual URL with values. var names = [], test = url.replace(matcher, function( whole, name ) { names.push(name) - return "([\\w\\.]*)" + // TODO: I think this should have a + + return "([^\\/\\&]*)" // The '\\' is for string-escaping giving single '\' for regEx escaping }); - // need a regexp to match - $route.routes[url] = { - test: new RegExp("^" + test), + // Add route in a form that can be easily figured out + $.route.routes[url] = { + // A regular expression that will match the route when variable values + // are present; i.e. for :page/:type the regEx is /([\w\.]*)/([\w\.]*)/ which + // will match for any value of :page and :type (word chars or period). + test: new RegExp("^" + test+"($|&)"), + // The original URL, same as the index for this entry in routes. route: url, + // An array of all the variable names in this route names: names, + // Default values provided for the variables. defaults: defaults || {}, + // The number of parts in the URL separated by '/'. length: url.split('/').length } + return $.route; }; - $.extend($route, { + extend($.route, { /** - * Parameterizes the raw JS object representation of - * $.route.data. - * + * Parameterizes the raw JS object representation provided in data. + * If a route matching the provided data is found that URL is built + * from the data. Any remaining data is added at the end of the + * URL as & separated key/value parameters. * * @param {Object} data + * @return {String} The route URL and & separated parameters. */ param: function( data ) { - // see what data is provided ... - // check if it matches the names in any routes ... - for ( var name in $route.routes ) { - var route = $route.routes[name], - ok = true; - - // check if data has props - for ( var i = 0; i < route.names.length; i++ ) { - if (!data.hasOwnProperty(route.names[i]) ) { - ok = false; - break; + // Check if the provided data keys match the names in any routes; + // get the one with the most matches. + var route, + // need it to be at least 1 match + matches = 0, + matchCount, + routeName = data.route; + + delete data.route; + // if we have a route name in our $.route data, use it + if(routeName && (route = $.route.routes[routeName])){ + + } else { + // otherwise find route + each($.route.routes, function(name, temp){ + matchCount = matchesData(temp, data); + if ( matchCount > matches ) { + route = temp; + matches = matchCount } - } - if ( ok ) { - // create url ... - var cpy = $.extend({}, data); - - var res = route.route.replace(matcher, function( whole, name ) { - delete cpy[name]; - return data[name] === route.defaults[name] ? "" : data[name]; - }); - var after = $.param(cpy); - return res + (after ? "&" + after : "") - } + }); + } + // if this is match + + if ( route ) { + var cpy = extend({}, data), + // Create the url by replacing the var names with the provided data. + // If the default value is found an empty string is inserted. + res = route.route.replace(matcher, function( whole, name ) { + delete cpy[name]; + return data[name] === route.defaults[name] ? "" : encode( data[name] ); + }), + after; + // remove matching default values + each(route.defaults, function(name,val){ + if(cpy[name] === val) { + delete cpy[name] + } + }) + + // The remaining elements of data are added as + // $amp; separated parameters to the url. + after = $.param(cpy); + return res + (after ? "&" + after : "") } - return $.param(data); + // If no route was found there is no hash URL, only paramters. + return $.isEmptyObject(data) ? "" : "&" + $.param(data); }, /** + * Populate the JS data object from a given URL. * * @param {Object} url */ deparam: function( url ) { - // see if there are any matches ... + // See if the url matches any routes by testing it against the route.test regEx. + // By comparing the URL length the most specialized route that matches is used. var route = { length: -1 }; - for ( var name in $route.routes ) { - var temp = $route.routes[name] + each($.route.routes, function(name, temp){ if ( temp.test.test(url) && temp.length > route.length ) { route = temp; } - } - if ( route.length > -1 ) { - var parts = url.match(route.test), + }); + // If a route was matched + if ( route.length > -1 ) { + var // Since RegEx backreferences are used in route.test (round brackets) + // the parts will contain the full matched string and each variable (backreferenced) value. + parts = url.match(route.test), + // start will contain the full matched string; parts contain the variable values. start = parts.shift(), - remainder = url.substr(start.length + 1), - obj = $.extend(true, remainder ? $.String.deparam(remainder) : {}, route.defaults); + // The remainder will be the &key=value list at the end of the URL. + remainder = url.substr(start.length - (parts[parts.length-1] === "&" ? 1 : 0) ), + // If there is a remainder and it contains a &key=value list deparam it. + obj = (remainder && paramsMatcher.test(remainder)) ? $.String.deparam( remainder.slice(1) ) : {}; - for ( var p = 0; p < parts.length; p++ ) { - if ( parts[p] ) { - obj[route.names[p]] = parts[p] + // Add the default values for this route + obj = extend(true, {}, route.defaults, obj); + // Overwrite each of the default values in obj with those in parts if that part is not empty. + each(parts,function(i, part){ + if ( part && part !== '&') { + obj[route.names[i]] = decode( part ); } - } + }); + obj.route = route.route; return obj; } - return $.String.deparam(url); + // If no route was matched it is parsed as a &key=value list. + if ( url.charAt(0) !== '&' ) { + url = '&' + url; + } + return paramsMatcher.test(url) ? $.String.deparam( url.slice(1) ) : {}; }, /** - * A $.Observe that represents the state of the - * history. + * @hide + * A $.Observe that represents the state of the history. */ data: new $.Observe({}), + /** + * @attribute + * @type Object + * @hide + * + * A list of routes recognized by the router indixed by the url used to add it. + * Each route is an object with these members: + * + * - test - A regular expression that will match the route when variable values + * are present; i.e. for :page/:type the regEx is /([\w\.]*)/([\w\.]*)/ which + * will match for any value of :page and :type (word chars or period). + * + * - route - The original URL, same as the index for this entry in routes. + * + * - names - An array of all the variable names in this route + * + * - defaults - Default values provided for the variables or an empty object. + * + * - length - The number of parts in the URL separated by '/'. + */ routes: {}, /** - * Indicates that all routes have been added - * and sets $.route.data based upon the routes. + * Indicates that all routes have been added and sets $.route.data + * based upon the routes and the current hash. + * + * By default, ready is fired on jQuery's ready event. Sometimes + * you might want it to happen sooner or earlier. To do this call + * + * $.route.ready(false); //prevents firing by the ready event + * $.route.ready(true); // fire the first route change + * + * @param {Boolean} [start] + * @return $.route */ - ready: function() { - setState(); + ready: function(val) { + if( val === false ) { + onready = false; + } + if( val === true || onready === true ) { + setState(); + } + return $.route; }, /** * Returns a url from the options @@ -149,59 +393,79 @@ steal('jquery/lang/observe', 'jquery/event/hashchange', 'jquery/lang/deparam', ' * @return {String} */ url: function( options, merge ) { - //merges - if (!merge ) { - return "#!" + $route.param(options) + if (merge) { + return "#!" + $.route.param(extend({}, curParams, options)) } else { - return "#!" + $route.param($.extend({}, curParams, options)) + return "#!" + $.route.param(options) } }, /** * Returns a link - * @param {Object} name - * @param {Object} options - * @param {Object} props + * @param {Object} name The text of the link. + * @param {Object} options The route options (variables) + * @param {Object} props Properties of the <a> other than href. + * @param {Boolean} merge true if the options should be merged with the current options */ - link: function( name, options, props ) { + link: function( name, options, props, merge ) { return "" + name + ""; }, /** - * Returns if the options represent the current page. + * Returns true if the options represent the current page. * @param {Object} options + * @return {Boolean} */ current: function( options ) { - return window.location.hash == "#!" + $route.param(options) + return location.hash == "#!" + $.route.param(options) } }); - - var throttle = function( func, time ) { - var timer; - return function() { - clearTimeout(timer); - timer = setTimeout(func, time || 1); + // onready + $(function() { + $.route.ready(); + }); + + // The functions in the following list applied to $.route (e.g. $.route.attr('...')) will + // instead act on the $.route.data Observe. + each(['bind','unbind','delegate','undelegate','attr','attrs','serialize','removeAttr'], function(i, name){ + $.route[name] = function(){ + return $.route.data[name].apply($.route.data, arguments) } - }, - curParams, setState = function() { - - var hash = window.location.hash.substr(2); // everything after #! - //deparam it - var props = $route.deparam(hash); - curParams = props; - $route.data.attrs(props, true); + }) + var // A throttled function called multiple times will only fire once the + // timer runs down. Each call resets the timer. + throttle = function( func ) { + var timer; + return function() { + var args = arguments, + self = this; + clearTimeout(timer); + timer = setTimeout(function(){ + func.apply(self, args) + }, 1); + } + }, + // Intermediate storage for $.route.data. + curParams, + // Deparameterizes the portion of the hash of interest and assign the + // values to the $.route.data removing existing values no longer in the hash. + setState = function() { + var hash = location.hash.substr(1, 1) === '!' ? + location.hash.slice(2) : + location.hash.slice(1); // everything after #! + curParams = $.route.deparam( hash ); + $.route.attrs(curParams, true); }; - // update the state object + // If the hash changes, update the $.route.data $(window).bind('hashchange', setState); - - // update the page - $route.data.bind("change", throttle(function() { - // param and change the hash if necessary - // throttle - window.location.hash = "#!" + $route.param($route.data.serialize()) + // If the $.route.data changes, update the hash. + // Using .serialize() retrieves the raw data contained in the observable. + // This function is throttled so it only updates once even if multiple values changed. + $.route.bind("change", throttle(function() { + location.hash = "#!" + $.route.param($.route.serialize()) })); }) \ No newline at end of file diff --git a/dom/route/route_test.js b/dom/route/route_test.js index 78a0ae21..f487da94 100644 --- a/dom/route/route_test.js +++ b/dom/route/route_test.js @@ -1,29 +1,81 @@ steal('funcunit/qunit').then('./route.js',function(){ - -module("jquery/dom/route") +module("jquery/dom/route") test("deparam", function(){ $.route.routes = {}; $.route(":page",{ page: "index" }) + var obj = $.route.deparam("jQuery.Controller"); same(obj, { - page : "jQuery.Controller" + page : "jQuery.Controller", + route: ":page" }); - + obj = $.route.deparam(""); - same(obj, { - page : "index" + page : "index", + route: ":page" }); - + obj = $.route.deparam("jQuery.Controller&where=there"); - same(obj, { page : "jQuery.Controller", - where: "there" + where: "there", + route: ":page" + }); + + $.route.routes = {}; + $.route(":page/:index",{ + page: "index", + index: "foo" + }); + + obj = $.route.deparam("jQuery.Controller/&where=there"); + same(obj, { + page : "jQuery.Controller", + index: "foo", + where: "there", + route: ":page/:index" + }); +}) + +test("deparam of invalid url", function(){ + $.route.routes = {}; + $.route("pages/:var1/:var2/:var3", { + var1: 'default1', + var2: 'default2', + var3: 'default3' + }); + + // This path does not match the above route, and since the hash is not + // a &key=value list there should not be data. + obj = $.route.deparam("pages//"); + same(obj, {}); + + // A valid path with invalid parameters should return the path data but + // ignore the parameters. + obj = $.route.deparam("pages/val1/val2/val3&invalid-parameters"); + same(obj, { + var1: 'val1', + var2: 'val2', + var3: 'val3', + route: "pages/:var1/:var2/:var3" + }); +}) + +test("deparam of url with non-generated hash (manual override)", function(){ + $.route.routes = {}; + + // This won't be set like this by route, but it could easily happen via a + // user manually changing the URL or when porting a prior URL structure. + obj = $.route.deparam("page=foo&bar=baz&where=there"); + same(obj, { + page: 'foo', + bar: 'baz', + where: 'there' }); }) @@ -32,9 +84,43 @@ test("param", function(){ $.route("pages/:page",{ page: "index" }) + var res = $.route.param({page: "foo"}); - equals(res, "pages/foo") + + res = $.route.param({page: "foo", index: "bar"}); + equals(res, "pages/foo&index=bar") + + $.route("pages/:page/:foo",{ + page: "index", + foo: "bar" + }) + + res = $.route.param({page: "foo", foo: "bar", where: "there"}); + equals(res, "pages/foo/&where=there") + + // There is no matching route so the hash should be empty. + res = $.route.param({}); + equals(res, "") + + $.route.routes = {}; + + res = $.route.param({page: "foo", bar: "baz", where: "there"}); + equals(res, "&page=foo&bar=baz&where=there") + + res = $.route.param({}); + equals(res, "") +}); + +test("symmetry", function(){ + $.route.routes = {}; + + var obj = {page: "=&[]", nestedArray : ["a"], nested : {a :"b"} } + + var res = $.route.param(obj) + + var o2 = $.route.deparam(res) + same(o2, obj) }) test("light param", function(){ @@ -42,39 +128,140 @@ test("light param", function(){ $.route(":page",{ page: "index" }) - + var res = $.route.param({page: "index"}); equals(res, "") + + $.route("pages/:p1/:p2/:p3",{ + p1: "index", + p2: "foo", + p3: "bar" + }) + + res = $.route.param({p1: "index", p2: "foo", p3: "bar"}); + equals(res, "pages///") + + res = $.route.param({p1: "index", p2: "baz", p3: "bar"}); + equals(res, "pages//baz/") +}); + +test('param doesnt add defaults to params', function(){ + $.route.routes = {}; + + $.route("pages/:p1",{ + p2: "foo" + }) + var res = $.route.param({p1: "index", p2: "foo"}); + equals(res, "pages/index") +}) + +test("param-deparam", function(){ + + $.route(":page/:type",{ + page: "index", + type: "foo" + }) + + var data = {page: "jQuery.Controller", + type: "document", + bar: "baz", + where: "there"}; + var res = $.route.param(data); + var obj = $.route.deparam(res); + delete obj.route + same(obj,data ) + return; + data = {page: "jQuery.Controller", type: "foo", bar: "baz", where: "there"}; + res = $.route.param(data); + obj = $.route.deparam(res); + delete obj.route; + same(data, obj) + + data = {page: " a ", type: " / "}; + res = $.route.param(data); + obj = $.route.deparam(res); + delete obj.route; + same(obj ,data ,"slashes and spaces") + + data = {page: "index", type: "foo", bar: "baz", where: "there"}; + res = $.route.param(data); + obj = $.route.deparam(res); + delete obj.route; + same(data, obj) + + $.route.routes = {}; + + data = {page: "foo", bar: "baz", where: "there"}; + res = $.route.param(data); + obj = $.route.deparam(res); + same(data, obj) }) test("precident", function(){ $.route.routes = {}; $.route(":who",{who: "index"}); $.route("search/:search"); - + var obj = $.route.deparam("jQuery.Controller"); same(obj, { - who : "jQuery.Controller" + who : "jQuery.Controller", + route: ":who" }); - + obj = $.route.deparam("search/jQuery.Controller"); same(obj, { - search : "jQuery.Controller" + search : "jQuery.Controller", + route: "search/:search" },"bad deparam"); - + equal( $.route.param({ search : "jQuery.Controller" }), "search/jQuery.Controller" , "bad param"); - + equal( $.route.param({ who : "jQuery.Controller" }), "jQuery.Controller" ); }) +test("precident2", function(){ + $.route.routes = {}; + $.route(":type",{who: "index"}); + $.route(":type/:id"); + + equal( $.route.param({ + type : "foo", + id: "bar" + }), + "foo/bar" ); +}) + test("linkTo", function(){ - var res = $.route.link("Hello",{foo: "bar"}); + $.route.routes = {}; + $.route(":foo"); + var res = $.route.link("Hello",{foo: "bar", baz: 'foo'}); + equal( res, 'Hello'); +}) + +test("param with route defined", function(){ + $.route.routes = {}; + $.route("holler") + $.route("foo"); + + var res = $.route.param({foo: "abc",route: "foo"}); + + equal(res, "foo&foo=abc") +}) + +test("route endings", function(){ + $.route.routes = {}; + $.route("foo",{foo: true}); + $.route("food",{food: true}) + + var res = $.route.deparam("food") + ok(res.food, "we get food back") + }) }) diff --git a/dom/selection/selection.html b/dom/selection/selection.html index 20840c29..536b16e5 100644 --- a/dom/selection/selection.html +++ b/dom/selection/selection.html @@ -11,68 +11,46 @@ - - - - - - - - - - - - - - - - - -
    Select Textarea
    Select Input
    Select Within One Element

    0123456789

    Select Across Multiple Elements
    012
    345
    - - -

    Hello World! how are you today?

    -

    I am good, thank you.

    -
    - - + + + Select Input + + + + Select Within One Element +

    0123456789

    + + + Select Across Multiple Elements +
    012
    345
    + + + src='../../../steal/steal.js'> \ No newline at end of file diff --git a/dom/selection/selection.js b/dom/selection/selection.js index 9343274f..45cc2280 100644 --- a/dom/selection/selection.js +++ b/dom/selection/selection.js @@ -195,10 +195,10 @@ getCharElement = function( elems , range, len ) { * returns an object with: * * - __start__ - The number of characters from the start of the element to the start of the selection. - * _ __end__ - The number of characters from teh start of the element to the end of the selection. - * _ __range__ - A [jQuery.Range] that represents the current selection. + * - __end__ - The number of characters from the start of the element to the end of the selection. + * - __range__ - A [jQuery.Range $.Range] that represents the current selection. * - * This lets you do: + * This lets you get the selected text in a textarea like: * * var textarea = $('textarea') * selection = textarea.selection(), @@ -206,7 +206,7 @@ getCharElement = function( elems , range, len ) { * * alert('You selected '+selected+'.'); * - * Selection works with all elements. If you want to get selection information on the page: + * Selection works with all elements. If you want to get selection information of the document: * * $(document.body).selection(); * @@ -216,9 +216,15 @@ getCharElement = function( elems , range, len ) { * * $('#rte').selection(30, 40) * - * @param {Number} [start] - Start of the range - * @param {Number} [end] - End of the range - * @return {Object|jQuery} - returns the selection information or the jQuery collection for + * ## Demo + * + * This demo shows setting the selection in various elements + * + * @demo jquery/dom/selection/selection.html + * + * @param {Number} [start] Start of the range + * @param {Number} [end] End of the range + * @return {Object|jQuery} returns the selection information or the jQuery collection for * chaining. */ $.fn.selection = function(start, end){ diff --git a/dom/selection/selection_test.js b/dom/selection/selection_test.js index 2a7e5131..28886444 100644 --- a/dom/selection/selection_test.js +++ b/dom/selection/selection_test.js @@ -12,7 +12,7 @@ test("getCharElement", function(){ setTimeout(function(){ var types = ['textarea','#inp','#1','#2']; for(var i =0; i< types.length; i++){ - console.log(types[i]) + //console.log(types[i]) $(types[i]).selection(1,5); } /* diff --git a/dom/within/within.js b/dom/within/within.js index 475c41c7..818a18e0 100644 --- a/dom/within/within.js +++ b/dom/within/within.js @@ -11,10 +11,18 @@ steal('jquery/dom').then(function($){ /** * @function within * @parent dom - * Returns if the elements are within the position - * @param {Number} left the position - * @param {Number} top - * @param {Boolean} [useOffsetCache] + * @plugin jquery/dom/within + * + * Returns the elements are within the position. + * + * // get all elements that touch 200x200. + * $('*').within(200, 200); + * + * @param {Number} left the position from the left of the page + * @param {Number} top the position from the top of the page + * @param {Boolean} [useOffsetCache] cache the dimensions and offset of the elements. + * @return {jQuery} a jQuery collection of elements whos area + * overlaps the element position. */ $.fn.within= function(left, top, useOffsetCache) { var ret = [] @@ -42,6 +50,7 @@ $.fn.within= function(left, top, useOffsetCache) { /** * @function withinBox + * @parent jQuery.fn.within * returns if elements are within the box * @param {Object} left * @param {Object} top @@ -56,7 +65,11 @@ $.fn.withinBox = function(left, top, width, height, cache){ if(this == document.documentElement) return this.ret.push(this); - var offset = cache ? jQuery.data(this,"offset", q.offset()) : q.offset(); + var offset = cache ? + jQuery.data(this,"offset") || + jQuery.data(this,"offset", q.offset()) : + q.offset(); + var ew = q.width(), eh = q.height(); diff --git a/download/download.html b/download/download.html index 83f69ac2..98535d6c 100644 --- a/download/download.html +++ b/download/download.html @@ -45,26 +45,6 @@

    Controller

    Organize event handlers using event delegation
    -
    - - - -
    Add page history support to Controller
    -
    - -
    - - - -
    Add pub/sub support to Controller
    -
    - -
    - - - -
    Helpers that tie view templates to a controller instance
    -
    @@ -82,12 +62,6 @@

    Model

    A basic skeleton to organize pieces of your application's data layer
    -
    - - - -
    Get data for related records
    -
    @@ -104,13 +78,6 @@

    Model

    -
    - - - -
    A storeable list of model instances
    -
    -