diff --git a/app/assistants/friends-followers-assistant.js b/app/assistants/friends-followers-assistant.js index 8009d26..fd12866 100644 --- a/app/assistants/friends-followers-assistant.js +++ b/app/assistants/friends-followers-assistant.js @@ -1,10 +1,10 @@ function FriendsFollowersAssistant() { - /* this is the creator function for your scene assistant object. It will be passed all the + /* this is the creator function for your scene assistant object. It will be passed all the additional parameters (after the scene name) that were passed to pushScene. The reference to the scene controller (this.controller) has not be established yet, so any initialization that needs the scene controller should be done in the setup function below. */ scene_helpers.addCommonSceneMethods(this); - + /* this connects App to this property of the appAssistant */ @@ -17,7 +17,7 @@ FriendsFollowersAssistant.prototype.setup = function() { var thisA = this; this.mode = 'friends'; - + this.scroller = this.controller.getSceneScroller(); this.initAppMenu({ 'items':LOGGEDIN_APPMENU_ITEMS }); this.initTwit('DOM'); @@ -43,7 +43,7 @@ FriendsFollowersAssistant.prototype.setup = function() { toggleCmd:'friends-followers', items: [ {label:$L('My Timeline'), icon:'conversation', command:'filter-timeline-all', shortcut:'T', 'class':"palm-header left"}, - {label:'@', icon:'at', command:'filter-timeline-replies'}, + {label:'@', icon:'at', command:'filter-timeline-replies'}, {label:$L('DM'), icon: 'dms', secondaryIconPath:'', command:'filter-timeline-dms'}, {label:$L('Favorites'), icon:'favorite', command:'favorites', shortcut:'F'}, {label:$L('Friends and Followers'), icon:'friends-followers', command:'friends-followers', shortcut:'L'}, @@ -53,33 +53,33 @@ FriendsFollowersAssistant.prototype.setup = function() { {} ] }); - + this.setCommand('friends-followers_friends', function(e) { thisA.mode = 'friends'; thisA.resetState(); thisA.refresh(); }); - + this.setCommand('friends-followers_followers', function(e) { thisA.mode = 'followers'; thisA.resetState(); thisA.refresh(); }); - - + + /* this function is for setup tasks that have to happen when the scene is first created */ - + /* use Luna.View.render to render view templates and add them to the scene, if needed. */ - + /* setup widgets here */ - + /* add event handlers to listen to events from widgets */ - + this.setupInlineSpinner('activity-spinner-friends-followers'); - + this.refreshOnActivate = true; - - + + this.controller.setupWidget("friends-followers-timeline", this.timeline_attributes = { itemTemplate: 'timeline-entry', @@ -99,7 +99,7 @@ FriendsFollowersAssistant.prototype.setup = function() { } ); this.timeline_list = this.controller.get('friends-followers-timeline'); - + /* more button */ @@ -112,41 +112,41 @@ FriendsFollowersAssistant.prototype.setup = function() { "buttonClass" : 'Primary' }; this.controller.setupWidget('more-friends-followers-button', this.moreButtonAttributes, this.moreButtonModel); - + this.listenForMetaTapScroll(); - + }; FriendsFollowersAssistant.prototype.activate = function(event) { /* put in event handlers here that should only be in effect when this scene is active. For example, key handlers that are observing the document */ - + // this.addPostPopup(); var thisA = this; // for closures below - + var tts = App.prefs.get('timeline-text-size'); this.setTimelineTextSize('#friends-followers-timeline', tts); - - + + /* Prepare for timeline entry taps */ this._handleTap = this.handleTap.bindAsEventListener(this); this.controller.listen('friends-followers-timeline', Mojo.Event.listTap, this._handleTap); - + /* - start the friends-followers timeline + start the friends-followers timeline */ if (this.refreshOnActivate) { this.refresh(); this.refreshOnActivate = false; } - - - + + + }; @@ -155,11 +155,11 @@ FriendsFollowersAssistant.prototype.deactivate = function(event) { stop listening for timeline entry taps */ this.controller.stopListening('friends-followers-timeline', Mojo.Event.listTap, this._handleTap); - + }; FriendsFollowersAssistant.prototype.cleanup = function(event) { - jQuery('#more-friends-followers-button').unbind(Mojo.Event.tap); + jQuery('#more-friends-followers-button').unbind(Mojo.Event.tap); }; @@ -171,24 +171,24 @@ FriendsFollowersAssistant.prototype.getEntryElementByStatusId = function(id) { FriendsFollowersAssistant.prototype.refresh = function(event) { var thisA = this; - + var method_name = 'getFriendsList'; - + var cursor = -1; if (event !== null && (sch.isNumber(event) || sch.isString(event))) { cursor = event; } - + Mojo.Log.error('CURSOR:%s', cursor); - + this.showInlineSpinner('activity-spinner-friends-followers', $L('Loading users…')); - + /* reset scrollstate to avoid white flash */ var scrollstate = this.scroller.mojo.getState(); this.scroller.mojo.setState(scrollstate, false); - + if (this.mode === 'friends') { method_name = 'getFriendsList'; } else if (this.mode === 'followers') { @@ -197,13 +197,13 @@ FriendsFollowersAssistant.prototype.refresh = function(event) { Mojo.Log.error('Invalid mode:%s', this.mode); return; } - - + + this.twit[method_name]( '@'+App.username, cursor, function(data, cursor_obj) { - + /* if mode is wrong, don't add */ @@ -214,12 +214,12 @@ FriendsFollowersAssistant.prototype.refresh = function(event) { thisA.hideInlineSpinner('activity-spinner-friends-followers'); return; } - + if (sch.isArray(data)) { - + // data = data.reverse(); var no_dupes = []; - + for (var i=0; i < data.length; i++) { // Mojo.Log.error('data[i]: %s', data[i].id); /* @@ -229,25 +229,25 @@ FriendsFollowersAssistant.prototype.refresh = function(event) { App.Tweets.saveUser(data[i]); no_dupes.push(data[i]); } - + }; - + Mojo.Log.error('no_dupes.length:%s', no_dupes.length); - + thisA.addItems(no_dupes); - + } - + if (cursor_obj && cursor_obj.next) { thisA.friends_more_cursor = cursor_obj.next; } - + thisA.hideInlineSpinner('activity-spinner-friends-followers'); }, function(xhr, msg, exc) { Mojo.Log.error('EROROR in getFriends'); Mojo.Log.error("%j , %j , %j", xhr, msg, exc); - + var err_msg = $L("There was an error retrieving users"); thisA.displayErrorInfo(err_msg, null); @@ -257,16 +257,16 @@ FriendsFollowersAssistant.prototype.refresh = function(event) { thisA.hideInlineSpinner('activity-spinner-friends-followers'); } ); - + }; FriendsFollowersAssistant.prototype.loadMore = function(event) { - + // if (this.timeline_model && this.timeline_model.items && this.timeline_model.items.length) { // this.friends_more_cursor = this.timeline_model.items[this.timeline_model.items.length-1].id; // } Mojo.Log.error('this.friends_more_cursor: %s', this.friends_more_cursor); - + this.refresh(this.friends_more_cursor); }; @@ -275,10 +275,10 @@ FriendsFollowersAssistant.prototype.loadMore = function(event) { redefine addItems to work with list model */ FriendsFollowersAssistant.prototype.addItems = function(new_items) { - + // now we have all the existing items from the model var model_items = this.timeline_model.items.clone(); - + var model_item; for (var i=0; i < new_items.length; i++) { model_item = { @@ -289,19 +289,19 @@ FriendsFollowersAssistant.prototype.addItems = function(new_items) { // add each item to the model model_items.push(model_item); } - + // sort // model_items.sort(function(a,b){ // Mojo.Log.error('a.created %s, b.created %s', a.created, b.created); // return a.created - b.created; // newest first // }); - + // re-assign the cloned items back to the model object this.timeline_model.items = model_items; - + // tell the controller it's changed to update list widget this.controller.modelChanged(this.timeline_model); - + /* reset scrollstate to avoid white flash */ @@ -311,7 +311,7 @@ FriendsFollowersAssistant.prototype.addItems = function(new_items) { FriendsFollowersAssistant.prototype.renderItem = function(obj) { - + var html = ''; Mojo.Timing.resume("timing_friends-followers-timeline.renderer"); @@ -319,20 +319,20 @@ FriendsFollowersAssistant.prototype.renderItem = function(obj) { html = App.tpl.parseTemplate('follower_row', obj); Mojo.Timing.pause("timing_friends-followers-timeline.renderer"); return html; - + } catch(err) { sch.error("There was an error rendering the object: "+sch.enJSON(obj)); sch.error("Error:"+sch.enJSON(err)); Mojo.Timing.pause("timing_friends-followers-timeline.renderer"); - + return ''; } - + }; FriendsFollowersAssistant.prototype.itemExistsInModel = function(obj) { - + for (var i=0; i < this.timeline_model.items.length; i++) { if (this.timeline_model.items[i].id == obj.id) { sch.error(obj.id +' exists in model'); diff --git a/app/assistants/preferences-assistant.js b/app/assistants/preferences-assistant.js index 57c9890..b30c361 100644 --- a/app/assistants/preferences-assistant.js +++ b/app/assistants/preferences-assistant.js @@ -1,11 +1,11 @@ function PreferencesAssistant() { - /* this is the creator function for your scene assistant object. It will be passed all the + /* this is the creator function for your scene assistant object. It will be passed all the additional parameters (after the scene name) that were passed to pushScene. The reference to the scene controller (this.controller) has not be established yet, so any initialization that needs the scene controller should be done in the setup function below. */ - + scene_helpers.addCommonSceneMethods(this); - + /* this connects App to this property of the appAssistant */ @@ -17,11 +17,11 @@ PreferencesAssistant.prototype.aboutToActivate = function(callback){ }; PreferencesAssistant.prototype.setup = function() { - + var thisA = this; this.scroller = this.controller.getSceneScroller(); - + this.initAppMenu({ 'items':[ Mojo.Menu.editItem, { label: $L('New Search Card'), command: 'new-search-card' }, @@ -30,19 +30,19 @@ PreferencesAssistant.prototype.setup = function() { { label: $L('Help...'), command:Mojo.Menu.helpCmd }, { label: $L('Donate...'), command:'donate' } ]}); - + this.setupCommonMenus({ viewMenuItems: [ { items:[ - {label: $L("Preferences"), command:'scroll-top', 'class':"palm-header left", width:320} + {label: $L("Preferences"), command:'scroll-top', 'class':"palm-header left", width:320} ] } ] }); - - + + /* note that these property keys MUST match a preference key */ @@ -69,14 +69,14 @@ PreferencesAssistant.prototype.setup = function() { 'post-rt-cursor-position': App.prefs.get('post-rt-cursor-position'), 'post-send-on-enter': App.prefs.get('post-send-on-enter'), 'timeline-absolute-timestamps': App.prefs.get('timeline-absolute-timestamps') - + }; - - + + /* Setup checkboxes */ - + /* temporarily disabling sound and vibration prefs until we can sort out how to tell if sound is off */ @@ -115,7 +115,7 @@ PreferencesAssistant.prototype.setup = function() { }, this.model ); - + /* Notification preferences @@ -168,7 +168,7 @@ PreferencesAssistant.prototype.setup = function() { }, this.model ); - + this.controller.setupWidget("checkbox-post-send-on-enter", this.soundEnabledAtts = { fieldName: 'post-send-on-enter', @@ -177,7 +177,7 @@ PreferencesAssistant.prototype.setup = function() { }, this.model ); - + this.controller.setupWidget("checkbox-timeline-absolute-timestamps", this.soundEnabledAtts = { fieldName: 'timeline-absolute-timestamps', @@ -186,7 +186,7 @@ PreferencesAssistant.prototype.setup = function() { }, this.model ); - + /* temporarily disabling sound and vibration prefs until we can sort out how to tell if sound is off */ @@ -204,7 +204,7 @@ PreferencesAssistant.prototype.setup = function() { /* - Setup refresh rate widgets + Setup refresh rate widgets */ this.setupChoices(); @@ -258,8 +258,8 @@ PreferencesAssistant.prototype.setup = function() { this.controller.listen('timeline-friends-getcount', Mojo.Event.propertyChange, this.saveSettings.bindAsEventListener(this)); this.controller.listen('timeline-replies-getcount', Mojo.Event.propertyChange, this.saveSettings.bindAsEventListener(this)); this.controller.listen('timeline-dm-getcount', Mojo.Event.propertyChange, this.saveSettings.bindAsEventListener(this)); - - + + this.controller.setupWidget('timeline-text-size', { label: $L('Timeline Text Size'), @@ -292,7 +292,7 @@ PreferencesAssistant.prototype.setup = function() { this.controller.listen('post-rt-cursor-position', Mojo.Event.propertyChange, this.saveSettings.bindAsEventListener(this)); - + this.controller.setupWidget('image-uploader', { label: $L('service'), @@ -302,7 +302,7 @@ PreferencesAssistant.prototype.setup = function() { this.model ); this.controller.listen('image-uploader', Mojo.Event.propertyChange, this.saveSettings.bindAsEventListener(this)); - + /* clear cache button */ @@ -319,7 +319,7 @@ PreferencesAssistant.prototype.setup = function() { * saves the current values of the selectors */ PreferencesAssistant.prototype.saveSettings = function(event) { - + for (var key in this.model) { App.prefs.set(key, this.model[key]); if (this.onSave[key]) { @@ -329,7 +329,7 @@ PreferencesAssistant.prototype.saveSettings = function(event) { }; /** - * a hash of functions to call on save for certain prefs + * a hash of functions to call on save for certain prefs */ PreferencesAssistant.prototype.onSave = { 'network-refreshinterval' : function(e, val) { @@ -354,11 +354,11 @@ PreferencesAssistant.prototype.onSave = { //function declares & initializes our choice arrays PreferencesAssistant.prototype.setupChoices = function(){ - + // Options for list selector choices: this.validTimes = [ - {label:$L('Never'), value:0}, - {label:$L('5min'), value:300000}, + {label:$L('Never'), value:0}, + {label:$L('5min'), value:300000}, {label:$L('10min'), value:600000}, {label:$L('15min'), value:900000}, {label:$L('30min'), value:1800000}, @@ -367,7 +367,7 @@ PreferencesAssistant.prototype.setupChoices = function(){ {label:$L('4hr'), value:14400000}, {label:$L('8hr'), value:28800000} ]; - + this.validInitialLoads = [ {label:$L('2'), value:2}, {label:$L('5'), value:5}, @@ -378,7 +378,7 @@ PreferencesAssistant.prototype.setupChoices = function(){ {label:$L('100'), value:100}, {label:$L('200'), value:200} ]; - + this.validInitialLoadsDmReply = [ {label:$L('2'), value:2}, {label:$L('5'), value:5}, @@ -387,25 +387,25 @@ PreferencesAssistant.prototype.setupChoices = function(){ {label:$L('40'), value:40}, {label:$L('60'), value:60}, {label:$L('100'), value:100}, - {label:$L('200'), value:200} + {label:$L('200'), value:200} ]; - + this.validTimelineTextSizes = [ - {label:$L('Tall'), value:'tall'}, - {label:$L('Grande'),value:'grande'}, - {label:$L('Venti'), value:'venti'} + {label:$L('Tall'), value:'tall'}, + {label:$L('Grande'),value:'grande'}, + {label:$L('Venti'), value:'venti'} ]; - + this.validAppThemes = []; for(var tkey in AppThemes) { this.validAppThemes.push({label:tkey, value:tkey}); } - + this.validRTCursorPositions = [ - {label:$L('Beginning'), value:'beginning'}, + {label:$L('Beginning'), value:'beginning'}, {label:$L('End'),value:'end'} ]; - + var image_uploader = new SpazImageUploader(); this.validImageUploaders = []; for (var key in image_uploader.services) { @@ -414,6 +414,8 @@ PreferencesAssistant.prototype.setupChoices = function(){ } }; +PreferencesAssistant.prototype.refresh = function() { +}; PreferencesAssistant.prototype.activate = function(event) { @@ -428,10 +430,10 @@ PreferencesAssistant.prototype.deactivate = function(event) { }; PreferencesAssistant.prototype.cleanup = function(event) { - /* this function should do any cleanup needed before the scene is destroyed as + /* this function should do any cleanup needed before the scene is destroyed as a result of being popped off the scene stack */ - - + + this.controller.stopListening('network-refreshinterval', Mojo.Event.propertyChange, this.saveSettings); this.controller.stopListening('network-searchrefreshinterval', Mojo.Event.propertyChange, this.saveSettings); this.controller.stopListening('timeline-friends-getcount', Mojo.Event.propertyChange, this.saveSettings); @@ -444,7 +446,7 @@ PreferencesAssistant.prototype.cleanup = function(event) { Mojo.Event.stopListening(jQuery('#clear-cache-button')[0], Mojo.Event.tap, function(e) { thisA.clearTimelineCache(); }); - + /* temporarily disabling sound and vibration prefs until we can sort out how to tell if sound is off */ @@ -457,12 +459,12 @@ PreferencesAssistant.prototype.cleanup = function(event) { this.controller.stopListening('checkbox-notify-mentions', Mojo.Event.propertyChange, this.saveSettings); this.controller.stopListening('checkbox-notify-dms', Mojo.Event.propertyChange, this.saveSettings); this.controller.stopListening('checkbox-notify-searchresults', Mojo.Event.propertyChange, this.saveSettings); - + }; -PreferencesAssistant.prototype.considerForNotification = function(params){ +PreferencesAssistant.prototype.considerForNotification = function(params){ Mojo.Log.error('NOTIFICATION RECEIVED in PreferencesAssistant:%j', params); - - return params; + + return params; }; diff --git a/app/assistants/search-twitter-assistant.js b/app/assistants/search-twitter-assistant.js index ec28414..51007bb 100644 --- a/app/assistants/search-twitter-assistant.js +++ b/app/assistants/search-twitter-assistant.js @@ -1,21 +1,21 @@ /** * events raised here: - * 'search_timeline_refresh' + * 'search_timeline_refresh' */ function SearchTwitterAssistant(args) { - /* this is the creator function for your scene assistant object. It will be passed all the + /* this is the creator function for your scene assistant object. It will be passed all the additional parameters (after the scene name) that were passed to pushScene. The reference to the scene controller (this.controller) has not be established yet, so any initialization that needs the scene controller should be done in the setup function below. */ - + scene_helpers.addCommonSceneMethods(this); - + /* this connects App to this property of the appAssistant */ App = Spaz.getAppObj(); - + if (args && args.searchterm) { this.passedSearch = args.searchterm; } @@ -23,10 +23,10 @@ function SearchTwitterAssistant(args) { /* we may be in a new stage, so need to init prefs if they don't exist */ - + this.lightweight = true; } - + if (args && args.saved_id > 0) { this.isSavedSearch = true; this.saved_id = args.saved_id; @@ -34,12 +34,12 @@ function SearchTwitterAssistant(args) { this.isSavedSearch = false; this.saved_id = null; } - + /* this property will hold the setInterval return */ this.refresher = null; - + this.lastQuery = ''; } @@ -49,19 +49,19 @@ SearchTwitterAssistant.prototype.aboutToActivate = function(callback){ SearchTwitterAssistant.prototype.setup = function() { /* this function is for setup tasks that have to happen when the scene is first created */ - + /* use Mojo.View.render to render view templates and add them to the scene, if needed. */ var thisA = this; this.scroller = this.controller.getSceneScroller(); - + this.initTwit(); - + this.trackStageActiveState(); - - + + /* view and command menus */ @@ -70,7 +70,7 @@ SearchTwitterAssistant.prototype.setup = function() { viewMenuItems: [ { items:[ - {label: $L("Search & Explore"), command:'scroll-top', 'class':"palm-header left", width:320} + {label: $L("Search & Explore"), command:'scroll-top', 'class':"palm-header left", width:320} ] } @@ -82,29 +82,29 @@ SearchTwitterAssistant.prototype.setup = function() { {label:$L('Compose'), icon:'compose', command:'compose', shortcut:'N'}, {}, {label:$L('Save search'), icon:'favorite-outline', command:'save-search', shortcut:'S'}, - {label:$L('Refresh'), icon:'sync', command:'refresh', shortcut:'R'} + {label:$L('Refresh'), icon:'sync', command:'refresh', shortcut:'R'} ] }); - - this.initAppMenu({ 'items':LOGGEDIN_APPMENU_ITEMS }); + + this.initAppMenu({ 'items':LOGGEDIN_APPMENU_ITEMS }); } else { this.setupCommonMenus({ viewMenuItems: [ { items:[ - {label: $L("Search & Explore"), command:'scroll-top', 'class':"palm-header left", width:320} + {label: $L("Search & Explore"), command:'scroll-top', 'class':"palm-header left", width:320} ] } ], cmdMenuItems: [ {}, - {label:$L('Refresh'), icon:'sync', command:'refresh', shortcut:'R'} + {label:$L('Refresh'), icon:'sync', command:'refresh', shortcut:'R'} ] - + }); - - this.initAppMenu(); + + this.initAppMenu(); } @@ -134,14 +134,14 @@ SearchTwitterAssistant.prototype.setup = function() { jQuery('#submit-search-button').bind(Mojo.Event.tap, function() { thisA.search.call(thisA, thisA.searchBoxModel.value, null, 1); }); - + this.searchButtonAttributes = { "type": Mojo.Widget.activityButton }; this.searchButtonModel = { "buttonLabel" : "Search", "buttonClass" : 'Primary' - }; + }; this.controller.setupWidget('submit-search-button', this.searchButtonAttributes, this.searchButtonModel); @@ -162,31 +162,33 @@ SearchTwitterAssistant.prototype.setup = function() { this.timeline_model = { items : [] } - ); + ); this.timeline_list = this.controller.get('search-timeline'); // this.refresh(); - + if (this.isSavedSearch) { this.fillStar(true); } else { this.fillStar(false); } - + /* more button */ jQuery('#more-search-button').bind(Mojo.Event.tap, function() { thisA.loadMore.call(thisA); }); - this.moreButtonAttributes = {}; + this.moreButtonAttributes = { + "type": Mojo.Widget.activityButton + }; this.moreButtonModel = { "buttonLabel" : "More", "buttonClass" : 'Primary' }; this.controller.setupWidget('more-search-button', this.moreButtonAttributes, this.moreButtonModel); - + this.listenForMetaTapScroll(); }; @@ -197,49 +199,49 @@ SearchTwitterAssistant.prototype.activate = function(event) { var thisA = this; // for closures - + if (event && event.searchterm) { this.passedSearch = event.searchterm; } - - + + if (this.passedSearch) { this.searchBoxModel.value = this.passedSearch.replace(/"/gi, '"'); // convert the entities back into "'s this.controller.modelChanged(this.searchBoxModel); this.search(this.passedSearch); this.passedSearch = null; // eliminate this so it isn't used anymore } - - + + var tts = App.prefs.get('timeline-text-size'); this.setTimelineTextSize('#search-timeline', tts); - - - + + + jQuery(document).bind('search_timeline_refresh', function(e) { thisA.markAllAsRead(); thisA.refresh(); }); - + this.listenForEnter('search-twitter-textfield', function() { thisA.controller.get('submit-search-button').mojo.activate(); thisA.search(thisA.searchBoxModel.value, null, 1); }); - + /* Prepare for timeline entry taps */ this.bindTimelineEntryTaps('search-timeline'); - + }; SearchTwitterAssistant.prototype.deactivate = function(event) { - jQuery(document).unbind('search_timeline_refresh'); - + jQuery(document).unbind('search_timeline_refresh'); + Mojo.Log.error('DEACTIVATE'); - + /* stop listening for timeline entry taps */ @@ -249,50 +251,48 @@ SearchTwitterAssistant.prototype.deactivate = function(event) { SearchTwitterAssistant.prototype.cleanup = function(event) { jQuery('#submit-search-button').unbind(Mojo.Event.tap); - + jQuery('#more-search-button').unbind(Mojo.Event.tap); - + this.stopListeningForEnter('search-twitter-textfield'); - + this.stopTrackingStageActiveState(); - + }; -SearchTwitterAssistant.prototype.search = function(e, type, page) { +SearchTwitterAssistant.prototype.search = function(e, type, since_id) { var thisA = this; var search_string; - - if (type && type.toLowerCase() == 'refresh') { // empty unless this is a refresh + + type = type ? type.toLowerCase() : ""; + + if (type == 'refresh') { // empty unless this is a refresh this.scrollToTop(); this.markAllAsRead(); - } else if (type && type.toLowerCase() == 'loadmore') { + } else if (type == 'loadmore') { this.markAllAsRead(); } else { - this.clear(); + this.clear(); } - + if (sch.isString(e)) { search_string = e; } else if (e.value && sch.isString(e.value)) { search_string = e.value; } - - if (!page) { - page = 1; - } - + Mojo.Log.info("Searching for: %s", search_string); - + /* clear any existing results */ if (search_string !== this.lastQuery) { this.clear(); } - + this.lastQuery = sch.fromHTMLSpecialChars(search_string); Mojo.Log.info('refresh()'); @@ -301,8 +301,8 @@ SearchTwitterAssistant.prototype.search = function(e, type, page) { thisA.markAllAsRead(); } - this.activateSpinner(); - + this.activateSpinner(type); + /* reset scrollstate to avoid white flash */ @@ -315,16 +315,17 @@ SearchTwitterAssistant.prototype.search = function(e, type, page) { thisA.twit.search( thisA.lastQuery, // query - null, // since_id - 100, // results_per_page - page, // page + since_id ? ('-' + since_id) : null, // since_id -> max_id + 10, // results_per_page + null, // page null, // lang null, // , geocode function(data, searchinfo) { // onSuccess - + Mojo.Log.error('searchinfo: %j', searchinfo); Mojo.Log.error('data: %j', data); - + thisA.max_id = searchinfo.max_id; + /* reverse the tweets for collection rendering (faster) */ @@ -344,10 +345,10 @@ SearchTwitterAssistant.prototype.search = function(e, type, page) { } } } - + thisA.addItems(no_dupes); - thisA.deactivateSpinner(); + thisA.deactivateSpinner(type); /* show a banner if need be @@ -363,7 +364,7 @@ SearchTwitterAssistant.prototype.search = function(e, type, page) { function(xhr, msg, exc) { // onFailure var err_msg = $L("There was an error loading the search results"); thisA.displayErrorInfo(err_msg, null); - thisA.deactivateSpinner(); + thisA.deactivateSpinner(type); } ); @@ -378,27 +379,21 @@ SearchTwitterAssistant.prototype.search = function(e, type, page) { */ this.checkInternetStatus( getSearchTimeline ); - + }; SearchTwitterAssistant.prototype.refresh = function(event) { var page = 1; - + if (event && sch.isNumber(event)) { page = event; } this.search(this.searchBoxModel.value, 'refresh', page); }; SearchTwitterAssistant.prototype.loadMore = function(event) { - if (this.search_more_page) { - this.search_more_page++; - } else { - this.search_more_page = 2; - } - - this.search(this.searchBoxModel.value, 'loadmore', this.search_more_page); + this.search(this.searchBoxModel.value, 'loadmore', this.max_id); }; @@ -413,12 +408,12 @@ SearchTwitterAssistant.prototype.clear = function() { redefine addItems to work with list model */ SearchTwitterAssistant.prototype.addItems = function(new_items) { - + Mojo.Log.error("addItems"); - + // now we have all the existing items from the model var model_items = this.timeline_model.items.clone(); - + var model_item; for (var i=0; i < new_items.length; i++) { model_item = { @@ -427,20 +422,20 @@ SearchTwitterAssistant.prototype.addItems = function(new_items) { }; // add each item to the model model_items.push(model_item); - + } - + // sort, in reverse model_items.sort(function(a,b){ return b.data.SC_created_at_unixtime - a.data.SC_created_at_unixtime; // newest first }); - + // re-assign the cloned items back to the model object this.timeline_model.items = model_items; - + // this filters and updates the model this.controller.modelChanged(this.timeline_model); - + /* reset scrollstate to avoid white flash */ @@ -450,7 +445,7 @@ SearchTwitterAssistant.prototype.addItems = function(new_items) { SearchTwitterAssistant.prototype.renderItem = function(obj) { - + var html = ''; Mojo.Timing.resume("timing_SearchTwitterAssistant.renderer"); @@ -462,19 +457,19 @@ SearchTwitterAssistant.prototype.renderItem = function(obj) { } Mojo.Timing.pause("timing_SearchTwitterAssistant.renderer"); return html; - + } catch(err) { sch.error("There was an error rendering the object: "+sch.enJSON(obj)); sch.error("Error:"+sch.enJSON(err)); Mojo.Timing.pause("timing_SearchTwitterAssistant.renderer"); - + return ''; } - + }; SearchTwitterAssistant.prototype.itemExistsInModel = function(obj) { - + for (var i=0; i < this.timeline_model.items.length; i++) { if (this.timeline_model.items[i].id == obj.id) { @@ -492,36 +487,46 @@ SearchTwitterAssistant.prototype.itemExistsInModel = function(obj) { * loop through items in timeline_model and set Spaz_is_new = false, Spaz_is_read = true */ SearchTwitterAssistant.prototype.markAllAsRead = function() { - + Mojo.Log.error("markAllAsRead"); - + Mojo.Timing.resume("timing_html_markAllAsRead"); - + for (var i=0; i < this.timeline_model.items.length; i++) { this.timeline_model.items[i].data.Spaz_is_new = false; this.timeline_model.items[i].data.Spaz_is_read = true; } - + Mojo.Timing.pause("timing_html_markAllAsRead"); - + Mojo.Log.error(Mojo.Timing.createTimingString("timing_html", "Updating HTML element times")); - + this.controller.modelChanged(this.timeline_model); }; -SearchTwitterAssistant.prototype.activateSpinner = function() { - this.buttonWidget = this.controller.get('submit-search-button'); - this.buttonWidget.mojo.activate(); +SearchTwitterAssistant.prototype.activateSpinner = function(type) { + if (type == 'loadmore') { + var buttonWidget = this.controller.get('more-search-button'); + buttonWidget.mojo.activate(); + } else { + var buttonWidget = this.controller.get('submit-search-button'); + buttonWidget.mojo.activate(); + } }; -SearchTwitterAssistant.prototype.deactivateSpinner = function() { - this.buttonWidget = this.controller.get('submit-search-button'); - this.buttonWidget.mojo.deactivate(); +SearchTwitterAssistant.prototype.deactivateSpinner = function(type) { + if (type == 'loadmore') { + var buttonWidget = this.controller.get('more-search-button'); + buttonWidget.mojo.deactivate(); + } else { + var buttonWidget = this.controller.get('submit-search-button'); + buttonWidget.mojo.deactivate(); + } }; SearchTwitterAssistant.prototype.saveSearch = function(searchstr) { - + var thisA = this; jQuery(document).bind('create_saved_search_succeeded', {thisAssistant:this}, function(e, resp) { @@ -532,14 +537,14 @@ SearchTwitterAssistant.prototype.saveSearch = function(searchstr) { thisA.twit.getSavedSearches(); // this will force a refresh on any listeners jQuery(document).unbind('create_saved_search_succeeded'); }); - + this.twit.addSavedSearch(searchstr); - + }; SearchTwitterAssistant.prototype.removeSearch = function(searchstr) { - + var thisA = this; jQuery(document).bind('destroy_saved_search_succeeded', {thisAssistant:this}, function(e, resp) { @@ -553,7 +558,7 @@ SearchTwitterAssistant.prototype.removeSearch = function(searchstr) { // alert(thisA.saved_id); this.twit.removeSavedSearch(thisA.saved_id); - + }; SearchTwitterAssistant.prototype.fillStar = function(fill) { @@ -566,4 +571,3 @@ SearchTwitterAssistant.prototype.fillStar = function(fill) { this.controller.modelChanged(this.cmdMenuModel); } }; - diff --git a/spazcore/spazcore-webos.js b/spazcore/spazcore-webos.js index 6571942..862ca68 100644 --- a/spazcore/spazcore-webos.js +++ b/spazcore/spazcore-webos.js @@ -1,5 +1,5 @@ /*********** Built 2011-06-01 14:39:47 CDT ***********/ -/*jslint +/*jslint browser: true, nomen: false, debug: true, @@ -7,37 +7,37 @@ forin: true, regexp: false, undef: true, white: false, -onevar: false +onevar: false */ /** * SPAZCORE * version 0.1.1 * 2009-08-06 - * + * * License - * + * * Copyright (c) 2008-2009, Edward Finkler, Funkatron Productions - * + * * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * + * * Neither the name of Edward Finkler, Funkatron Productions nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. - * - * + * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -48,2301 +48,2304 @@ onevar: false * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * + * + * * SpazCore includes code from other software projects. Their licenses follow: - * + * * date.js * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved. * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. - * + * * webtoolkit.info (hash libs, trim funcs, utf8 encoder/decoder) * http://www.webtoolkit.info/ * As long as you leave the copyright notice of the original script, or link * back to this website, you can use any of the content published on this * website free of charge for any use: commercial or noncommercial. */ - + /** - * @namespace + * @namespace */ var sc = {}; -/** - * @namespace - */ -sc.app = {}; +/** + * @namespace + */ +sc.app = {}; + +/** + * @namespace + */ +sc.helpers = {}; + +/** + * dump level for limiting what gets dumped to console + */ +sc.dumplevel = 1; + +/** + * method to set dump level + */ +sc.setDumpLevel = function(level) { + sc.dumplevel = parseInt(level, 10); +}; + +/** + * @namespace helper shortcuts + * this lets us write "sch.method" instead of "sc.helpers.method" + * + */ +var sch = sc.helpers; + + +sc.events = {}; + + + +/** + * various constant definitions that aren't specific to a single library + */ + +/** + * @constant + */ +var SPAZCORE_SERVICE_TWITTER = 'twitter'; +/** + * @constant + */ +var SPAZCORE_SERVICE_IDENTICA = 'identi.ca'; +/** + * @constant + */ +var SPAZCORE_SERVICE_FREELISHUS = 'freelish.us'; +/** + * @constant + */ +var SPAZCORE_SERVICE_WORDPRESS_TWITTER = 'wordpress-twitter'; +/** + * @constant + */ +var SPAZCORE_SERVICE_TUMBLR_TWITTER = 'tumblr-twitter'; +/** + * @constant + */ +var SPAZCORE_SERVICE_CUSTOM = 'custom'; + +/** + * @constant + */ +var SPAZCORE_BASEURL_TWITTER = 'https://twitter.com/'; +/** + * @constant + */ +var SPAZCORE_BASEURL_IDENTICA = 'https://identi.ca/'; +/** + * @constant + */ +var SPAZCORE_BASEURL_FREELISHUS = 'http://freelish.us/'; +/** + * @constant + */ +var SPAZCORE_APIVERSION_TWITTER = '1.1'; + + +/** + * Build the helpers + * @depends ../helpers/datetime.js + * @depends ../helpers/event.js + * @depends ../helpers/javascript.js + * @depends ../helpers/json.js + * @depends ../helpers/location.js + * @depends ../helpers/string.js + * @depends ../helpers/sys.js + * @depends ../helpers/view.js + * @depends ../helpers/xml.js + * + * Build the libs + * @depends spazcron.js + * @depends spazlocker.js + * @depends spazphotomailer.js + * @depends spazpingfm.js + * @depends spazprefs.js + * @depends spazshorttext.js + * @depends spazshorturl.js + * @depends spaztemplate.js + * @depends spaztimeline.js + * @depends spaztwit.js + */ +Date.CultureInfo = { + /* Culture Name */ + name: "en-US", + englishName: "English (United States)", + nativeName: "English (United States)", + + /* Day Name Strings */ + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"], + + /* Month Name Strings */ + monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + + /* AM/PM Designators */ + amDesignator: "AM", + pmDesignator: "PM", + + firstDayOfWeek: 0, + twoDigitYearMax: 2029, + + /** + * The dateElementOrder is based on the order of the + * format specifiers in the formatPatterns.DatePattern. + * + * Example: +
+ shortDatePattern dateElementOrder + ------------------ ---------------- + "M/d/yyyy" "mdy" + "dd/MM/yyyy" "dmy" + "yyyy-MM-dd" "ymd" ++ * + * The correct dateElementOrder is required by the parser to + * determine the expected order of the date elements in the + * string being parsed. + */ + dateElementOrder: "mdy", + + /* Standard date and time format patterns */ + formatPatterns: { + shortDate: "M/d/yyyy", + longDate: "dddd, MMMM dd, yyyy", + shortTime: "h:mm tt", + longTime: "h:mm:ss tt", + fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt", + sortableDateTime: "yyyy-MM-ddTHH:mm:ss", + universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", + rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", + monthDay: "MMMM dd", + yearMonth: "MMMM, yyyy" + }, + + /** + * NOTE: If a string format is not parsing correctly, but + * you would expect it parse, the problem likely lies below. + * + * The following regex patterns control most of the string matching + * within the parser. + * + * The Month name and Day name patterns were automatically generated + * and in general should be (mostly) correct. + * + * Beyond the month and day name patterns are natural language strings. + * Example: "next", "today", "months" + * + * These natural language string may NOT be correct for this culture. + * If they are not correct, please translate and edit this file + * providing the correct regular expression pattern. + * + * If you modify this file, please post your revised CultureInfo file + * to the Datejs Forum located at http://www.datejs.com/forums/. + * + * Please mark the subject of the post with [CultureInfo]. Example: + * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark) + * + * We will add the modified patterns to the master source files. + * + * As well, please review the list of "Future Strings" section below. + */ + regexPatterns: { + jan: /^jan(uary)?/i, + feb: /^feb(ruary)?/i, + mar: /^mar(ch)?/i, + apr: /^apr(il)?/i, + may: /^may/i, + jun: /^jun(e)?/i, + jul: /^jul(y)?/i, + aug: /^aug(ust)?/i, + sep: /^sep(t(ember)?)?/i, + oct: /^oct(ober)?/i, + nov: /^nov(ember)?/i, + dec: /^dec(ember)?/i, + + sun: /^su(n(day)?)?/i, + mon: /^mo(n(day)?)?/i, + tue: /^tu(e(s(day)?)?)?/i, + wed: /^we(d(nesday)?)?/i, + thu: /^th(u(r(s(day)?)?)?)?/i, + fri: /^fr(i(day)?)?/i, + sat: /^sa(t(urday)?)?/i, + + future: /^next/i, + past: /^last|past|prev(ious)?/i, + add: /^(\+|aft(er)?|from|hence)/i, + subtract: /^(\-|bef(ore)?|ago)/i, + + yesterday: /^yes(terday)?/i, + today: /^t(od(ay)?)?/i, + tomorrow: /^tom(orrow)?/i, + now: /^n(ow)?/i, + + millisecond: /^ms|milli(second)?s?/i, + second: /^sec(ond)?s?/i, + minute: /^mn|min(ute)?s?/i, + hour: /^h(our)?s?/i, + week: /^w(eek)?s?/i, + month: /^m(onth)?s?/i, + day: /^d(ay)?s?/i, + year: /^y(ear)?s?/i, + + shortMeridian: /^(a|p)/i, + longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i, + timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i, + ordinalSuffix: /^\s*(st|nd|rd|th)/i, + timeContext: /^\s*(\:|a(?!u|p)|p)/i + }, + + timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}] +}; + +/******************** + ** Future Strings ** + ******************** + * + * The following list of strings may not be currently being used, but + * may be incorporated into the Datejs library later. + * + * We would appreciate any help translating the strings below. + * + * If you modify this file, please post your revised CultureInfo file + * to the Datejs Forum located at http://www.datejs.com/forums/. + * + * Please mark the subject of the post with [CultureInfo]. Example: + * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b + * + * English Name Translated + * ------------------ ----------------- + * about about + * ago ago + * date date + * time time + * calendar calendar + * show show + * hourly hourly + * daily daily + * weekly weekly + * bi-weekly bi-weekly + * fortnight fortnight + * monthly monthly + * bi-monthly bi-monthly + * quarter quarter + * quarterly quarterly + * yearly yearly + * annual annual + * annually annually + * annum annum + * again again + * between between + * after after + * from now from now + * repeat repeat + * times times + * per per + * min (abbrev minute) min + * morning morning + * noon noon + * night night + * midnight midnight + * mid-night mid-night + * evening evening + * final final + * future future + * spring spring + * summer summer + * fall fall + * winter winter + * end of end of + * end end + * long long + * short short + *//** + * @version: 1.0 Alpha-1 + * @author: Coolite Inc. http://www.coolite.com/ + * @date: 2008-04-13 + * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved. + * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. + * @website: http://www.datejs.com/ + */ + +(function () { + var $D = Date, + $P = $D.prototype, + $C = $D.CultureInfo, + p = function (s, l) { + if (!l) { + l = 2; + } + return ("000" + s).slice(l * -1); + }; + + /** + * Resets the time of this Date object to 12:00 AM (00:00), which is the start of the day. + * @param {Boolean} .clone() this date instance before clearing Time + * @return {Date} this + */ + $P.clearTime = function () { + this.setHours(0); + this.setMinutes(0); + this.setSeconds(0); + this.setMilliseconds(0); + return this; + }; + + /** + * Resets the time of this Date object to the current time ('now'). + * @return {Date} this + */ + $P.setTimeToNow = function () { + var n = new Date(); + this.setHours(n.getHours()); + this.setMinutes(n.getMinutes()); + this.setSeconds(n.getSeconds()); + this.setMilliseconds(n.getMilliseconds()); + return this; + }; + + /** + * Gets a date that is set to the current date. The time is set to the start of the day (00:00 or 12:00 AM). + * @return {Date} The current date. + */ + $D.today = function () { + return new Date().clearTime(); + }; + + /** + * Compares the first date to the second date and returns an number indication of their relative values. + * @param {Date} First Date object to compare [Required]. + * @param {Date} Second Date object to compare to [Required]. + * @return {Number} -1 = date1 is lessthan date2. 0 = values are equal. 1 = date1 is greaterthan date2. + */ + $D.compare = function (date1, date2) { + if (isNaN(date1) || isNaN(date2)) { + throw new Error(date1 + " - " + date2); + } else if (date1 instanceof Date && date2 instanceof Date) { + return (date1 < date2) ? -1 : (date1 > date2) ? 1 : 0; + } else { + throw new TypeError(date1 + " - " + date2); + } + }; + + /** + * Compares the first Date object to the second Date object and returns true if they are equal. + * @param {Date} First Date object to compare [Required] + * @param {Date} Second Date object to compare to [Required] + * @return {Boolean} true if dates are equal. false if they are not equal. + */ + $D.equals = function (date1, date2) { + return (date1.compareTo(date2) === 0); + }; + + /** + * Gets the day number (0-6) if given a CultureInfo specific string which is a valid dayName, abbreviatedDayName or shortestDayName (two char). + * @param {String} The name of the day (eg. "Monday, "Mon", "tuesday", "tue", "We", "we"). + * @return {Number} The day number + */ + $D.getDayNumberFromName = function (name) { + var n = $C.dayNames, m = $C.abbreviatedDayNames, o = $C.shortestDayNames, s = name.toLowerCase(); + for (var i = 0; i < n.length; i++) { + if (n[i].toLowerCase() == s || m[i].toLowerCase() == s || o[i].toLowerCase() == s) { + return i; + } + } + return -1; + }; + + /** + * Gets the month number (0-11) if given a Culture Info specific string which is a valid monthName or abbreviatedMonthName. + * @param {String} The name of the month (eg. "February, "Feb", "october", "oct"). + * @return {Number} The day number + */ + $D.getMonthNumberFromName = function (name) { + var n = $C.monthNames, m = $C.abbreviatedMonthNames, s = name.toLowerCase(); + for (var i = 0; i < n.length; i++) { + if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) { + return i; + } + } + return -1; + }; + + /** + * Determines if the current date instance is within a LeapYear. + * @param {Number} The year. + * @return {Boolean} true if date is within a LeapYear, otherwise false. + */ + $D.isLeapYear = function (year) { + return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); + }; + + /** + * Gets the number of days in the month, given a year and month value. Automatically corrects for LeapYear. + * @param {Number} The year. + * @param {Number} The month (0-11). + * @return {Number} The number of days in the month. + */ + $D.getDaysInMonth = function (year, month) { + return [31, ($D.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }; + + $D.getTimezoneAbbreviation = function (offset) { + var z = $C.timezones, p; + for (var i = 0; i < z.length; i++) { + if (z[i].offset === offset) { + return z[i].name; + } + } + return null; + }; + + $D.getTimezoneOffset = function (name) { + var z = $C.timezones, p; + for (var i = 0; i < z.length; i++) { + if (z[i].name === name.toUpperCase()) { + return z[i].offset; + } + } + return null; + }; + + /** + * Returns a new Date object that is an exact date and time copy of the original instance. + * @return {Date} A new Date instance + */ + $P.clone = function () { + return new Date(this.getTime()); + }; + + /** + * Compares this instance to a Date object and returns an number indication of their relative values. + * @param {Date} Date object to compare [Required] + * @return {Number} -1 = this is lessthan date. 0 = values are equal. 1 = this is greaterthan date. + */ + $P.compareTo = function (date) { + return Date.compare(this, date); + }; + + /** + * Compares this instance to another Date object and returns true if they are equal. + * @param {Date} Date object to compare. If no date to compare, new Date() [now] is used. + * @return {Boolean} true if dates are equal. false if they are not equal. + */ + $P.equals = function (date) { + return Date.equals(this, date || new Date()); + }; + + /** + * Determines if this instance is between a range of two dates or equal to either the start or end dates. + * @param {Date} Start of range [Required] + * @param {Date} End of range [Required] + * @return {Boolean} true is this is between or equal to the start and end dates, else false + */ + $P.between = function (start, end) { + return this.getTime() >= start.getTime() && this.getTime() <= end.getTime(); + }; + + /** + * Determines if this date occurs after the date to compare to. + * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used. + * @return {Boolean} true if this date instance is greater than the date to compare to (or "now"), otherwise false. + */ + $P.isAfter = function (date) { + return this.compareTo(date || new Date()) === 1; + }; + + /** + * Determines if this date occurs before the date to compare to. + * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used. + * @return {Boolean} true if this date instance is less than the date to compare to (or "now"). + */ + $P.isBefore = function (date) { + return (this.compareTo(date || new Date()) === -1); + }; + + /** + * Determines if the current Date instance occurs today. + * @return {Boolean} true if this date instance is 'today', otherwise false. + */ + + /** + * Determines if the current Date instance occurs on the same Date as the supplied 'date'. + * If no 'date' to compare to is provided, the current Date instance is compared to 'today'. + * @param {date} Date object to compare. If no date to compare, the current Date ("now") is used. + * @return {Boolean} true if this Date instance occurs on the same Day as the supplied 'date'. + */ + $P.isToday = $P.isSameDay = function (date) { + return this.clone().clearTime().equals((date || new Date()).clone().clearTime()); + }; + + /** + * Adds the specified number of milliseconds to this instance. + * @param {Number} The number of milliseconds to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addMilliseconds = function (value) { + this.setMilliseconds(this.getMilliseconds() + value * 1); + return this; + }; + + /** + * Adds the specified number of seconds to this instance. + * @param {Number} The number of seconds to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addSeconds = function (value) { + return this.addMilliseconds(value * 1000); + }; + + /** + * Adds the specified number of seconds to this instance. + * @param {Number} The number of seconds to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addMinutes = function (value) { + return this.addMilliseconds(value * 60000); /* 60*1000 */ + }; + + /** + * Adds the specified number of hours to this instance. + * @param {Number} The number of hours to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addHours = function (value) { + return this.addMilliseconds(value * 3600000); /* 60*60*1000 */ + }; + + /** + * Adds the specified number of days to this instance. + * @param {Number} The number of days to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addDays = function (value) { + this.setDate(this.getDate() + value * 1); + return this; + }; + + /** + * Adds the specified number of weeks to this instance. + * @param {Number} The number of weeks to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addWeeks = function (value) { + return this.addDays(value * 7); + }; + + /** + * Adds the specified number of months to this instance. + * @param {Number} The number of months to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addMonths = function (value) { + var n = this.getDate(); + this.setDate(1); + this.setMonth(this.getMonth() + value * 1); + this.setDate(Math.min(n, $D.getDaysInMonth(this.getFullYear(), this.getMonth()))); + return this; + }; + + /** + * Adds the specified number of years to this instance. + * @param {Number} The number of years to add. The number can be positive or negative [Required] + * @return {Date} this + */ + $P.addYears = function (value) { + return this.addMonths(value * 12); + }; + + /** + * Adds (or subtracts) to the value of the years, months, weeks, days, hours, minutes, seconds, milliseconds of the date instance using given configuration object. Positive and Negative values allowed. + * Example +
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config == "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ var $y, $m, $d;
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * This algorithm is a JavaScript port of the work presented by Claus Tøndering at http://www.tondering.dk/claus/cal/node8.html#SECTION00880000000000000000
+ * .getWeek() Algorithm Copyright (c) 2008 Claus Tondering.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used. Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function () {
+ var a, b, c, d, e, f, g, n, s, w;
+
+ $y = (!$y) ? this.getFullYear() : $y;
+ $m = (!$m) ? this.getMonth() + 1 : $m;
+ $d = (!$d) ? this.getDate() : $d;
+
+ if ($m <= 2) {
+ a = $y - 1;
+ b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
+ c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
+ s = b - c;
+ e = 0;
+ f = $d - 1 + (31 * ($m - 1));
+ } else {
+ a = $y;
+ b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
+ c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
+ s = b - c;
+ e = s + 1;
+ f = $d + ((153 * ($m - 3) + 2) / 5) + 58 + s;
+ }
+
+ g = (a + b) % 7;
+ d = (f + g - e) % 7;
+ n = (f + 3 - d) | 0;
+
+ if (n < 0) {
+ w = 53 - ((g - s) / 5 | 0);
+ } else if (n > 364 + s) {
+ w = 1;
+ } else {
+ w = (n / 7 | 0) + 1;
+ }
+
+ $y = $m = $d = null;
+
+ return w;
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ $y = this.getUTCFullYear();
+ $m = this.getUTCMonth() + 1;
+ $d = this.getUTCDate();
+ return p(this.getWeek());
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ return this.moveToDayOfWeek(1).addWeeks(n - this.getWeek());
+ };
+
+ // private
+ var validate = function (n, min, max, name) {
+ if (typeof n == "undefined") {
+ return false;
+ } else if (typeof n != "number") {
+ throw new TypeError(n + " is not a Number.");
+ } else if (n < min || n > max) {
+ throw new RangeError(n + " is not a valid value for " + name + ".");
+ }
+ return true;
+ };
+
+ /**
+ * Validates the number is within an acceptable range for milliseconds [0-999].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMillisecond = function (value) {
+ return validate(value, 0, 999, "millisecond");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for seconds [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateSecond = function (value) {
+ return validate(value, 0, 59, "second");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for minutes [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMinute = function (value) {
+ return validate(value, 0, 59, "minute");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for hours [0-23].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateHour = function (value) {
+ return validate(value, 0, 23, "hour");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for the days in a month [0-MaxDaysInMonth].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateDay = function (value, year, month) {
+ return validate(value, 1, $D.getDaysInMonth(year, month), "day");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for months [0-11].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMonth = function (value) {
+ return validate(value, 0, 11, "month");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for years.
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateYear = function (value) {
+ return validate(value, 0, 9999, "year");
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ if ($D.validateMillisecond(config.millisecond)) {
+ this.addMilliseconds(config.millisecond - this.getMilliseconds());
+ }
+
+ if ($D.validateSecond(config.second)) {
+ this.addSeconds(config.second - this.getSeconds());
+ }
+
+ if ($D.validateMinute(config.minute)) {
+ this.addMinutes(config.minute - this.getMinutes());
+ }
+
+ if ($D.validateHour(config.hour)) {
+ this.addHours(config.hour - this.getHours());
+ }
+
+ if ($D.validateMonth(config.month)) {
+ this.addMonths(config.month - this.getMonth());
+ }
+
+ if ($D.validateYear(config.year)) {
+ this.addYears(config.year - this.getFullYear());
+ }
+
+ /* day has to go last because you can't validate the day without first knowing the month */
+ if ($D.validateDay(config.day, this.getFullYear(), this.getMonth())) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ if (config.timezone) {
+ this.setTimezone(config.timezone);
+ }
+
+ if (config.timezoneOffset) {
+ this.setTimezoneOffset(config.timezoneOffset);
+ }
+
+ if (config.week && validate(config.week, 0, 53, "week")) {
+ this.setWeek(config.week);
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = function (dayOfWeek, orient) {
+ var diff = (dayOfWeek - this.getDay() + 7 * (orient || +1)) % 7;
+ return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff);
+ };
+
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = function (month, orient) {
+ var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12;
+ return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff);
+ };
+
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return this.addMinutes(there - here);
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() != this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function () {
+ var n = this.getTimezoneOffset() * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ if (!$P.toISOString) {
+ /**
+ * Converts the current date instance into a string with an ISO 8601 format. The date is converted to it's UTC value.
+ * @return {String} ISO 8601 string of date
+ */
+ $P.toISOString = function () {
+ // From http://www.json.org/json.js. Public Domain.
+ function f(n) {
+ return n < 10 ? '0' + n : n;
+ }
+
+ return '"' + this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z"';
+ };
+ }
+
+ // private
+ $P._toString = $P.toString;
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ + CUSTOM DATE AND TIME FORMAT STRINGS + Format Description Example + ------ --------------------------------------------------------------------------- ----------------------- + s The seconds of the minute between 0-59. "0" to "59" + ss The seconds of the minute with leading zero if required. "00" to "59" + + m The minute of the hour between 0-59. "0" or "59" + mm The minute of the hour with leading zero if required. "00" or "59" + + h The hour of the day between 1-12. "1" to "12" + hh The hour of the day with leading zero if required. "01" to "12" + + H The hour of the day between 0-23. "0" to "23" + HH The hour of the day with leading zero if required. "00" to "23" + + d The day of the month between 1 and 31. "1" to "31" + dd The day of the month with leading zero if required. "01" to "31" + ddd Abbreviated day name. $C.abbreviatedDayNames. "Mon" to "Sun" + dddd The full day name. $C.dayNames. "Monday" to "Sunday" + + M The month of the year between 1-12. "1" to "12" + MM The month of the year with leading zero if required. "01" to "12" + MMM Abbreviated month name. $C.abbreviatedMonthNames. "Jan" to "Dec" + MMMM The full month name. $C.monthNames. "January" to "December" + + yy The year as a two-digit number. "99" or "08" + yyyy The full four digit year. "1999" or "2008" + + t Displays the first character of the A.M./P.M. designator. "A" or "P" + $C.amDesignator or $C.pmDesignator + tt Displays the A.M./P.M. designator. "AM" or "PM" + $C.amDesignator or $C.pmDesignator + + S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th" + +|| *Format* || *Description* || *Example* || +|| d || The CultureInfo shortDate Format Pattern || "M/d/yyyy" || +|| D || The CultureInfo longDate Format Pattern || "dddd, MMMM dd, yyyy" || +|| F || The CultureInfo fullDateTime Format Pattern || "dddd, MMMM dd, yyyy h:mm:ss tt" || +|| m || The CultureInfo monthDay Format Pattern || "MMMM dd" || +|| r || The CultureInfo rfc1123 Format Pattern || "ddd, dd MMM yyyy HH:mm:ss GMT" || +|| s || The CultureInfo sortableDateTime Format Pattern || "yyyy-MM-ddTHH:mm:ss" || +|| t || The CultureInfo shortTime Format Pattern || "h:mm tt" || +|| T || The CultureInfo longTime Format Pattern || "h:mm:ss tt" || +|| u || The CultureInfo universalSortableDateTime Format Pattern || "yyyy-MM-dd HH:mm:ssZ" || +|| y || The CultureInfo yearMonth Format Pattern || "MMMM, yyyy" || + + + STANDARD DATE AND TIME FORMAT STRINGS + Format Description Example ("en-US") + ------ --------------------------------------------------------------------------- ----------------------- + d The CultureInfo shortDate Format Pattern "M/d/yyyy" + D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy" + F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt" + m The CultureInfo monthDay Format Pattern "MMMM dd" + r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT" + s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss" + t The CultureInfo shortTime Format Pattern "h:mm tt" + T The CultureInfo longTime Format Pattern "h:mm:ss tt" + u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ" + y The CultureInfo yearMonth Format Pattern "MMMM, yyyy" ++ * @param {String} A format string consisting of one or more format spcifiers [Optional]. + * @return {String} A string representation of the current Date object. + */ + $P.toString = function (format) { + var x = this; + + // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and + // may vary by culture. + if (format && format.length == 1) { + var c = $C.formatPatterns; + x.t = x.toString; + switch (format) { + case "d": + return x.t(c.shortDate); + case "D": + return x.t(c.longDate); + case "F": + return x.t(c.fullDateTime); + case "m": + return x.t(c.monthDay); + case "r": + return x.t(c.rfc1123); + case "s": + return x.t(c.sortableDateTime); + case "t": + return x.t(c.shortTime); + case "T": + return x.t(c.longTime); + case "u": + return x.t(c.universalSortableDateTime); + case "y": + return x.t(c.yearMonth); + } + } + + var ord = function (n) { + switch (n * 1) { + case 1: + case 21: + case 31: + return "st"; + case 2: + case 22: + return "nd"; + case 3: + case 23: + return "rd"; + default: + return "th"; + } + }; + + return format ? format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g, + function (m) { + if (m.charAt(0) === "\\") { + return m.replace("\\", ""); + } + x.h = x.getHours; + switch (m) { + case "hh": + return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12)); + case "h": + return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12); + case "HH": + return p(x.h()); + case "H": + return x.h(); + case "mm": + return p(x.getMinutes()); + case "m": + return x.getMinutes(); + case "ss": + return p(x.getSeconds()); + case "s": + return x.getSeconds(); + case "yyyy": + return p(x.getFullYear(), 4); + case "yy": + return p(x.getFullYear()); + case "dddd": + return $C.dayNames[x.getDay()]; + case "ddd": + return $C.abbreviatedDayNames[x.getDay()]; + case "dd": + return p(x.getDate()); + case "d": + return x.getDate(); + case "MMMM": + return $C.monthNames[x.getMonth()]; + case "MMM": + return $C.abbreviatedMonthNames[x.getMonth()]; + case "MM": + return p((x.getMonth() + 1)); + case "M": + return x.getMonth() + 1; + case "t": + return x.h() < 12 ? $C.amDesignator.substring(0, 1) : $C.pmDesignator.substring(0, 1); + case "tt": + return x.h() < 12 ? $C.amDesignator : $C.pmDesignator; + case "S": + return ord(x.getDate()); + default: + return m; + } + } + ) : this._toString(); + }; +}()); /** + * @version: 1.0 Alpha-1 + * @author: Coolite Inc. http://www.coolite.com/ + * @date: 2008-04-13 + * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved. + * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. + * @website: http://www.datejs.com/ + */ + +(function () { + Date.Parsing = { + Exception: function (s) { + this.message = "Parse error at '" + s.substring(0, 10) + " ...'"; + } + }; + + var $P = Date.Parsing; + var _ = $P.Operators = { + // + // Tokenizers + // + rtoken: function (r) { // regex token + return function (s) { + var mx = s.match(r); + if (mx) { + return ([ mx[0], s.substring(mx[0].length) ]); + } else { + throw new $P.Exception(s); + } + }; + }, + token: function (s) { // whitespace-eating token + return function (s) { + return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s); + // Removed .strip() + // return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s).strip(); + }; + }, + stoken: function (s) { // string token + return _.rtoken(new RegExp("^" + s)); + }, + + // + // Atomic Operators + // + + until: function (p) { + return function (s) { + var qx = [], rx = null; + while (s.length) { + try { + rx = p.call(this, s); + } catch (e) { + qx.push(rx[0]); + s = rx[1]; + continue; + } + break; + } + return [ qx, s ]; + }; + }, + many: function (p) { + return function (s) { + var rx = [], r = null; + while (s.length) { + try { + r = p.call(this, s); + } catch (e) { + return [ rx, s ]; + } + rx.push(r[0]); + s = r[1]; + } + return [ rx, s ]; + }; + }, + + // generator operators -- see below + optional: function (p) { + return function (s) { + var r = null; + try { + r = p.call(this, s); + } catch (e) { + return [ null, s ]; + } + return [ r[0], r[1] ]; + }; + }, + not: function (p) { + return function (s) { + try { + p.call(this, s); + } catch (e) { + return [null, s]; + } + throw new $P.Exception(s); + }; + }, + ignore: function (p) { + return p ? + function (s) { + var r = null; + r = p.call(this, s); + return [null, r[1]]; + } : null; + }, + product: function () { + var px = arguments[0], + qx = Array.prototype.slice.call(arguments, 1), rx = []; + for (var i = 0 ; i < px.length ; i++) { + rx.push(_.each(px[i], qx)); + } + return rx; + }, + cache: function (rule) { + var cache = {}, r = null; + return function (s) { + try { + r = cache[s] = (cache[s] || rule.call(this, s)); + } catch (e) { + r = cache[s] = e; + } + if (r instanceof $P.Exception) { + throw r; + } else { + return r; + } + }; + }, + + // vector operators -- see below + any: function () { + var px = arguments; + return function (s) { + var r = null; + for (var i = 0; i < px.length; i++) { + if (px[i] == null) { + continue; + } + try { + r = (px[i].call(this, s)); + } catch (e) { + r = null; + } + if (r) { + return r; + } + } + throw new $P.Exception(s); + }; + }, + each: function () { + var px = arguments; + return function (s) { + var rx = [], r = null; + for (var i = 0; i < px.length ; i++) { + if (px[i] == null) { + continue; + } + try { + r = (px[i].call(this, s)); + } catch (e) { + throw new $P.Exception(s); + } + rx.push(r[0]); + s = r[1]; + } + return [ rx, s]; + }; + }, + all: function () { + var px = arguments, _ = _; + return _.each(_.optional(px)); + }, + + // delimited operators + sequence: function (px, d, c) { + d = d || _.rtoken(/^\s*/); + c = c || null; + + if (px.length == 1) { + return px[0]; + } + return function (s) { + var r = null, q = null; + var rx = []; + for (var i = 0; i < px.length ; i++) { + try { + r = px[i].call(this, s); + } catch (e) { + break; + } + rx.push(r[0]); + try { + q = d.call(this, r[1]); + } catch (ex) { + q = null; + break; + } + s = q[1]; + } + if (!r) { + throw new $P.Exception(s); + } + if (q) { + throw new $P.Exception(q[1]); + } + if (c) { + try { + r = c.call(this, r[1]); + } catch (ey) { + throw new $P.Exception(r[1]); + } + } + return [ rx, (r?r[1]:s) ]; + }; + }, + + // + // Composite Operators + // + + between: function (d1, p, d2) { + d2 = d2 || d1; + var _fn = _.each(_.ignore(d1), p, _.ignore(d2)); + return function (s) { + var rx = _fn.call(this, s); + return [[rx[0][0], r[0][2]], rx[1]]; + }; + }, + list: function (p, d, c) { + d = d || _.rtoken(/^\s*/); + c = c || null; + return (p instanceof Array ? + _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) : + _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c))); + }, + set: function (px, d, c) { + d = d || _.rtoken(/^\s*/); + c = c || null; + return function (s) { + // r is the current match, best the current 'best' match + // which means it parsed the most amount of input + var r = null, p = null, q = null, rx = null, best = [[], s], last = false; + + // go through the rules in the given set + for (var i = 0; i < px.length ; i++) { + + // last is a flag indicating whether this must be the last element + // if there is only 1 element, then it MUST be the last one + q = null; + p = null; + r = null; + last = (px.length == 1); + + // first, we try simply to match the current pattern + // if not, try the next pattern + try { + r = px[i].call(this, s); + } catch (e) { + continue; + } + + // since we are matching against a set of elements, the first + // thing to do is to add r[0] to matched elements + rx = [[r[0]], r[1]]; + + // if we matched and there is still input to parse and + // we don't already know this is the last element, + // we're going to next check for the delimiter ... + // if there's none, or if there's no input left to parse + // than this must be the last element after all ... + if (r[1].length > 0 && ! last) { + try { + q = d.call(this, r[1]); + } catch (ex) { + last = true; + } + } else { + last = true; + } + + // if we parsed the delimiter and now there's no more input, + // that means we shouldn't have parsed the delimiter at all + // so don't update r and mark this as the last element ... + if (!last && q[1].length === 0) { + last = true; + } + + + // so, if this isn't the last element, we're going to see if + // we can get any more matches from the remaining (unmatched) + // elements ... + if (!last) { + + // build a list of the remaining rules we can match against, + // i.e., all but the one we just matched against + var qx = []; + for (var j = 0; j < px.length ; j++) { + if (i != j) { + qx.push(px[j]); + } + } + + // now invoke recursively set with the remaining input + // note that we don't include the closing delimiter ... + // we'll check for that ourselves at the end + p = _.set(qx, d).call(this, q[1]); + + // if we got a non-empty set as a result ... + // (otw rx already contains everything we want to match) + if (p[0].length > 0) { + // update current result, which is stored in rx ... + // basically, pick up the remaining text from p[1] + // and concat the result from p[0] so that we don't + // get endless nesting ... + rx[0] = rx[0].concat(p[0]); + rx[1] = p[1]; + } + } + + // at this point, rx either contains the last matched element + // or the entire matched set that starts with this element. + + // now we just check to see if this variation is better than + // our best so far, in terms of how much of the input is parsed + if (rx[1].length < best[1].length) { + best = rx; + } + + // if we've parsed all the input, then we're finished + if (best[1].length === 0) { + break; + } + } + + // so now we've either gone through all the patterns trying them + // as the initial match; or we found one that parsed the entire + // input string ... + + // if best has no matches, just return empty set ... + if (best[0].length === 0) { + return best; + } + + // if a closing delimiter is provided, then we have to check it also + if (c) { + // we try this even if there is no remaining input because the pattern + // may well be optional or match empty input ... + try { + q = c.call(this, best[1]); + } catch (ey) { + throw new $P.Exception(best[1]); + } + + // it parsed ... be sure to update the best match remaining input + best[1] = q[1]; + } + + // if we're here, either there was no closing delimiter or we parsed it + // so now we have the best match; just return it! + return best; + }; + }, + forward: function (gr, fname) { + return function (s) { + return gr[fname].call(this, s); + }; + }, + + // + // Translation Operators + // + replace: function (rule, repl) { + return function (s) { + var r = rule.call(this, s); + return [repl, r[1]]; + }; + }, + process: function (rule, fn) { + return function (s) { + var r = rule.call(this, s); + return [fn.call(this, r[0]), r[1]]; + }; + }, + min: function (min, rule) { + return function (s) { + var rx = rule.call(this, s); + if (rx[0].length < min) { + throw new $P.Exception(s); + } + return rx; + }; + } + }; + + + // Generator Operators And Vector Operators + + // Generators are operators that have a signature of F(R) => R, + // taking a given rule and returning another rule, such as + // ignore, which parses a given rule and throws away the result. + + // Vector operators are those that have a signature of F(R1,R2,...) => R, + // take a list of rules and returning a new rule, such as each. + + // Generator operators are converted (via the following _generator + // function) into functions that can also take a list or array of rules + // and return an array of new rules as though the function had been + // called on each rule in turn (which is what actually happens). + + // This allows generators to be used with vector operators more easily. + // Example: + // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar)) + + // This also turns generators into vector operators, which allows + // constructs like: + // not(cache(foo, bar)) + + var _generator = function (op) { + return function () { + var args = null, rx = []; + if (arguments.length > 1) { + args = Array.prototype.slice.call(arguments); + } else if (arguments[0] instanceof Array) { + args = arguments[0]; + } + if (args) { + for (var i = 0, px = args.shift() ; i < px.length ; i++) { + args.unshift(px[i]); + rx.push(op.apply(null, args)); + args.shift(); + return rx; + } + } else { + return op.apply(null, arguments); + } + }; + }; + + var gx = "optional not ignore cache".split(/\s/); + + for (var i = 0 ; i < gx.length ; i++) { + _[gx[i]] = _generator(_[gx[i]]); + } + + var _vector = function (op) { + return function () { + if (arguments[0] instanceof Array) { + return op.apply(null, arguments[0]); + } else { + return op.apply(null, arguments); + } + }; + }; + + var vx = "each any all".split(/\s/); + + for (var j = 0 ; j < vx.length ; j++) { + _[vx[j]] = _vector(_[vx[j]]); + } + +}()); + +(function () { + var $D = Date, $P = $D.prototype, $C = $D.CultureInfo; + + var flattenAndCompact = function (ax) { + var rx = []; + for (var i = 0; i < ax.length; i++) { + if (ax[i] instanceof Array) { + rx = rx.concat(flattenAndCompact(ax[i])); + } else { + if (ax[i]) { + rx.push(ax[i]); + } + } + } + return rx; + }; + + $D.Grammar = {}; + + $D.Translator = { + hour: function (s) { + return function () { + this.hour = Number(s); + }; + }, + minute: function (s) { + return function () { + this.minute = Number(s); + }; + }, + second: function (s) { + return function () { + this.second = Number(s); + }; + }, + meridian: function (s) { + return function () { + this.meridian = s.slice(0, 1).toLowerCase(); + }; + }, + timezone: function (s) { + return function () { + var n = s.replace(/[^\d\+\-]/g, ""); + if (n.length) { + this.timezoneOffset = Number(n); + } else { + this.timezone = s.toLowerCase(); + } + }; + }, + day: function (x) { + var s = x[0]; + return function () { + this.day = Number(s.match(/\d+/)[0]); + }; + }, + month: function (s) { + return function () { + this.month = (s.length == 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1; + }; + }, + year: function (s) { + return function () { + var n = Number(s); + this.year = ((s.length > 2) ? n : + (n + (((n + 2000) < $C.twoDigitYearMax) ? 2000 : 1900))); + }; + }, + rday: function (s) { + return function () { + switch (s) { + case "yesterday": + this.days = -1; + break; + case "tomorrow": + this.days = 1; + break; + case "today": + this.days = 0; + break; + case "now": + this.days = 0; + this.now = true; + break; + } + }; + }, + finishExact: function (x) { + x = (x instanceof Array) ? x : [ x ]; + + for (var i = 0 ; i < x.length ; i++) { + if (x[i]) { + x[i].call(this); + } + } + + var now = new Date(); + + if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) { + this.day = now.getDate(); + } + + if (!this.year) { + this.year = now.getFullYear(); + } + + if (!this.month && this.month !== 0) { + this.month = now.getMonth(); + } + + if (!this.day) { + this.day = 1; + } + + if (!this.hour) { + this.hour = 0; + } + + if (!this.minute) { + this.minute = 0; + } + + if (!this.second) { + this.second = 0; + } + + if (this.meridian && this.hour) { + if (this.meridian == "p" && this.hour < 12) { + this.hour = this.hour + 12; + } else if (this.meridian == "a" && this.hour == 12) { + this.hour = 0; + } + } + + if (this.day > $D.getDaysInMonth(this.year, this.month)) { + throw new RangeError(this.day + " is not a valid value for days."); + } + + var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second); + + if (this.timezone) { + r.set({ timezone: this.timezone }); + } else if (this.timezoneOffset) { + r.set({ timezoneOffset: this.timezoneOffset }); + } + + return r; + }, + finish: function (x) { + x = (x instanceof Array) ? flattenAndCompact(x) : [ x ]; + + if (x.length === 0) { + return null; + } + + for (var i = 0 ; i < x.length ; i++) { + if (typeof x[i] == "function") { + x[i].call(this); + } + } + + var today = $D.today(); + + if (this.now && !this.unit && !this.operator) { + return new Date(); + } else if (this.now) { + today = new Date(); + } + + var expression = !!(this.days && this.days !== null || this.orient || this.operator); + + var gap, mod, orient; + orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1); + + if(!this.now && "hour minute second".indexOf(this.unit) != -1) { + today.setTimeToNow(); + } + + if (this.month || this.month === 0) { + if ("year day hour minute second".indexOf(this.unit) != -1) { + this.value = this.month + 1; + this.month = null; + expression = true; + } + } + + if (!expression && this.weekday && !this.day && !this.days) { + var temp = Date[this.weekday](); + this.day = temp.getDate(); + if (!this.month) { + this.month = temp.getMonth(); + } + this.year = temp.getFullYear(); + } + + if (expression && this.weekday && this.unit != "month") { + this.unit = "day"; + gap = ($D.getDayNumberFromName(this.weekday) - today.getDay()); + mod = 7; + this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); + } + + if (this.month && this.unit == "day" && this.operator) { + this.value = (this.month + 1); + this.month = null; + } -/** - * @namespace - */ -sc.helpers = {}; + if (this.value != null && this.month != null && this.year != null) { + this.day = this.value * 1; + } -/** - * dump level for limiting what gets dumped to console - */ -sc.dumplevel = 1; + if (this.month && !this.day && this.value) { + today.set({ day: this.value * 1 }); + if (!expression) { + this.day = this.value * 1; + } + } -/** - * method to set dump level - */ -sc.setDumpLevel = function(level) { - sc.dumplevel = parseInt(level, 10); -}; + if (!this.month && this.value && this.unit == "month" && !this.now) { + this.month = this.value; + expression = true; + } -/** - * @namespace helper shortcuts - * this lets us write "sch.method" instead of "sc.helpers.method" - * - */ -var sch = sc.helpers; + if (expression && (this.month || this.month === 0) && this.unit != "year") { + this.unit = "month"; + gap = (this.month - today.getMonth()); + mod = 12; + this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); + this.month = null; + } + if (!this.unit) { + this.unit = "day"; + } -sc.events = {}; + if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) { + this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator == "add") ? 1 : -1) + (this.value||0) * orient; + } else if (this[this.unit + "s"] == null || this.operator != null) { + if (!this.value) { + this.value = 1; + } + this[this.unit + "s"] = this.value * orient; + } + if (this.meridian && this.hour) { + if (this.meridian == "p" && this.hour < 12) { + this.hour = this.hour + 12; + } else if (this.meridian == "a" && this.hour == 12) { + this.hour = 0; + } + } + if (this.weekday && !this.day && !this.days) { + var temp = Date[this.weekday](); + this.day = temp.getDate(); + if (temp.getMonth() !== today.getMonth()) { + this.month = temp.getMonth(); + } + } -/** - * various constant definitions that aren't specific to a single library - */ + if ((this.month || this.month === 0) && !this.day) { + this.day = 1; + } -/** - * @constant - */ -var SPAZCORE_SERVICE_TWITTER = 'twitter'; -/** - * @constant - */ -var SPAZCORE_SERVICE_IDENTICA = 'identi.ca'; -/** - * @constant - */ -var SPAZCORE_SERVICE_FREELISHUS = 'freelish.us'; -/** - * @constant - */ -var SPAZCORE_SERVICE_WORDPRESS_TWITTER = 'wordpress-twitter'; -/** - * @constant - */ -var SPAZCORE_SERVICE_TUMBLR_TWITTER = 'tumblr-twitter'; -/** - * @constant - */ -var SPAZCORE_SERVICE_CUSTOM = 'custom'; + if (!this.orient && !this.operator && this.unit == "week" && this.value && !this.day && !this.month) { + return Date.today().setWeek(this.value); + } -/** - * @constant - */ -var SPAZCORE_BASEURL_TWITTER = 'https://twitter.com/'; -/** - * @constant - */ -var SPAZCORE_BASEURL_IDENTICA = 'https://identi.ca/'; -/** - * @constant - */ -var SPAZCORE_BASEURL_FREELISHUS = 'http://freelish.us/'; + if (expression && this.timezone && this.day && this.days) { + this.day = this.days; + } + return (expression) ? today.add(this) : today.set(this); + } + }; + var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn; + + g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/); + g.timePartDelimiter = _.stoken(":"); + g.whiteSpace = _.rtoken(/^\s*/); + g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/); + + var _C = {}; + g.ctoken = function (keys) { + var fn = _C[keys]; + if (! fn) { + var c = $C.regexPatterns; + var kx = keys.split(/\s+/), px = []; + for (var i = 0; i < kx.length ; i++) { + px.push(_.replace(_.rtoken(c[kx[i]]), kx[i])); + } + fn = _C[keys] = _.any.apply(null, px); + } + return fn; + }; + g.ctoken2 = function (key) { + return _.rtoken($C.regexPatterns[key]); + }; -/** - * Build the helpers - * @depends ../helpers/datetime.js - * @depends ../helpers/event.js - * @depends ../helpers/javascript.js - * @depends ../helpers/json.js - * @depends ../helpers/location.js - * @depends ../helpers/string.js - * @depends ../helpers/sys.js - * @depends ../helpers/view.js - * @depends ../helpers/xml.js - * - * Build the libs - * @depends spazcron.js - * @depends spazlocker.js - * @depends spazphotomailer.js - * @depends spazpingfm.js - * @depends spazprefs.js - * @depends spazshorttext.js - * @depends spazshorturl.js - * @depends spaztemplate.js - * @depends spaztimeline.js - * @depends spaztwit.js - */ -Date.CultureInfo = { - /* Culture Name */ - name: "en-US", - englishName: "English (United States)", - nativeName: "English (United States)", - - /* Day Name Strings */ - dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], - abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], - shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], - firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"], - - /* Month Name Strings */ - monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], - - /* AM/PM Designators */ - amDesignator: "AM", - pmDesignator: "PM", - - firstDayOfWeek: 0, - twoDigitYearMax: 2029, - - /** - * The dateElementOrder is based on the order of the - * format specifiers in the formatPatterns.DatePattern. - * - * Example: -
- shortDatePattern dateElementOrder - ------------------ ---------------- - "M/d/yyyy" "mdy" - "dd/MM/yyyy" "dmy" - "yyyy-MM-dd" "ymd" -- * - * The correct dateElementOrder is required by the parser to - * determine the expected order of the date elements in the - * string being parsed. - */ - dateElementOrder: "mdy", - - /* Standard date and time format patterns */ - formatPatterns: { - shortDate: "M/d/yyyy", - longDate: "dddd, MMMM dd, yyyy", - shortTime: "h:mm tt", - longTime: "h:mm:ss tt", - fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt", - sortableDateTime: "yyyy-MM-ddTHH:mm:ss", - universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", - rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", - monthDay: "MMMM dd", - yearMonth: "MMMM, yyyy" - }, - - /** - * NOTE: If a string format is not parsing correctly, but - * you would expect it parse, the problem likely lies below. - * - * The following regex patterns control most of the string matching - * within the parser. - * - * The Month name and Day name patterns were automatically generated - * and in general should be (mostly) correct. - * - * Beyond the month and day name patterns are natural language strings. - * Example: "next", "today", "months" - * - * These natural language string may NOT be correct for this culture. - * If they are not correct, please translate and edit this file - * providing the correct regular expression pattern. - * - * If you modify this file, please post your revised CultureInfo file - * to the Datejs Forum located at http://www.datejs.com/forums/. - * - * Please mark the subject of the post with [CultureInfo]. Example: - * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark) - * - * We will add the modified patterns to the master source files. - * - * As well, please review the list of "Future Strings" section below. - */ - regexPatterns: { - jan: /^jan(uary)?/i, - feb: /^feb(ruary)?/i, - mar: /^mar(ch)?/i, - apr: /^apr(il)?/i, - may: /^may/i, - jun: /^jun(e)?/i, - jul: /^jul(y)?/i, - aug: /^aug(ust)?/i, - sep: /^sep(t(ember)?)?/i, - oct: /^oct(ober)?/i, - nov: /^nov(ember)?/i, - dec: /^dec(ember)?/i, - - sun: /^su(n(day)?)?/i, - mon: /^mo(n(day)?)?/i, - tue: /^tu(e(s(day)?)?)?/i, - wed: /^we(d(nesday)?)?/i, - thu: /^th(u(r(s(day)?)?)?)?/i, - fri: /^fr(i(day)?)?/i, - sat: /^sa(t(urday)?)?/i, - - future: /^next/i, - past: /^last|past|prev(ious)?/i, - add: /^(\+|aft(er)?|from|hence)/i, - subtract: /^(\-|bef(ore)?|ago)/i, - - yesterday: /^yes(terday)?/i, - today: /^t(od(ay)?)?/i, - tomorrow: /^tom(orrow)?/i, - now: /^n(ow)?/i, - - millisecond: /^ms|milli(second)?s?/i, - second: /^sec(ond)?s?/i, - minute: /^mn|min(ute)?s?/i, - hour: /^h(our)?s?/i, - week: /^w(eek)?s?/i, - month: /^m(onth)?s?/i, - day: /^d(ay)?s?/i, - year: /^y(ear)?s?/i, - - shortMeridian: /^(a|p)/i, - longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i, - timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i, - ordinalSuffix: /^\s*(st|nd|rd|th)/i, - timeContext: /^\s*(\:|a(?!u|p)|p)/i - }, - - timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}] -}; - -/******************** - ** Future Strings ** - ******************** - * - * The following list of strings may not be currently being used, but - * may be incorporated into the Datejs library later. - * - * We would appreciate any help translating the strings below. - * - * If you modify this file, please post your revised CultureInfo file - * to the Datejs Forum located at http://www.datejs.com/forums/. - * - * Please mark the subject of the post with [CultureInfo]. Example: - * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b - * - * English Name Translated - * ------------------ ----------------- - * about about - * ago ago - * date date - * time time - * calendar calendar - * show show - * hourly hourly - * daily daily - * weekly weekly - * bi-weekly bi-weekly - * fortnight fortnight - * monthly monthly - * bi-monthly bi-monthly - * quarter quarter - * quarterly quarterly - * yearly yearly - * annual annual - * annually annually - * annum annum - * again again - * between between - * after after - * from now from now - * repeat repeat - * times times - * per per - * min (abbrev minute) min - * morning morning - * noon noon - * night night - * midnight midnight - * mid-night mid-night - * evening evening - * final final - * future future - * spring spring - * summer summer - * fall fall - * winter winter - * end of end of - * end end - * long long - * short short - *//** - * @version: 1.0 Alpha-1 - * @author: Coolite Inc. http://www.coolite.com/ - * @date: 2008-04-13 - * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved. - * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. - * @website: http://www.datejs.com/ - */ - -(function () { - var $D = Date, - $P = $D.prototype, - $C = $D.CultureInfo, - p = function (s, l) { - if (!l) { - l = 2; - } - return ("000" + s).slice(l * -1); - }; - - /** - * Resets the time of this Date object to 12:00 AM (00:00), which is the start of the day. - * @param {Boolean} .clone() this date instance before clearing Time - * @return {Date} this - */ - $P.clearTime = function () { - this.setHours(0); - this.setMinutes(0); - this.setSeconds(0); - this.setMilliseconds(0); - return this; - }; - - /** - * Resets the time of this Date object to the current time ('now'). - * @return {Date} this - */ - $P.setTimeToNow = function () { - var n = new Date(); - this.setHours(n.getHours()); - this.setMinutes(n.getMinutes()); - this.setSeconds(n.getSeconds()); - this.setMilliseconds(n.getMilliseconds()); - return this; - }; - - /** - * Gets a date that is set to the current date. The time is set to the start of the day (00:00 or 12:00 AM). - * @return {Date} The current date. - */ - $D.today = function () { - return new Date().clearTime(); - }; - - /** - * Compares the first date to the second date and returns an number indication of their relative values. - * @param {Date} First Date object to compare [Required]. - * @param {Date} Second Date object to compare to [Required]. - * @return {Number} -1 = date1 is lessthan date2. 0 = values are equal. 1 = date1 is greaterthan date2. - */ - $D.compare = function (date1, date2) { - if (isNaN(date1) || isNaN(date2)) { - throw new Error(date1 + " - " + date2); - } else if (date1 instanceof Date && date2 instanceof Date) { - return (date1 < date2) ? -1 : (date1 > date2) ? 1 : 0; - } else { - throw new TypeError(date1 + " - " + date2); - } - }; - - /** - * Compares the first Date object to the second Date object and returns true if they are equal. - * @param {Date} First Date object to compare [Required] - * @param {Date} Second Date object to compare to [Required] - * @return {Boolean} true if dates are equal. false if they are not equal. - */ - $D.equals = function (date1, date2) { - return (date1.compareTo(date2) === 0); - }; - - /** - * Gets the day number (0-6) if given a CultureInfo specific string which is a valid dayName, abbreviatedDayName or shortestDayName (two char). - * @param {String} The name of the day (eg. "Monday, "Mon", "tuesday", "tue", "We", "we"). - * @return {Number} The day number - */ - $D.getDayNumberFromName = function (name) { - var n = $C.dayNames, m = $C.abbreviatedDayNames, o = $C.shortestDayNames, s = name.toLowerCase(); - for (var i = 0; i < n.length; i++) { - if (n[i].toLowerCase() == s || m[i].toLowerCase() == s || o[i].toLowerCase() == s) { - return i; - } - } - return -1; - }; - - /** - * Gets the month number (0-11) if given a Culture Info specific string which is a valid monthName or abbreviatedMonthName. - * @param {String} The name of the month (eg. "February, "Feb", "october", "oct"). - * @return {Number} The day number - */ - $D.getMonthNumberFromName = function (name) { - var n = $C.monthNames, m = $C.abbreviatedMonthNames, s = name.toLowerCase(); - for (var i = 0; i < n.length; i++) { - if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) { - return i; - } - } - return -1; - }; - - /** - * Determines if the current date instance is within a LeapYear. - * @param {Number} The year. - * @return {Boolean} true if date is within a LeapYear, otherwise false. - */ - $D.isLeapYear = function (year) { - return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); - }; - - /** - * Gets the number of days in the month, given a year and month value. Automatically corrects for LeapYear. - * @param {Number} The year. - * @param {Number} The month (0-11). - * @return {Number} The number of days in the month. - */ - $D.getDaysInMonth = function (year, month) { - return [31, ($D.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; - }; - - $D.getTimezoneAbbreviation = function (offset) { - var z = $C.timezones, p; - for (var i = 0; i < z.length; i++) { - if (z[i].offset === offset) { - return z[i].name; - } - } - return null; - }; - - $D.getTimezoneOffset = function (name) { - var z = $C.timezones, p; - for (var i = 0; i < z.length; i++) { - if (z[i].name === name.toUpperCase()) { - return z[i].offset; - } - } - return null; - }; - - /** - * Returns a new Date object that is an exact date and time copy of the original instance. - * @return {Date} A new Date instance - */ - $P.clone = function () { - return new Date(this.getTime()); - }; - - /** - * Compares this instance to a Date object and returns an number indication of their relative values. - * @param {Date} Date object to compare [Required] - * @return {Number} -1 = this is lessthan date. 0 = values are equal. 1 = this is greaterthan date. - */ - $P.compareTo = function (date) { - return Date.compare(this, date); - }; - - /** - * Compares this instance to another Date object and returns true if they are equal. - * @param {Date} Date object to compare. If no date to compare, new Date() [now] is used. - * @return {Boolean} true if dates are equal. false if they are not equal. - */ - $P.equals = function (date) { - return Date.equals(this, date || new Date()); - }; - - /** - * Determines if this instance is between a range of two dates or equal to either the start or end dates. - * @param {Date} Start of range [Required] - * @param {Date} End of range [Required] - * @return {Boolean} true is this is between or equal to the start and end dates, else false - */ - $P.between = function (start, end) { - return this.getTime() >= start.getTime() && this.getTime() <= end.getTime(); - }; - - /** - * Determines if this date occurs after the date to compare to. - * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used. - * @return {Boolean} true if this date instance is greater than the date to compare to (or "now"), otherwise false. - */ - $P.isAfter = function (date) { - return this.compareTo(date || new Date()) === 1; - }; - - /** - * Determines if this date occurs before the date to compare to. - * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used. - * @return {Boolean} true if this date instance is less than the date to compare to (or "now"). - */ - $P.isBefore = function (date) { - return (this.compareTo(date || new Date()) === -1); - }; - - /** - * Determines if the current Date instance occurs today. - * @return {Boolean} true if this date instance is 'today', otherwise false. - */ - - /** - * Determines if the current Date instance occurs on the same Date as the supplied 'date'. - * If no 'date' to compare to is provided, the current Date instance is compared to 'today'. - * @param {date} Date object to compare. If no date to compare, the current Date ("now") is used. - * @return {Boolean} true if this Date instance occurs on the same Day as the supplied 'date'. - */ - $P.isToday = $P.isSameDay = function (date) { - return this.clone().clearTime().equals((date || new Date()).clone().clearTime()); - }; - - /** - * Adds the specified number of milliseconds to this instance. - * @param {Number} The number of milliseconds to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addMilliseconds = function (value) { - this.setMilliseconds(this.getMilliseconds() + value * 1); - return this; - }; - - /** - * Adds the specified number of seconds to this instance. - * @param {Number} The number of seconds to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addSeconds = function (value) { - return this.addMilliseconds(value * 1000); - }; - - /** - * Adds the specified number of seconds to this instance. - * @param {Number} The number of seconds to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addMinutes = function (value) { - return this.addMilliseconds(value * 60000); /* 60*1000 */ - }; - - /** - * Adds the specified number of hours to this instance. - * @param {Number} The number of hours to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addHours = function (value) { - return this.addMilliseconds(value * 3600000); /* 60*60*1000 */ - }; - - /** - * Adds the specified number of days to this instance. - * @param {Number} The number of days to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addDays = function (value) { - this.setDate(this.getDate() + value * 1); - return this; - }; - - /** - * Adds the specified number of weeks to this instance. - * @param {Number} The number of weeks to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addWeeks = function (value) { - return this.addDays(value * 7); - }; - - /** - * Adds the specified number of months to this instance. - * @param {Number} The number of months to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addMonths = function (value) { - var n = this.getDate(); - this.setDate(1); - this.setMonth(this.getMonth() + value * 1); - this.setDate(Math.min(n, $D.getDaysInMonth(this.getFullYear(), this.getMonth()))); - return this; - }; - - /** - * Adds the specified number of years to this instance. - * @param {Number} The number of years to add. The number can be positive or negative [Required] - * @return {Date} this - */ - $P.addYears = function (value) { - return this.addMonths(value * 12); - }; - - /** - * Adds (or subtracts) to the value of the years, months, weeks, days, hours, minutes, seconds, milliseconds of the date instance using given configuration object. Positive and Negative values allowed. - * Example -
- Date.today().add( { days: 1, months: 1 } )
-
- new Date().add( { years: -1 } )
-
- * @param {Object} Configuration object containing attributes (months, days, etc.)
- * @return {Date} this
- */
- $P.add = function (config) {
- if (typeof config == "number") {
- this._orient = config;
- return this;
- }
-
- var x = config;
-
- if (x.milliseconds) {
- this.addMilliseconds(x.milliseconds);
- }
- if (x.seconds) {
- this.addSeconds(x.seconds);
- }
- if (x.minutes) {
- this.addMinutes(x.minutes);
- }
- if (x.hours) {
- this.addHours(x.hours);
- }
- if (x.weeks) {
- this.addWeeks(x.weeks);
- }
- if (x.months) {
- this.addMonths(x.months);
- }
- if (x.years) {
- this.addYears(x.years);
- }
- if (x.days) {
- this.addDays(x.days);
- }
- return this;
- };
-
- var $y, $m, $d;
-
- /**
- * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
- * This algorithm is a JavaScript port of the work presented by Claus Tøndering at http://www.tondering.dk/claus/cal/node8.html#SECTION00880000000000000000
- * .getWeek() Algorithm Copyright (c) 2008 Claus Tondering.
- * The .getWeek() function does NOT convert the date to UTC. The local datetime is used. Please use .getISOWeek() to get the week of the UTC converted date.
- * @return {Number} 1 to 53
- */
- $P.getWeek = function () {
- var a, b, c, d, e, f, g, n, s, w;
-
- $y = (!$y) ? this.getFullYear() : $y;
- $m = (!$m) ? this.getMonth() + 1 : $m;
- $d = (!$d) ? this.getDate() : $d;
-
- if ($m <= 2) {
- a = $y - 1;
- b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
- c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
- s = b - c;
- e = 0;
- f = $d - 1 + (31 * ($m - 1));
- } else {
- a = $y;
- b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
- c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
- s = b - c;
- e = s + 1;
- f = $d + ((153 * ($m - 3) + 2) / 5) + 58 + s;
- }
-
- g = (a + b) % 7;
- d = (f + g - e) % 7;
- n = (f + 3 - d) | 0;
-
- if (n < 0) {
- w = 53 - ((g - s) / 5 | 0);
- } else if (n > 364 + s) {
- w = 1;
- } else {
- w = (n / 7 | 0) + 1;
- }
-
- $y = $m = $d = null;
-
- return w;
- };
-
- /**
- * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
- * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
- * @return {String} "01" to "53"
- */
- $P.getISOWeek = function () {
- $y = this.getUTCFullYear();
- $m = this.getUTCMonth() + 1;
- $d = this.getUTCDate();
- return p(this.getWeek());
- };
-
- /**
- * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
- * @param {Number} A Number (1 to 53) that represents the week of the year.
- * @return {Date} this
- */
- $P.setWeek = function (n) {
- return this.moveToDayOfWeek(1).addWeeks(n - this.getWeek());
- };
-
- // private
- var validate = function (n, min, max, name) {
- if (typeof n == "undefined") {
- return false;
- } else if (typeof n != "number") {
- throw new TypeError(n + " is not a Number.");
- } else if (n < min || n > max) {
- throw new RangeError(n + " is not a valid value for " + name + ".");
- }
- return true;
- };
-
- /**
- * Validates the number is within an acceptable range for milliseconds [0-999].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateMillisecond = function (value) {
- return validate(value, 0, 999, "millisecond");
- };
-
- /**
- * Validates the number is within an acceptable range for seconds [0-59].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateSecond = function (value) {
- return validate(value, 0, 59, "second");
- };
-
- /**
- * Validates the number is within an acceptable range for minutes [0-59].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateMinute = function (value) {
- return validate(value, 0, 59, "minute");
- };
-
- /**
- * Validates the number is within an acceptable range for hours [0-23].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateHour = function (value) {
- return validate(value, 0, 23, "hour");
- };
-
- /**
- * Validates the number is within an acceptable range for the days in a month [0-MaxDaysInMonth].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateDay = function (value, year, month) {
- return validate(value, 1, $D.getDaysInMonth(year, month), "day");
- };
-
- /**
- * Validates the number is within an acceptable range for months [0-11].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateMonth = function (value) {
- return validate(value, 0, 11, "month");
- };
-
- /**
- * Validates the number is within an acceptable range for years.
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateYear = function (value) {
- return validate(value, 0, 9999, "year");
- };
-
- /**
- * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
- * Example
-
- Date.today().set( { day: 20, month: 1 } )
-
- new Date().set( { millisecond: 0 } )
-
- *
- * @param {Object} Configuration object containing attributes (month, day, etc.)
- * @return {Date} this
- */
- $P.set = function (config) {
- if ($D.validateMillisecond(config.millisecond)) {
- this.addMilliseconds(config.millisecond - this.getMilliseconds());
- }
-
- if ($D.validateSecond(config.second)) {
- this.addSeconds(config.second - this.getSeconds());
- }
-
- if ($D.validateMinute(config.minute)) {
- this.addMinutes(config.minute - this.getMinutes());
- }
-
- if ($D.validateHour(config.hour)) {
- this.addHours(config.hour - this.getHours());
- }
-
- if ($D.validateMonth(config.month)) {
- this.addMonths(config.month - this.getMonth());
- }
-
- if ($D.validateYear(config.year)) {
- this.addYears(config.year - this.getFullYear());
- }
-
- /* day has to go last because you can't validate the day without first knowing the month */
- if ($D.validateDay(config.day, this.getFullYear(), this.getMonth())) {
- this.addDays(config.day - this.getDate());
- }
-
- if (config.timezone) {
- this.setTimezone(config.timezone);
- }
-
- if (config.timezoneOffset) {
- this.setTimezoneOffset(config.timezoneOffset);
- }
-
- if (config.week && validate(config.week, 0, 53, "week")) {
- this.setWeek(config.week);
- }
-
- return this;
- };
-
- /**
- * Moves the date to the first day of the month.
- * @return {Date} this
- */
- $P.moveToFirstDayOfMonth = function () {
- return this.set({ day: 1 });
- };
-
- /**
- * Moves the date to the last day of the month.
- * @return {Date} this
- */
- $P.moveToLastDayOfMonth = function () {
- return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
- };
-
- /**
- * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
- * @param {Number} The dayOfWeek to move to
- * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
- * @return {Date} this
- */
- $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
- var shift = 0;
- if (occurrence > 0) {
- shift = occurrence - 1;
- }
- else if (occurrence === -1) {
- this.moveToLastDayOfMonth();
- if (this.getDay() !== dayOfWeek) {
- this.moveToDayOfWeek(dayOfWeek, -1);
- }
- return this;
- }
- return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
- };
-
- /**
- * Move to the next or last dayOfWeek based on the orient value.
- * @param {Number} The dayOfWeek to move to
- * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
- * @return {Date} this
- */
- $P.moveToDayOfWeek = function (dayOfWeek, orient) {
- var diff = (dayOfWeek - this.getDay() + 7 * (orient || +1)) % 7;
- return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff);
- };
-
- /**
- * Move to the next or last month based on the orient value.
- * @param {Number} The month to move to. 0 = January, 11 = December
- * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
- * @return {Date} this
- */
- $P.moveToMonth = function (month, orient) {
- var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12;
- return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff);
- };
-
- /**
- * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
- * @return {Number} 1 through 365 (366 in leap years)
- */
- $P.getOrdinalNumber = function () {
- return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
- };
-
- /**
- * Get the time zone abbreviation of the current date.
- * @return {String} The abbreviated time zone name (e.g. "EST")
- */
- $P.getTimezone = function () {
- return $D.getTimezoneAbbreviation(this.getUTCOffset());
- };
-
- $P.setTimezoneOffset = function (offset) {
- var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
- return this.addMinutes(there - here);
- };
-
- $P.setTimezone = function (offset) {
- return this.setTimezoneOffset($D.getTimezoneOffset(offset));
- };
-
- /**
- * Indicates whether Daylight Saving Time is observed in the current time zone.
- * @return {Boolean} true|false
- */
- $P.hasDaylightSavingTime = function () {
- return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
- };
-
- /**
- * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
- * @return {Boolean} true|false
- */
- $P.isDaylightSavingTime = function () {
- return Date.today().set({month: 0, day: 1}).getTimezoneOffset() != this.getTimezoneOffset();
- };
-
- /**
- * Get the offset from UTC of the current date.
- * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
- */
- $P.getUTCOffset = function () {
- var n = this.getTimezoneOffset() * -10 / 6, r;
- if (n < 0) {
- r = (n - 10000).toString();
- return r.charAt(0) + r.substr(2);
- } else {
- r = (n + 10000).toString();
- return "+" + r.substr(1);
- }
- };
-
- /**
- * Returns the number of milliseconds between this date and date.
- * @param {Date} Defaults to now
- * @return {Number} The diff in milliseconds
- */
- $P.getElapsed = function (date) {
- return (date || new Date()) - this;
- };
-
- if (!$P.toISOString) {
- /**
- * Converts the current date instance into a string with an ISO 8601 format. The date is converted to it's UTC value.
- * @return {String} ISO 8601 string of date
- */
- $P.toISOString = function () {
- // From http://www.json.org/json.js. Public Domain.
- function f(n) {
- return n < 10 ? '0' + n : n;
- }
-
- return '"' + this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z"';
- };
- }
-
- // private
- $P._toString = $P.toString;
-
- /**
- * Converts the value of the current Date object to its equivalent string representation.
- * Format Specifiers
- - CUSTOM DATE AND TIME FORMAT STRINGS - Format Description Example - ------ --------------------------------------------------------------------------- ----------------------- - s The seconds of the minute between 0-59. "0" to "59" - ss The seconds of the minute with leading zero if required. "00" to "59" - - m The minute of the hour between 0-59. "0" or "59" - mm The minute of the hour with leading zero if required. "00" or "59" - - h The hour of the day between 1-12. "1" to "12" - hh The hour of the day with leading zero if required. "01" to "12" - - H The hour of the day between 0-23. "0" to "23" - HH The hour of the day with leading zero if required. "00" to "23" - - d The day of the month between 1 and 31. "1" to "31" - dd The day of the month with leading zero if required. "01" to "31" - ddd Abbreviated day name. $C.abbreviatedDayNames. "Mon" to "Sun" - dddd The full day name. $C.dayNames. "Monday" to "Sunday" - - M The month of the year between 1-12. "1" to "12" - MM The month of the year with leading zero if required. "01" to "12" - MMM Abbreviated month name. $C.abbreviatedMonthNames. "Jan" to "Dec" - MMMM The full month name. $C.monthNames. "January" to "December" - - yy The year as a two-digit number. "99" or "08" - yyyy The full four digit year. "1999" or "2008" - - t Displays the first character of the A.M./P.M. designator. "A" or "P" - $C.amDesignator or $C.pmDesignator - tt Displays the A.M./P.M. designator. "AM" or "PM" - $C.amDesignator or $C.pmDesignator - - S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th" - -|| *Format* || *Description* || *Example* || -|| d || The CultureInfo shortDate Format Pattern || "M/d/yyyy" || -|| D || The CultureInfo longDate Format Pattern || "dddd, MMMM dd, yyyy" || -|| F || The CultureInfo fullDateTime Format Pattern || "dddd, MMMM dd, yyyy h:mm:ss tt" || -|| m || The CultureInfo monthDay Format Pattern || "MMMM dd" || -|| r || The CultureInfo rfc1123 Format Pattern || "ddd, dd MMM yyyy HH:mm:ss GMT" || -|| s || The CultureInfo sortableDateTime Format Pattern || "yyyy-MM-ddTHH:mm:ss" || -|| t || The CultureInfo shortTime Format Pattern || "h:mm tt" || -|| T || The CultureInfo longTime Format Pattern || "h:mm:ss tt" || -|| u || The CultureInfo universalSortableDateTime Format Pattern || "yyyy-MM-dd HH:mm:ssZ" || -|| y || The CultureInfo yearMonth Format Pattern || "MMMM, yyyy" || - - - STANDARD DATE AND TIME FORMAT STRINGS - Format Description Example ("en-US") - ------ --------------------------------------------------------------------------- ----------------------- - d The CultureInfo shortDate Format Pattern "M/d/yyyy" - D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy" - F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt" - m The CultureInfo monthDay Format Pattern "MMMM dd" - r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT" - s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss" - t The CultureInfo shortTime Format Pattern "h:mm tt" - T The CultureInfo longTime Format Pattern "h:mm:ss tt" - u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ" - y The CultureInfo yearMonth Format Pattern "MMMM, yyyy" -- * @param {String} A format string consisting of one or more format spcifiers [Optional]. - * @return {String} A string representation of the current Date object. - */ - $P.toString = function (format) { - var x = this; - - // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and - // may vary by culture. - if (format && format.length == 1) { - var c = $C.formatPatterns; - x.t = x.toString; - switch (format) { - case "d": - return x.t(c.shortDate); - case "D": - return x.t(c.longDate); - case "F": - return x.t(c.fullDateTime); - case "m": - return x.t(c.monthDay); - case "r": - return x.t(c.rfc1123); - case "s": - return x.t(c.sortableDateTime); - case "t": - return x.t(c.shortTime); - case "T": - return x.t(c.longTime); - case "u": - return x.t(c.universalSortableDateTime); - case "y": - return x.t(c.yearMonth); - } - } - - var ord = function (n) { - switch (n * 1) { - case 1: - case 21: - case 31: - return "st"; - case 2: - case 22: - return "nd"; - case 3: - case 23: - return "rd"; - default: - return "th"; - } - }; - - return format ? format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g, - function (m) { - if (m.charAt(0) === "\\") { - return m.replace("\\", ""); - } - x.h = x.getHours; - switch (m) { - case "hh": - return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12)); - case "h": - return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12); - case "HH": - return p(x.h()); - case "H": - return x.h(); - case "mm": - return p(x.getMinutes()); - case "m": - return x.getMinutes(); - case "ss": - return p(x.getSeconds()); - case "s": - return x.getSeconds(); - case "yyyy": - return p(x.getFullYear(), 4); - case "yy": - return p(x.getFullYear()); - case "dddd": - return $C.dayNames[x.getDay()]; - case "ddd": - return $C.abbreviatedDayNames[x.getDay()]; - case "dd": - return p(x.getDate()); - case "d": - return x.getDate(); - case "MMMM": - return $C.monthNames[x.getMonth()]; - case "MMM": - return $C.abbreviatedMonthNames[x.getMonth()]; - case "MM": - return p((x.getMonth() + 1)); - case "M": - return x.getMonth() + 1; - case "t": - return x.h() < 12 ? $C.amDesignator.substring(0, 1) : $C.pmDesignator.substring(0, 1); - case "tt": - return x.h() < 12 ? $C.amDesignator : $C.pmDesignator; - case "S": - return ord(x.getDate()); - default: - return m; - } - } - ) : this._toString(); - }; -}()); /** - * @version: 1.0 Alpha-1 - * @author: Coolite Inc. http://www.coolite.com/ - * @date: 2008-04-13 - * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved. - * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. - * @website: http://www.datejs.com/ - */ - -(function () { - Date.Parsing = { - Exception: function (s) { - this.message = "Parse error at '" + s.substring(0, 10) + " ...'"; - } - }; - - var $P = Date.Parsing; - var _ = $P.Operators = { - // - // Tokenizers - // - rtoken: function (r) { // regex token - return function (s) { - var mx = s.match(r); - if (mx) { - return ([ mx[0], s.substring(mx[0].length) ]); - } else { - throw new $P.Exception(s); - } - }; - }, - token: function (s) { // whitespace-eating token - return function (s) { - return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s); - // Removed .strip() - // return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s).strip(); - }; - }, - stoken: function (s) { // string token - return _.rtoken(new RegExp("^" + s)); - }, - - // - // Atomic Operators - // - - until: function (p) { - return function (s) { - var qx = [], rx = null; - while (s.length) { - try { - rx = p.call(this, s); - } catch (e) { - qx.push(rx[0]); - s = rx[1]; - continue; - } - break; - } - return [ qx, s ]; - }; - }, - many: function (p) { - return function (s) { - var rx = [], r = null; - while (s.length) { - try { - r = p.call(this, s); - } catch (e) { - return [ rx, s ]; - } - rx.push(r[0]); - s = r[1]; - } - return [ rx, s ]; - }; - }, - - // generator operators -- see below - optional: function (p) { - return function (s) { - var r = null; - try { - r = p.call(this, s); - } catch (e) { - return [ null, s ]; - } - return [ r[0], r[1] ]; - }; - }, - not: function (p) { - return function (s) { - try { - p.call(this, s); - } catch (e) { - return [null, s]; - } - throw new $P.Exception(s); - }; - }, - ignore: function (p) { - return p ? - function (s) { - var r = null; - r = p.call(this, s); - return [null, r[1]]; - } : null; - }, - product: function () { - var px = arguments[0], - qx = Array.prototype.slice.call(arguments, 1), rx = []; - for (var i = 0 ; i < px.length ; i++) { - rx.push(_.each(px[i], qx)); - } - return rx; - }, - cache: function (rule) { - var cache = {}, r = null; - return function (s) { - try { - r = cache[s] = (cache[s] || rule.call(this, s)); - } catch (e) { - r = cache[s] = e; - } - if (r instanceof $P.Exception) { - throw r; - } else { - return r; - } - }; - }, - - // vector operators -- see below - any: function () { - var px = arguments; - return function (s) { - var r = null; - for (var i = 0; i < px.length; i++) { - if (px[i] == null) { - continue; - } - try { - r = (px[i].call(this, s)); - } catch (e) { - r = null; - } - if (r) { - return r; - } - } - throw new $P.Exception(s); - }; - }, - each: function () { - var px = arguments; - return function (s) { - var rx = [], r = null; - for (var i = 0; i < px.length ; i++) { - if (px[i] == null) { - continue; - } - try { - r = (px[i].call(this, s)); - } catch (e) { - throw new $P.Exception(s); - } - rx.push(r[0]); - s = r[1]; - } - return [ rx, s]; - }; - }, - all: function () { - var px = arguments, _ = _; - return _.each(_.optional(px)); - }, - - // delimited operators - sequence: function (px, d, c) { - d = d || _.rtoken(/^\s*/); - c = c || null; - - if (px.length == 1) { - return px[0]; - } - return function (s) { - var r = null, q = null; - var rx = []; - for (var i = 0; i < px.length ; i++) { - try { - r = px[i].call(this, s); - } catch (e) { - break; - } - rx.push(r[0]); - try { - q = d.call(this, r[1]); - } catch (ex) { - q = null; - break; - } - s = q[1]; - } - if (!r) { - throw new $P.Exception(s); - } - if (q) { - throw new $P.Exception(q[1]); - } - if (c) { - try { - r = c.call(this, r[1]); - } catch (ey) { - throw new $P.Exception(r[1]); - } - } - return [ rx, (r?r[1]:s) ]; - }; - }, - - // - // Composite Operators - // - - between: function (d1, p, d2) { - d2 = d2 || d1; - var _fn = _.each(_.ignore(d1), p, _.ignore(d2)); - return function (s) { - var rx = _fn.call(this, s); - return [[rx[0][0], r[0][2]], rx[1]]; - }; - }, - list: function (p, d, c) { - d = d || _.rtoken(/^\s*/); - c = c || null; - return (p instanceof Array ? - _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) : - _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c))); - }, - set: function (px, d, c) { - d = d || _.rtoken(/^\s*/); - c = c || null; - return function (s) { - // r is the current match, best the current 'best' match - // which means it parsed the most amount of input - var r = null, p = null, q = null, rx = null, best = [[], s], last = false; - - // go through the rules in the given set - for (var i = 0; i < px.length ; i++) { - - // last is a flag indicating whether this must be the last element - // if there is only 1 element, then it MUST be the last one - q = null; - p = null; - r = null; - last = (px.length == 1); - - // first, we try simply to match the current pattern - // if not, try the next pattern - try { - r = px[i].call(this, s); - } catch (e) { - continue; - } - - // since we are matching against a set of elements, the first - // thing to do is to add r[0] to matched elements - rx = [[r[0]], r[1]]; - - // if we matched and there is still input to parse and - // we don't already know this is the last element, - // we're going to next check for the delimiter ... - // if there's none, or if there's no input left to parse - // than this must be the last element after all ... - if (r[1].length > 0 && ! last) { - try { - q = d.call(this, r[1]); - } catch (ex) { - last = true; - } - } else { - last = true; - } - - // if we parsed the delimiter and now there's no more input, - // that means we shouldn't have parsed the delimiter at all - // so don't update r and mark this as the last element ... - if (!last && q[1].length === 0) { - last = true; - } - - - // so, if this isn't the last element, we're going to see if - // we can get any more matches from the remaining (unmatched) - // elements ... - if (!last) { - - // build a list of the remaining rules we can match against, - // i.e., all but the one we just matched against - var qx = []; - for (var j = 0; j < px.length ; j++) { - if (i != j) { - qx.push(px[j]); - } - } - - // now invoke recursively set with the remaining input - // note that we don't include the closing delimiter ... - // we'll check for that ourselves at the end - p = _.set(qx, d).call(this, q[1]); - - // if we got a non-empty set as a result ... - // (otw rx already contains everything we want to match) - if (p[0].length > 0) { - // update current result, which is stored in rx ... - // basically, pick up the remaining text from p[1] - // and concat the result from p[0] so that we don't - // get endless nesting ... - rx[0] = rx[0].concat(p[0]); - rx[1] = p[1]; - } - } - - // at this point, rx either contains the last matched element - // or the entire matched set that starts with this element. - - // now we just check to see if this variation is better than - // our best so far, in terms of how much of the input is parsed - if (rx[1].length < best[1].length) { - best = rx; - } - - // if we've parsed all the input, then we're finished - if (best[1].length === 0) { - break; - } - } - - // so now we've either gone through all the patterns trying them - // as the initial match; or we found one that parsed the entire - // input string ... - - // if best has no matches, just return empty set ... - if (best[0].length === 0) { - return best; - } - - // if a closing delimiter is provided, then we have to check it also - if (c) { - // we try this even if there is no remaining input because the pattern - // may well be optional or match empty input ... - try { - q = c.call(this, best[1]); - } catch (ey) { - throw new $P.Exception(best[1]); - } - - // it parsed ... be sure to update the best match remaining input - best[1] = q[1]; - } - - // if we're here, either there was no closing delimiter or we parsed it - // so now we have the best match; just return it! - return best; - }; - }, - forward: function (gr, fname) { - return function (s) { - return gr[fname].call(this, s); - }; - }, - - // - // Translation Operators - // - replace: function (rule, repl) { - return function (s) { - var r = rule.call(this, s); - return [repl, r[1]]; - }; - }, - process: function (rule, fn) { - return function (s) { - var r = rule.call(this, s); - return [fn.call(this, r[0]), r[1]]; - }; - }, - min: function (min, rule) { - return function (s) { - var rx = rule.call(this, s); - if (rx[0].length < min) { - throw new $P.Exception(s); - } - return rx; - }; - } - }; - - - // Generator Operators And Vector Operators - - // Generators are operators that have a signature of F(R) => R, - // taking a given rule and returning another rule, such as - // ignore, which parses a given rule and throws away the result. - - // Vector operators are those that have a signature of F(R1,R2,...) => R, - // take a list of rules and returning a new rule, such as each. - - // Generator operators are converted (via the following _generator - // function) into functions that can also take a list or array of rules - // and return an array of new rules as though the function had been - // called on each rule in turn (which is what actually happens). - - // This allows generators to be used with vector operators more easily. - // Example: - // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar)) - - // This also turns generators into vector operators, which allows - // constructs like: - // not(cache(foo, bar)) - - var _generator = function (op) { - return function () { - var args = null, rx = []; - if (arguments.length > 1) { - args = Array.prototype.slice.call(arguments); - } else if (arguments[0] instanceof Array) { - args = arguments[0]; - } - if (args) { - for (var i = 0, px = args.shift() ; i < px.length ; i++) { - args.unshift(px[i]); - rx.push(op.apply(null, args)); - args.shift(); - return rx; - } - } else { - return op.apply(null, arguments); - } - }; - }; - - var gx = "optional not ignore cache".split(/\s/); - - for (var i = 0 ; i < gx.length ; i++) { - _[gx[i]] = _generator(_[gx[i]]); - } - - var _vector = function (op) { - return function () { - if (arguments[0] instanceof Array) { - return op.apply(null, arguments[0]); - } else { - return op.apply(null, arguments); - } - }; - }; - - var vx = "each any all".split(/\s/); - - for (var j = 0 ; j < vx.length ; j++) { - _[vx[j]] = _vector(_[vx[j]]); - } - -}()); - -(function () { - var $D = Date, $P = $D.prototype, $C = $D.CultureInfo; - - var flattenAndCompact = function (ax) { - var rx = []; - for (var i = 0; i < ax.length; i++) { - if (ax[i] instanceof Array) { - rx = rx.concat(flattenAndCompact(ax[i])); - } else { - if (ax[i]) { - rx.push(ax[i]); - } - } - } - return rx; - }; - - $D.Grammar = {}; - - $D.Translator = { - hour: function (s) { - return function () { - this.hour = Number(s); - }; - }, - minute: function (s) { - return function () { - this.minute = Number(s); - }; - }, - second: function (s) { - return function () { - this.second = Number(s); - }; - }, - meridian: function (s) { - return function () { - this.meridian = s.slice(0, 1).toLowerCase(); - }; - }, - timezone: function (s) { - return function () { - var n = s.replace(/[^\d\+\-]/g, ""); - if (n.length) { - this.timezoneOffset = Number(n); - } else { - this.timezone = s.toLowerCase(); - } - }; - }, - day: function (x) { - var s = x[0]; - return function () { - this.day = Number(s.match(/\d+/)[0]); - }; - }, - month: function (s) { - return function () { - this.month = (s.length == 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1; - }; - }, - year: function (s) { - return function () { - var n = Number(s); - this.year = ((s.length > 2) ? n : - (n + (((n + 2000) < $C.twoDigitYearMax) ? 2000 : 1900))); - }; - }, - rday: function (s) { - return function () { - switch (s) { - case "yesterday": - this.days = -1; - break; - case "tomorrow": - this.days = 1; - break; - case "today": - this.days = 0; - break; - case "now": - this.days = 0; - this.now = true; - break; - } - }; - }, - finishExact: function (x) { - x = (x instanceof Array) ? x : [ x ]; - - for (var i = 0 ; i < x.length ; i++) { - if (x[i]) { - x[i].call(this); - } - } - - var now = new Date(); - - if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) { - this.day = now.getDate(); - } - - if (!this.year) { - this.year = now.getFullYear(); - } - - if (!this.month && this.month !== 0) { - this.month = now.getMonth(); - } - - if (!this.day) { - this.day = 1; - } - - if (!this.hour) { - this.hour = 0; - } - - if (!this.minute) { - this.minute = 0; - } - - if (!this.second) { - this.second = 0; - } - - if (this.meridian && this.hour) { - if (this.meridian == "p" && this.hour < 12) { - this.hour = this.hour + 12; - } else if (this.meridian == "a" && this.hour == 12) { - this.hour = 0; - } - } - - if (this.day > $D.getDaysInMonth(this.year, this.month)) { - throw new RangeError(this.day + " is not a valid value for days."); - } - - var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second); - - if (this.timezone) { - r.set({ timezone: this.timezone }); - } else if (this.timezoneOffset) { - r.set({ timezoneOffset: this.timezoneOffset }); - } - - return r; - }, - finish: function (x) { - x = (x instanceof Array) ? flattenAndCompact(x) : [ x ]; - - if (x.length === 0) { - return null; - } - - for (var i = 0 ; i < x.length ; i++) { - if (typeof x[i] == "function") { - x[i].call(this); - } - } - - var today = $D.today(); - - if (this.now && !this.unit && !this.operator) { - return new Date(); - } else if (this.now) { - today = new Date(); - } - - var expression = !!(this.days && this.days !== null || this.orient || this.operator); - - var gap, mod, orient; - orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1); - - if(!this.now && "hour minute second".indexOf(this.unit) != -1) { - today.setTimeToNow(); - } - - if (this.month || this.month === 0) { - if ("year day hour minute second".indexOf(this.unit) != -1) { - this.value = this.month + 1; - this.month = null; - expression = true; - } - } - - if (!expression && this.weekday && !this.day && !this.days) { - var temp = Date[this.weekday](); - this.day = temp.getDate(); - if (!this.month) { - this.month = temp.getMonth(); - } - this.year = temp.getFullYear(); - } - - if (expression && this.weekday && this.unit != "month") { - this.unit = "day"; - gap = ($D.getDayNumberFromName(this.weekday) - today.getDay()); - mod = 7; - this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); - } - - if (this.month && this.unit == "day" && this.operator) { - this.value = (this.month + 1); - this.month = null; - } - - if (this.value != null && this.month != null && this.year != null) { - this.day = this.value * 1; - } - - if (this.month && !this.day && this.value) { - today.set({ day: this.value * 1 }); - if (!expression) { - this.day = this.value * 1; - } - } - - if (!this.month && this.value && this.unit == "month" && !this.now) { - this.month = this.value; - expression = true; - } - - if (expression && (this.month || this.month === 0) && this.unit != "year") { - this.unit = "month"; - gap = (this.month - today.getMonth()); - mod = 12; - this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); - this.month = null; - } - - if (!this.unit) { - this.unit = "day"; - } - - if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) { - this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator == "add") ? 1 : -1) + (this.value||0) * orient; - } else if (this[this.unit + "s"] == null || this.operator != null) { - if (!this.value) { - this.value = 1; - } - this[this.unit + "s"] = this.value * orient; - } - - if (this.meridian && this.hour) { - if (this.meridian == "p" && this.hour < 12) { - this.hour = this.hour + 12; - } else if (this.meridian == "a" && this.hour == 12) { - this.hour = 0; - } - } - - if (this.weekday && !this.day && !this.days) { - var temp = Date[this.weekday](); - this.day = temp.getDate(); - if (temp.getMonth() !== today.getMonth()) { - this.month = temp.getMonth(); - } - } - - if ((this.month || this.month === 0) && !this.day) { - this.day = 1; - } - - if (!this.orient && !this.operator && this.unit == "week" && this.value && !this.day && !this.month) { - return Date.today().setWeek(this.value); - } - - if (expression && this.timezone && this.day && this.days) { - this.day = this.days; - } - - return (expression) ? today.add(this) : today.set(this); - } - }; - - var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn; - - g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/); - g.timePartDelimiter = _.stoken(":"); - g.whiteSpace = _.rtoken(/^\s*/); - g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/); - - var _C = {}; - g.ctoken = function (keys) { - var fn = _C[keys]; - if (! fn) { - var c = $C.regexPatterns; - var kx = keys.split(/\s+/), px = []; - for (var i = 0; i < kx.length ; i++) { - px.push(_.replace(_.rtoken(c[kx[i]]), kx[i])); - } - fn = _C[keys] = _.any.apply(null, px); - } - return fn; - }; - g.ctoken2 = function (key) { - return _.rtoken($C.regexPatterns[key]); - }; - - // hour, minute, second, meridian, timezone - g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour)); - g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour)); - g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour)); - g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour)); - g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute)); - g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute)); - g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second)); - g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second)); - g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter)); - - // _.min(1, _.set([ g.H, g.m, g.s ], g._t)); - g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian)); - g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian)); - g.z = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone)); - g.zz = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone)); - - g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone)); - g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ])); - g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix); - - // days, months, years - g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/), - _.optional(g.ctoken2("ordinalSuffix"))), t.day)); - g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/), - _.optional(g.ctoken2("ordinalSuffix"))), t.day)); - g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"), - function (s) { - return function () { - this.weekday = s; - }; - } - )); - g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month)); - g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month)); - g.MMM = g.MMMM = _.cache(_.process( - g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month)); - g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year)); - g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year)); - g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year)); - g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year)); - - // rolling these up into general purpose rules - _fn = function () { - return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext"))); - }; - - g.day = _fn(g.d, g.dd); - g.month = _fn(g.M, g.MMM); - g.year = _fn(g.yyyy, g.yy); - - // relative date / time expressions - g.orientation = _.process(g.ctoken("past future"), - function (s) { - return function () { - this.orient = s; - }; - } - ); - g.operator = _.process(g.ctoken("add subtract"), - function (s) { - return function () { - this.operator = s; - }; - } - ); - g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday); - g.unit = _.process(g.ctoken("second minute hour day week month year"), - function (s) { - return function () { - this.unit = s; - }; - } - ); - g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/), - function (s) { - return function () { - this.value = s.replace(/\D/g, ""); - }; - } - ); - g.expression = _.set([ g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]); - - // pre-loaded rules for different date part order preferences - _fn = function () { - return _.set(arguments, g.datePartDelimiter); - }; - g.mdy = _fn(g.ddd, g.month, g.day, g.year); - g.ymd = _fn(g.ddd, g.year, g.month, g.day); - g.dmy = _fn(g.ddd, g.day, g.month, g.year); - g.date = function (s) { - return ((g[$C.dateElementOrder] || g.mdy).call(this, s)); - }; - - // parsing date format specifiers - ex: "h:m:s tt" - // this little guy will generate a custom parser based - // on the format string, ex: g.format("h:m:s tt") - g.format = _.process(_.many( - _.any( - // translate format specifiers into grammar rules - _.process( - _.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/), - function (fmt) { - if (g[fmt]) { - return g[fmt]; - } else { - throw $D.Parsing.Exception(fmt); - } - } - ), - // translate separator tokens into token rules - _.process( - _.rtoken(/^[^dMyhHmstz]+/), // all legal separators - function (s) { - return _.ignore(_.stoken(s)); - } - ) - )), - // construct the parser ... - function (rules) { - return _.process(_.each.apply(null, rules), t.finishExact); - } - ); - - var _F = { - //"M/d/yyyy": function (s) { - // var m = s.match(/^([0-2]\d|3[0-1]|\d)\/(1[0-2]|0\d|\d)\/(\d\d\d\d)/); - // if (m!=null) { - // var r = [ t.month.call(this,m[1]), t.day.call(this,m[2]), t.year.call(this,m[3]) ]; - // r = t.finishExact.call(this,r); - // return [ r, "" ]; - // } else { - // throw new Date.Parsing.Exception(s); - // } - //} - //"M/d/yyyy": function (s) { return [ new Date(Date._parse(s)), ""]; } - }; - var _get = function (f) { - return _F[f] = (_F[f] || g.format(f)[0]); - }; - - g.formats = function (fx) { - if (fx instanceof Array) { - var rx = []; - for (var i = 0 ; i < fx.length ; i++) { - rx.push(_get(fx[i])); - } - return _.any.apply(null, rx); - } else { - return _get(fx); - } - }; - - // check for these formats first - g._formats = g.formats([ - "\"yyyy-MM-ddTHH:mm:ssZ\"", - "yyyy-MM-ddTHH:mm:ssZ", - "yyyy-MM-ddTHH:mm:ssz", - "yyyy-MM-ddTHH:mm:ss", - "yyyy-MM-ddTHH:mmZ", - "yyyy-MM-ddTHH:mmz", - "yyyy-MM-ddTHH:mm", - "ddd, MMM dd, yyyy H:mm:ss tt", - "ddd MMM d yyyy HH:mm:ss zzz", - "MMddyyyy", - "ddMMyyyy", - "Mddyyyy", - "ddMyyyy", - "Mdyyyy", - "dMyyyy", - "yyyy", - "Mdyy", - "dMyy", - "d" - ]); - - // starting rule for general purpose grammar - g._start = _.process(_.set([ g.date, g.time, g.expression ], - g.generalDelimiter, g.whiteSpace), t.finish); - - // real starting rule: tries selected formats first, - // then general purpose rule - g.start = function (s) { - try { - var r = g._formats.call({}, s); - if (r[1].length === 0) { - return r; - } - } catch (e) {} - return g._start.call({}, s); - }; - - $D._parse = $D.parse; - - /** - * Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information. - * - * Example -
- ///////////
- // Dates //
- ///////////
-
- // 15-Oct-2004
- var d1 = Date.parse("10/15/2004");
-
- // 15-Oct-2004
- var d1 = Date.parse("15-Oct-2004");
-
- // 15-Oct-2004
- var d1 = Date.parse("2004.10.15");
-
- //Fri Oct 15, 2004
- var d1 = Date.parse("Fri Oct 15, 2004");
-
- ///////////
- // Times //
- ///////////
-
- // Today at 10 PM.
- var d1 = Date.parse("10 PM");
-
- // Today at 10:30 PM.
- var d1 = Date.parse("10:30 P.M.");
-
- // Today at 6 AM.
- var d1 = Date.parse("06am");
-
- /////////////////////
- // Dates and Times //
- /////////////////////
-
- // 8-July-2004 @ 10:30 PM
- var d1 = Date.parse("July 8th, 2004, 10:30 PM");
-
- // 1-July-2004 @ 10:30 PM
- var d1 = Date.parse("2004-07-01T22:30:00");
-
- ////////////////////
- // Relative Dates //
- ////////////////////
-
- // Returns today's date. The string "today" is culture specific.
- var d1 = Date.parse("today");
-
- // Returns yesterday's date. The string "yesterday" is culture specific.
- var d1 = Date.parse("yesterday");
-
- // Returns the date of the next thursday.
- var d1 = Date.parse("Next thursday");
-
- // Returns the date of the most previous monday.
- var d1 = Date.parse("last monday");
-
- // Returns today's day + one year.
- var d1 = Date.parse("next year");
-
- ///////////////
- // Date Math //
- ///////////////
-
- // Today + 2 days
- var d1 = Date.parse("t+2");
-
- // Today + 2 days
- var d1 = Date.parse("today + 2 days");
-
- // Today + 3 months
- var d1 = Date.parse("t+3m");
-
- // Today - 1 year
- var d1 = Date.parse("today - 1 year");
-
- // Today - 1 year
- var d1 = Date.parse("t-1y");
-
-
- /////////////////////////////
- // Partial Dates and Times //
- /////////////////////////////
-
- // July 15th of this year.
- var d1 = Date.parse("July 15");
-
- // 15th day of current day and year.
- var d1 = Date.parse("15");
-
- // July 1st of current year at 10pm.
- var d1 = Date.parse("7/1 10pm");
-
- *
- * @param {String} The string value to convert into a Date object [Required]
- * @return {Date} A Date object or null if the string cannot be converted into a Date.
- */
- $D.parse = function (s) {
- var r = null;
- if (!s) {
- return null;
- }
- if (s instanceof Date) {
- return s;
- }
- try {
- r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
- } catch (e) {
- return null;
- }
- return ((r[1].length === 0) ? r[0] : null);
- };
-
- $D.getParseFunction = function (fx) {
- var fn = $D.Grammar.formats(fx);
- return function (s) {
- var r = null;
- try {
- r = fn.call({}, s);
- } catch (e) {
- return null;
- }
- return ((r[1].length === 0) ? r[0] : null);
- };
- };
-
- /**
- * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
- * The format of the string value must match one of the supplied formats exactly.
- *
- * Example
-
- // 15-Oct-2004
- var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
-
- // 15-Oct-2004
- var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
-
- // 15-Oct-2004
- var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
-
- // Multiple formats
- var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
-
- *
- * @param {String} The string value to convert into a Date object [Required].
- * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
- * @return {Date} A Date object or null if the string cannot be converted into a Date.
- */
- $D.parseExact = function (s, fx) {
- return $D.getParseFunction(fx)(s);
- };
+ // hour, minute, second, meridian, timezone
+ g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour));
+ g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour));
+ g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour));
+ g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour));
+ g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute));
+ g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute));
+ g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second));
+ g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second));
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ // _.min(1, _.set([ g.H, g.m, g.s ], g._t));
+ g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian));
+ g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian));
+ g.z = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
+ g.zz = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
+
+ g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone));
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+
+ // days, months, years
+ g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),
+ _.optional(g.ctoken2("ordinalSuffix"))), t.day));
+ g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),
+ _.optional(g.ctoken2("ordinalSuffix"))), t.day));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+ g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month));
+ g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month));
+ g.MMM = g.MMMM = _.cache(_.process(
+ g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year));
+ g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year));
+ g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year));
+ g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year));
+
+ // rolling these up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([ g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ // pre-loaded rules for different date part order preferences
+ _fn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ g.mdy = _fn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _fn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _fn(g.ddd, g.day, g.month, g.year);
+ g.date = function (s) {
+ return ((g[$C.dateElementOrder] || g.mdy).call(this, s));
+ };
+
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(
+ _.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ var _F = {
+ //"M/d/yyyy": function (s) {
+ // var m = s.match(/^([0-2]\d|3[0-1]|\d)\/(1[0-2]|0\d|\d)\/(\d\d\d\d)/);
+ // if (m!=null) {
+ // var r = [ t.month.call(this,m[1]), t.day.call(this,m[2]), t.year.call(this,m[3]) ];
+ // r = t.finishExact.call(this,r);
+ // return [ r, "" ];
+ // } else {
+ // throw new Date.Parsing.Exception(s);
+ // }
+ //}
+ //"M/d/yyyy": function (s) { return [ new Date(Date._parse(s)), ""]; }
+ };
+ var _get = function (f) {
+ return _F[f] = (_F[f] || g.format(f)[0]);
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+
+ $D._parse = $D.parse;
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parse = function (s) {
+ var r = null;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s;
+ }
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+ return ((r[1].length === 0) ? r[0] : null);
+ };
+
+ $D.getParseFunction = function (fx) {
+ var fn = $D.Grammar.formats(fx);
+ return function (s) {
+ var r = null;
+ try {
+ r = fn.call({}, s);
+ } catch (e) {
+ return null;
+ }
+ return ((r[1].length === 0) ? r[0] : null);
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
}());/*
http://www.JSON.org/json2.js
2008-11-19
@@ -3920,346 +3923,346 @@ replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// Export module
module.exports = _s;
- // Integrate with Underscore.js
- } else if (typeof root._ !== 'undefined') {
- root._.mixin(_s);
+ // Integrate with Underscore.js
+ } else if (typeof root._ !== 'undefined') {
+ root._.mixin(_s);
+
+ // Or define it
+ } else {
+ root._ = _s;
+ }
+
+}());
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
+ * in FIPS 180-1
+ * Version 2.2 Copyright Paul Johnston 2000 - 2009.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); }
+function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); }
+function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); }
+function hex_hmac_sha1(k, d)
+ { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_sha1(k, d)
+ { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_sha1(k, d, e)
+ { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function sha1_vm_test()
+{
+ return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
+}
+
+/*
+ * Calculate the SHA1 of a raw string
+ */
+function rstr_sha1(s)
+{
+ return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8));
+}
+
+/*
+ * Calculate the HMAC-SHA1 of a key and some data (raw strings)
+ */
+function rstr_hmac_sha1(key, data)
+{
+ var bkey = rstr2binb(key);
+ if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8);
+
+ var ipad = Array(16), opad = Array(16);
+ for(var i = 0; i < 16; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
+ return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160));
+}
+
+/*
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var remainders = Array();
+ var i, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. We stop when the dividend is zero.
+ * All remainders are stored for later use.
+ */
+ while(dividend.length > 0)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[remainders.length] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ /* Append leading zero equivalents */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)))
+ for(i = output.length; i < full_length; i++)
+ output = encoding[0] + output;
+
+ return output;
+}
+
+/*
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/*
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/*
+ * Convert a raw string to an array of big-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binb(input)
+{
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
+ return output;
+}
+
+/*
+ * Convert an array of big-endian words to a string
+ */
+function binb2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
+ return output;
+}
+
+/*
+ * Calculate the SHA-1 of an array of big-endian words, and a bit length
+ */
+function binb_sha1(x, len)
+{
+ /* append padding */
+ x[len >> 5] |= 0x80 << (24 - len % 32);
+ x[((len + 64 >> 9) << 4) + 15] = len;
+
+ var w = Array(80);
+ var a = 1732584193;
+ var b = -271733879;
+ var c = -1732584194;
+ var d = 271733878;
+ var e = -1009589776;
+
+ for(var i = 0; i < x.length; i += 16)
+ {
+ var olda = a;
+ var oldb = b;
+ var oldc = c;
+ var oldd = d;
+ var olde = e;
+
+ for(var j = 0; j < 80; j++)
+ {
+ if(j < 16) w[j] = x[i + j];
+ else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
+ var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
+ safe_add(safe_add(e, w[j]), sha1_kt(j)));
+ e = d;
+ d = c;
+ c = bit_rol(b, 30);
+ b = a;
+ a = t;
+ }
+
+ a = safe_add(a, olda);
+ b = safe_add(b, oldb);
+ c = safe_add(c, oldc);
+ d = safe_add(d, oldd);
+ e = safe_add(e, olde);
+ }
+ return Array(a, b, c, d, e);
+
+}
+
+/*
+ * Perform the appropriate triplet combination function for the current
+ * iteration
+ */
+function sha1_ft(t, b, c, d)
+{
+ if(t < 20) return (b & c) | ((~b) & d);
+ if(t < 40) return b ^ c ^ d;
+ if(t < 60) return (b & c) | (b & d) | (c & d);
+ return b ^ c ^ d;
+}
+
+/*
+ * Determine the appropriate additive constant for the current iteration
+ */
+function sha1_kt(t)
+{
+ return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
+ (t < 60) ? -1894007588 : -899497514;
+}
- // Or define it
- } else {
- root._ = _s;
- }
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+}
-}());
-/*
- * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
- * in FIPS 180-1
- * Version 2.2 Copyright Paul Johnston 2000 - 2009.
- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
- * Distributed under the BSD License
- * See http://pajhome.org.uk/crypt/md5 for details.
- */
-
-/*
- * Configurable variables. You may need to tweak these to be compatible with
- * the server-side, but the defaults work in most cases.
- */
-var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
-var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
-
-/*
- * These are the functions you'll usually want to call
- * They take string arguments and return either hex or base-64 encoded strings
- */
-function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); }
-function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); }
-function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); }
-function hex_hmac_sha1(k, d)
- { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
-function b64_hmac_sha1(k, d)
- { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
-function any_hmac_sha1(k, d, e)
- { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
-
-/*
- * Perform a simple self-test to see if the VM is working
- */
-function sha1_vm_test()
-{
- return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
-}
-
-/*
- * Calculate the SHA1 of a raw string
- */
-function rstr_sha1(s)
-{
- return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8));
-}
-
-/*
- * Calculate the HMAC-SHA1 of a key and some data (raw strings)
- */
-function rstr_hmac_sha1(key, data)
-{
- var bkey = rstr2binb(key);
- if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8);
-
- var ipad = Array(16), opad = Array(16);
- for(var i = 0; i < 16; i++)
- {
- ipad[i] = bkey[i] ^ 0x36363636;
- opad[i] = bkey[i] ^ 0x5C5C5C5C;
- }
-
- var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
- return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160));
-}
-
-/*
- * Convert a raw string to a hex string
- */
-function rstr2hex(input)
-{
- try { hexcase } catch(e) { hexcase=0; }
- var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
- var output = "";
- var x;
- for(var i = 0; i < input.length; i++)
- {
- x = input.charCodeAt(i);
- output += hex_tab.charAt((x >>> 4) & 0x0F)
- + hex_tab.charAt( x & 0x0F);
- }
- return output;
-}
-
-/*
- * Convert a raw string to a base-64 string
- */
-function rstr2b64(input)
-{
- try { b64pad } catch(e) { b64pad=''; }
- var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- var output = "";
- var len = input.length;
- for(var i = 0; i < len; i += 3)
- {
- var triplet = (input.charCodeAt(i) << 16)
- | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
- | (i + 2 < len ? input.charCodeAt(i+2) : 0);
- for(var j = 0; j < 4; j++)
- {
- if(i * 8 + j * 6 > input.length * 8) output += b64pad;
- else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
- }
- }
- return output;
-}
-
-/*
- * Convert a raw string to an arbitrary string encoding
- */
-function rstr2any(input, encoding)
-{
- var divisor = encoding.length;
- var remainders = Array();
- var i, q, x, quotient;
-
- /* Convert to an array of 16-bit big-endian values, forming the dividend */
- var dividend = Array(Math.ceil(input.length / 2));
- for(i = 0; i < dividend.length; i++)
- {
- dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
- }
-
- /*
- * Repeatedly perform a long division. The binary array forms the dividend,
- * the length of the encoding is the divisor. Once computed, the quotient
- * forms the dividend for the next step. We stop when the dividend is zero.
- * All remainders are stored for later use.
- */
- while(dividend.length > 0)
- {
- quotient = Array();
- x = 0;
- for(i = 0; i < dividend.length; i++)
- {
- x = (x << 16) + dividend[i];
- q = Math.floor(x / divisor);
- x -= q * divisor;
- if(quotient.length > 0 || q > 0)
- quotient[quotient.length] = q;
- }
- remainders[remainders.length] = x;
- dividend = quotient;
- }
-
- /* Convert the remainders to the output string */
- var output = "";
- for(i = remainders.length - 1; i >= 0; i--)
- output += encoding.charAt(remainders[i]);
-
- /* Append leading zero equivalents */
- var full_length = Math.ceil(input.length * 8 /
- (Math.log(encoding.length) / Math.log(2)))
- for(i = output.length; i < full_length; i++)
- output = encoding[0] + output;
-
- return output;
-}
-
-/*
- * Encode a string as utf-8.
- * For efficiency, this assumes the input is valid utf-16.
- */
-function str2rstr_utf8(input)
-{
- var output = "";
- var i = -1;
- var x, y;
-
- while(++i < input.length)
- {
- /* Decode utf-16 surrogate pairs */
- x = input.charCodeAt(i);
- y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
- if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
- {
- x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
- i++;
- }
-
- /* Encode output as utf-8 */
- if(x <= 0x7F)
- output += String.fromCharCode(x);
- else if(x <= 0x7FF)
- output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
- 0x80 | ( x & 0x3F));
- else if(x <= 0xFFFF)
- output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
- 0x80 | ((x >>> 6 ) & 0x3F),
- 0x80 | ( x & 0x3F));
- else if(x <= 0x1FFFFF)
- output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
- 0x80 | ((x >>> 12) & 0x3F),
- 0x80 | ((x >>> 6 ) & 0x3F),
- 0x80 | ( x & 0x3F));
- }
- return output;
-}
-
-/*
- * Encode a string as utf-16
- */
-function str2rstr_utf16le(input)
-{
- var output = "";
- for(var i = 0; i < input.length; i++)
- output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
- (input.charCodeAt(i) >>> 8) & 0xFF);
- return output;
-}
-
-function str2rstr_utf16be(input)
-{
- var output = "";
- for(var i = 0; i < input.length; i++)
- output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
- input.charCodeAt(i) & 0xFF);
- return output;
-}
-
-/*
- * Convert a raw string to an array of big-endian words
- * Characters >255 have their high-byte silently ignored.
- */
-function rstr2binb(input)
-{
- var output = Array(input.length >> 2);
- for(var i = 0; i < output.length; i++)
- output[i] = 0;
- for(var i = 0; i < input.length * 8; i += 8)
- output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
- return output;
-}
-
-/*
- * Convert an array of big-endian words to a string
- */
-function binb2rstr(input)
-{
- var output = "";
- for(var i = 0; i < input.length * 32; i += 8)
- output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
- return output;
-}
-
-/*
- * Calculate the SHA-1 of an array of big-endian words, and a bit length
- */
-function binb_sha1(x, len)
-{
- /* append padding */
- x[len >> 5] |= 0x80 << (24 - len % 32);
- x[((len + 64 >> 9) << 4) + 15] = len;
-
- var w = Array(80);
- var a = 1732584193;
- var b = -271733879;
- var c = -1732584194;
- var d = 271733878;
- var e = -1009589776;
-
- for(var i = 0; i < x.length; i += 16)
- {
- var olda = a;
- var oldb = b;
- var oldc = c;
- var oldd = d;
- var olde = e;
-
- for(var j = 0; j < 80; j++)
- {
- if(j < 16) w[j] = x[i + j];
- else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
- var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
- safe_add(safe_add(e, w[j]), sha1_kt(j)));
- e = d;
- d = c;
- c = bit_rol(b, 30);
- b = a;
- a = t;
- }
-
- a = safe_add(a, olda);
- b = safe_add(b, oldb);
- c = safe_add(c, oldc);
- d = safe_add(d, oldd);
- e = safe_add(e, olde);
- }
- return Array(a, b, c, d, e);
-
-}
-
-/*
- * Perform the appropriate triplet combination function for the current
- * iteration
- */
-function sha1_ft(t, b, c, d)
-{
- if(t < 20) return (b & c) | ((~b) & d);
- if(t < 40) return b ^ c ^ d;
- if(t < 60) return (b & c) | (b & d) | (c & d);
- return b ^ c ^ d;
-}
-
-/*
- * Determine the appropriate additive constant for the current iteration
- */
-function sha1_kt(t)
-{
- return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
- (t < 60) ? -1894007588 : -899497514;
-}
-
-/*
- * Add integers, wrapping at 2^32. This uses 16-bit operations internally
- * to work around bugs in some JS interpreters.
- */
-function safe_add(x, y)
-{
- var lsw = (x & 0xFFFF) + (y & 0xFFFF);
- var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
- return (msw << 16) | (lsw & 0xFFFF);
-}
-
-/*
- * Bitwise rotate a 32-bit number to the left.
- */
-function bit_rol(num, cnt)
-{
- return (num << cnt) | (num >>> (32 - cnt));
-}
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+ return (num << cnt) | (num >>> (32 - cnt));
+}
/**
* OAuth JavaScript library
* Taken from http://oauth.googlecode.com/
@@ -4811,30 +4814,30 @@ OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"],
));
OAuth.correctTimestampFromSrc();
-/*jslint
+/*jslint
browser: true,
nomen: false,
debug: true,
forin: true,
undef: true,
white: false,
-onevar: false
+onevar: false
*/
var sc;
-
+
/*
* makes relative time out of "Sun Jul 08 19:01:12 +0000 2007" type string
* Borrowed from Mike Demers (slightly altered)
* https://twitter.pbwiki.com/RelativeTimeScripts
- *
+ *
* This requires date.js
* http://www.datejs.com/
* @param {string} time_value a string to convert into relative time
* @param {object} [labels] labels for text portions of time descriptions
* @param {boolean} [use_dateparse] Whether or not to use the Date.parse method to parse the time_value. Default is FALSE
*/
-sc.helpers.getRelativeTime = function(time_value, labels, use_dateparse) {
-
+sc.helpers.getRelativeTime = function(time_value, labels, use_dateparse) {
+
var default_labels = {
'now':'Just now',
'seconds':'sec ago',
@@ -4843,22 +4846,22 @@ sc.helpers.getRelativeTime = function(time_value, labels, use_dateparse) {
'hour':'hr ago',
'hours':'hr ago',
'day':'day ago',
- 'days':'days ago'
+ 'days':'days ago'
};
-
+
labels = sch.defaults(default_labels, labels);
-
+
var parsed_date;
-
+
if (use_dateparse === true) {
parsed_date = new Date.parse(time_value);
} else {
parsed_date = new Date(time_value);
}
-
+
var now = new Date();
var delta = parseInt( (now.getTime() - parsed_date.getTime()) / 1000, 10);
-
+
if (delta < 10) {
return labels.now;
} else if(delta < 60) {
@@ -4883,87 +4886,87 @@ sc.helpers.getRelativeTime = function(time_value, labels, use_dateparse) {
};
/**
- * @member sc.helpers
+ * @member sc.helpers
*/
sc.helpers.httpTimeToInt = function(entry_date, use_dateparse) {
return sc.helpers.dateToInt(entry_date, use_dateparse);
};
/**
- * this returns milliseconds, not seconds!
- * @member sc.helpers
+ * this returns milliseconds, not seconds!
+ * @member sc.helpers
*/
sc.helpers.dateToInt = function(entry_date, use_dateparse) {
var parsedDate = new Date();
-
+
if (use_dateparse === true) {
entry_date = new Date.parse(entry_date);
} else {
entry_date = new Date(entry_date);
}
-
+
parsedDate.setTime(entry_date);
return parsedDate.getTime();
};
/**
- * @member sc.helpers
+ * @member sc.helpers
*/
sc.helpers.getTimeAsInt = function() {
var now = new Date();
return now.getTime();
};
-/*jslint
+/*jslint
browser: true,
nomen: false,
debug: true,
forin: true,
undef: true,
white: false,
-onevar: false
+onevar: false
*/
var sc;
-
+
/**
* add an event listener to a target (element, window, etc). Uses target.addEventListener
- *
+ *
* @param {object} target
* @param {string} event_type
* @param {function} handler a method that will take the event as a param, and "this" refers to target
* @param {Object} [scope] the scope to execute the handler within (what "this" refers to)
* @param {boolean} [use_capture] defaults to false
* @returns {function} the handler that was passed -- or created, if we passed a scope. You can use this to remove the listener later on
- * @member sc.helpers
+ * @member sc.helpers
*/
sc.helpers.addListener = function(target, event_type, handler, scope, use_capture) {
-
+
if (scope) {
sch.warn('scope no longer supported! use a closure or reference "scope" in your event handler');
}
if (use_capture) {
sch.warn('use_capture no longer supported!');
}
-
+
sch.debug('listening for '+event_type);
sch.debug('on target nodeName:'+target.nodeName);
-
+
jQuery(target).bind(event_type, handler);
-
+
};
/**
* removes an event listener on a target (element, window, etc). uses Uses target.removeEventListener
- *
+ *
* Note that you must match all of the parameters to successfully remove the listener
- *
+ *
* @param {object} target
* @param {string} event_type
* @param {function} handler a method that will take the event as a param, and "this" refers to target
* @param {Object} scope the scope to execute the handler
* @param {boolean} use_capture defaults to false
- * @member sc.helpers
+ * @member sc.helpers
*/
sc.helpers.removeListener = function(target, event_type, handler, use_capture) {
@@ -4973,75 +4976,75 @@ sc.helpers.removeListener = function(target, event_type, handler, use_capture) {
if (use_capture) {
sch.warn('use_capture no longer supported!');
}
-
+
jQuery(target).unbind(event_type, handler);
};
/**
* @param {DOMElement} base_target The base target where the delegated listener will be set-up
* @param {string} selector The CSS Selector that will be used to match incoming events. Matching is done with jQuery
- * @param {string} event_type The event type
+ * @param {string} event_type The event type
* @param {Function} handler a method that will take the event as a param, and "this" refers to target
* @param {Object} [scope] the scope to execute the handler
* @param {Boolean} [use_capture] Describe this parameter
*/
sc.helpers.addDelegatedListener = function(base_target, selector, event_type, handler, scope) {
-
+
sch.warn('scope no longer supported! use a closure or reference "scope" in your event handler');
-
+
sch.debug('listening for '+event_type);
sch.debug('on target nodeName:'+target.nodeName);
sch.debug('for selector:'+selector);
-
+
jQuery(base_target).delegate(selector, event_type, handler);
-
+
};
/**
* @param {DOMElement} base_target The base target where the delegated listener will be set-up
* @param {string} selector The CSS Selector that will be used to match incoming events. Matching is done with jQuery
- * @param {string} event_type The event type
+ * @param {string} event_type The event type
* @param {Function} handler a method that will take the event as a param, and "this" refers to target
* @param {Object} [scope] the scope to execute the handler
*/
sc.helpers.removeDelegatedListener = function(base_target, selector, event_type, handler, scope) {
sch.warn('scope no longer supported! use a closure or reference "scope" in your event handler');
-
+
jQuery(base_target).delegate(selector, event_type, handler);
-
+
};
/**
* This triggers a custom event using document.createEvent('Events') and target.dispatchEvent()
- *
+ *
* @param {string} event_type
* @param {DOMElement} target the target for the event (element, window, etc)
* @param {object} data data to pass with event. it is always passed as the second parameter to the handler (after the event object)
* @param {boolean} bubble whether the event should bubble or not. defaults to true
- * @member sc.helpers
+ * @member sc.helpers
*/
sc.helpers.triggerCustomEvent = function(event_type, target, data, bubble) {
-
+
sch.debug('EVENT triggering '+event_type);
sch.debug('EVENT on target nodeName:'+target.nodeName);
-
+
if (bubble) {
sch.warn('bubble is no longer supported!');
}
-
+
if (data) {
sch.debug('EVENT data passed');
data = [data];
}
-
+
jQuery(target).trigger(event_type, data);
-
+
};
/**
* retrieves the data added to this event object
- * @param {DOMEvent} event_obj
+ * @param {DOMEvent} event_obj
* @deprecated
*/
sc.helpers.getEventData = function(event_obj) {
@@ -5050,40 +5053,40 @@ sc.helpers.getEventData = function(event_obj) {
};
/**
- * Alias for sc.helpers.addListener
- * @member sc.helpers
+ * Alias for sc.helpers.addListener
+ * @member sc.helpers
* @function
*/
sc.helpers.listen = sc.helpers.addListener;
/**
* Alias for sc.helpers.removeListener
- * @member sc.helpers
+ * @member sc.helpers
* @function
*/
sc.helpers.unlisten = sc.helpers.removeListener;
/**
* Alias for sc.helpers.addDelegatedListener
- * @member sc.helpers
+ * @member sc.helpers
* @function
*/
sc.helpers.delegate = sc.helpers.addDelegatedListener;
/**
* Alias for sc.helpers.removeDelegatedListener
- * @member sc.helpers
+ * @member sc.helpers
* @function
*/
sc.helpers.undelegate = sc.helpers.removeDelegatedListener;
/**
- * Alias for sc.helpers.triggerCustomEvent
- * @member sc.helpers
+ * Alias for sc.helpers.triggerCustomEvent
+ * @member sc.helpers
* @function
*/
-sc.helpers.trigger = sc.helpers.triggerCustomEvent;/*jslint
+sc.helpers.trigger = sc.helpers.triggerCustomEvent;/*jslint
bitwise: false,
browser: true,
nomen: false,
@@ -5095,10 +5098,10 @@ plusplus: false,
newcap: false,
undef: false,
white: false,
-onevar: false
+onevar: false
*/
var sc;
-
+
/*
We're more lax with JSLint here because this is almost all not our code
*/
@@ -5271,15 +5274,15 @@ sc.helpers.Base64 = {
* @function
**/
sc.helpers.crc32 = function (str) {
-
+
function Utf8Encode(string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
-
+
for (var n = 0; n < string.length; n++) {
-
+
var c = string.charCodeAt(n);
-
+
if (c < 128) {
utftext += String.fromCharCode(c);
}
@@ -5292,29 +5295,29 @@ sc.helpers.crc32 = function (str) {
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
-
+
}
-
+
return utftext;
}
-
+
str = Utf8Encode(str);
-
+
var table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D";
-
+
if (typeof(crc) == "undefined") { crc = 0; }
var x = 0;
var y = 0;
-
+
crc = crc ^ (-1);
for( var i = 0, iTop = str.length; i < iTop; i++ ) {
y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
x = "0x" + table.substr( y * 9, 8 );
crc = ( crc >>> 8 ) ^ x;
}
-
+
return crc ^ (-1);
-
+
};
@@ -5325,11 +5328,11 @@ sc.helpers.crc32 = function (str) {
* @function
**/
sc.helpers.MD5 = function (string) {
-
+
function RotateLeft(lValue, iShiftBits) {
return (lValue<