Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1121 from njam/page-state
Browse files Browse the repository at this point in the history
Allow page to handle URL params in _changeState()
  • Loading branch information
njam committed Apr 11, 2014
2 parents 511772f + d815902 commit cb39a04
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 53 deletions.
78 changes: 59 additions & 19 deletions client-vendor/after-body/jquery.tabs/jquery.tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,69 @@
* Author: CM
*/
(function($) {
$.fn.tabs = function() {

/**
* @param {jQuery} $buttonsContainer
* @constructor
*/
var Tabs = function($buttonsContainer) {
this.$buttonsContainer = $buttonsContainer;
this.$contentContainer = this.$buttonsContainer.next('.tabs-content');
if (!this.$contentContainer.length) {
throw new Error('No tabs contents found');
}

var self = this;
this.$buttonsContainer.on('click', 'a', function(event) {
self.showTab($(this).closest('.tabs > *'));
});

var $tabs = this.$buttonsContainer.find('> *');
var $activeTab = $tabs.filter('.active');
if (!$activeTab.length) {
$activeTab = $tabs.first();
}
this.showTab($activeTab);
};

Tabs.prototype = {
$buttonsContainer: null,
$contentContainer: null,

showTabByName: function(tab) {
var $tab = this.$buttonsContainer.children('[data-tab="' + tab + '"]:first');
if (!$tab.length) {
throw new Error('No tab with name `' + tab + '` found');
}
this.showTab($tab);
},

showTab: function($tab) {
var index = $tab.index();
$tab.addClass('active').siblings().removeClass('active');
var $tabContent = this.$contentContainer.find('> *').eq(index);
$tabContent.addClass('active').show().find(':focusable:first').focus();
$tabContent.siblings().removeClass('active').hide();
}
};

/**
* @param {String} [tab]
* @return {jQuery}
*/
$.fn.tabs = function(tab) {
return this.each(function() {
var $buttonsContainer = $(this);
var $contentContainer = $buttonsContainer.next('.tabs-content');
if (!$contentContainer.length) {
return;
var $self = $(this);
var tabs = $self.data('tabs');

if (!tabs) {
tabs = new Tabs($self);
$self.data('tabs', tabs);
}

$buttonsContainer.on('click', 'a', function(event) {
var $activeTab = $(this).closest('.tabs > *');
var index = $activeTab.index();
$activeTab.addClass('active').siblings().removeClass('active');
var $activeTabContent = $contentContainer.find('> *').eq(index);
$activeTabContent.addClass('active').show().find(':focusable:first').focus();
$activeTabContent.siblings().removeClass('active').hide();
});

var $tabs = $buttonsContainer.find('> *');
var $activeTab = $tabs.filter('.active');
if (!$activeTab.length) {
$activeTab = $tabs.first();
if (tab) {
tabs.showTabByName(tab);
}
$activeTab.find('> a').click();
});
};
})(jQuery);
66 changes: 66 additions & 0 deletions client-vendor/after-body/query-string/query-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*!
query-string
Parse and stringify URL query strings
https://github.com/sindresorhus/query-string
by Sindre Sorhus
MIT License
*/
(function () {
'use strict';
var queryString = {};

queryString.parse = function (str) {
if (typeof str !== 'string') {
return {};
}

str = str.trim().replace(/^\?/, '');

if (!str) {
return {};
}

return str.trim().split('&').reduce(function (ret, param) {
var parts = param.replace(/\+/g, ' ').split('=');
var key = parts[0];
var val = parts[1];

key = decodeURIComponent(key);
// missing `=` should be `null`:
// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
val = val === undefined ? null : decodeURIComponent(val);

if (!ret.hasOwnProperty(key)) {
ret[key] = val;
} else if (Array.isArray(ret[key])) {
ret[key].push(val);
} else {
ret[key] = [ret[key], val];
}

return ret;
}, {});
};

queryString.stringify = function (obj) {
return obj ? Object.keys(obj).map(function (key) {
var val = obj[key];

if (Array.isArray(val)) {
return val.map(function (val2) {
return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
}).join('&');
}

return encodeURIComponent(key) + '=' + encodeURIComponent(val);
}).join('&') : '';
};

if (typeof define === 'function' && define.amd) {
define([], queryString);
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = queryString;
} else {
window.queryString = queryString;
}
})();
14 changes: 7 additions & 7 deletions layout/default/Component/Example/default.tpl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<ul class="tabs menu-tabs">
<ul class="tabs menu-tabs example-navigation">
{block name="tabs"}
<li><a href="javascript:;">Components</a></li>
<li><a href="javascript:;">Menus</a></li>
<li><a href="javascript:;">Buttons</a></li>
<li><a href="javascript:;">Forms</a></li>
<li><a href="javascript:;">Variables</a></li>
<li><a href="javascript:;">Icons</a></li>
<li data-tab="components"><a href="{linkUrl page='CM_Page_Example' tab='components'}">Components</a></li>
<li data-tab="menus"><a href="{linkUrl page='CM_Page_Example' tab='menus'}">Menus</a></li>
<li data-tab="button"><a href="{linkUrl page='CM_Page_Example' tab='button'}">Buttons</a></li>
<li data-tab="forms"><a href="{linkUrl page='CM_Page_Example' tab='forms'}">Forms</a></li>
<li data-tab="variables"><a href="{linkUrl page='CM_Page_Example' tab='variables'}">Variables</a></li>
<li data-tab="icons"><a href="{linkUrl page='CM_Page_Example' tab='icons'}">Icons</a></li>
{/block}
</ul>

Expand Down
5 changes: 5 additions & 0 deletions layout/default/Page/Example/default.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{extends file=$render->getLayoutPath('Page/Abstract/default.tpl')}

{block name='content-main'}
{component name='CM_Component_Example' site=$render->getSite()}
{/block}
1 change: 1 addition & 0 deletions layout/default/Page/Example/title.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{translate 'Example'}
110 changes: 85 additions & 25 deletions library/CM/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ var CM_App = CM_Class_Abstract.extend({
}
var messages = _.toArray(arguments);
messages.unshift('[CM]');
if (console && console.log) {
var log = console.log;
if (window.console && window.console.log) {
var log = window.console.log;
if (typeof log == "object" && Function.prototype.bind) {
log = Function.prototype.bind.call(console.log, console);
}
Expand Down Expand Up @@ -589,8 +589,8 @@ var CM_App = CM_Class_Abstract.extend({
handler.focus.add(handler.getId());
handler._hasFocus = true;
}).blur(function() {
handler._hasFocus = false;
});
handler._hasFocus = false;
});
this.title.ready();
},

Expand Down Expand Up @@ -742,20 +742,20 @@ var CM_App = CM_Class_Abstract.extend({
}
}
}).fail(function(xhr, textStatus) {
if (xhr.status === 0) {
return; // Ignore interrupted ajax-request caused by leaving a page
}
if (xhr.status === 0) {
return; // Ignore interrupted ajax-request caused by leaving a page
}

var msg = cm.language.get('An unexpected connection problem occurred.');
if (cm.options.debug) {
msg = xhr.responseText || textStatus;
}
errorHandler(msg, null, false, callbacks.error);
}).always(function() {
if (callbacks.complete) {
callbacks.complete();
}
});
var msg = cm.language.get('An unexpected connection problem occurred.');
if (cm.options.debug) {
msg = xhr.responseText || textStatus;
}
errorHandler(msg, null, false, callbacks.error);
}).always(function() {
if (callbacks.complete) {
callbacks.complete();
}
});

return jqXHR;
},
Expand Down Expand Up @@ -1032,9 +1032,7 @@ var CM_App = CM_Class_Abstract.extend({
skipInitialFire = false;
return;
}
var location = window.history.location || document.location;
var fragment = location.pathname + location.search;
cm.getLayout().loadPage(location.pathname + location.search);
router._handleLocationChange(router._getFragment());
});

var hash = window.location.hash.substr(1);
Expand Down Expand Up @@ -1081,12 +1079,14 @@ var CM_App = CM_Class_Abstract.extend({
window.location.assign(url);
return;
}
if (replaceState) {
this.replaceState(fragment);
} else {
this.pushState(fragment);
if (fragment !== this._getFragment()) {
if (replaceState) {
this.replaceState(fragment);
} else {
this.pushState(fragment);
}
}
cm.getLayout().loadPage(fragment);
this._handleLocationChange(fragment);
},

/**
Expand All @@ -1101,6 +1101,66 @@ var CM_App = CM_Class_Abstract.extend({
*/
replaceState: function(url) {
window.history.replaceState(null, null, url);
},

/**
* @returns Location
*/
_getLocation: function() {
return window.history.location || document.location;
},

/**
* @returns string
*/
_getFragment: function() {
var location = this._getLocation();
return location.pathname + location.search;
},

/**
* @param {String} fragment
* @returns Location
*/
_getLocationByFragment: function(fragment) {
var location = document.createElement('a');
if (fragment) {
location.href = fragment;
}
return location;
},

/**
* @param {String} fragment
*/
_handleLocationChange: function(fragment) {
var paramsStateNext = null;
var pageCurrent = cm.getLayout().findPage();

if (pageCurrent && pageCurrent.hasStateParams()) {
var locationCurrent = this._getLocationByFragment(pageCurrent.getFragment());
var locationNext = this._getLocationByFragment(fragment);

if (locationCurrent.pathname === locationNext.pathname) {
var paramsCurrent = queryString.parse(locationCurrent.search);
var paramsNext = queryString.parse(locationNext.search);

var stateParamNames = pageCurrent.getStateParams();

var paramsNonStateCurrent = _.pick(paramsCurrent, _.difference(_.keys(paramsCurrent), stateParamNames));
var paramsNonStateNext = _.pick(paramsNext, _.difference(_.keys(paramsNext), stateParamNames));

if (_.isEqual(paramsNonStateCurrent, paramsNonStateNext)) {
paramsStateNext = _.pick(paramsNext, _.intersection(_.keys(paramsNext), stateParamNames));
}
}
}

if (paramsStateNext) {
cm.getLayout().getPage().routeToState(paramsStateNext, fragment);
} else {
cm.getLayout().loadPage(fragment);
}
}
}
});
7 changes: 7 additions & 0 deletions library/CM/Bootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ public function isDebug() {
return $this->_debug;
}

/**
* @param bool $state
*/
public function setDebug($state) {
$this->_debug = $state;
}

/**
* @return bool
*/
Expand Down
7 changes: 7 additions & 0 deletions library/CM/Component/Example.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ var CM_Component_Example = CM_Component_Abstract.extend({
this.message("Component ready, uname: " + this.uname);
},

/**
* @param {String} name
*/
showTab: function(name) {
this.$('.example-navigation.tabs').tabs(name);
},

reloadChinese: function() {
this.reload({foo: 'some chinese.. 百度一下,你就知道 繁體字!'});
},
Expand Down
20 changes: 19 additions & 1 deletion library/CM/Layout/Abstract.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ var CM_Layout_Abstract = CM_View_Abstract.extend({
/** @type jqXHR|Null */
_pageRequest: null,

/**
* @returns {CM_View_Abstract|null}
*/
findPage: function() {
return this.findChild('CM_Page_Abstract');
},

/**
* @returns {CM_View_Abstract}
*/
getPage: function() {
var page = this.findPage();
if (!page) {
cm.error.triggerThrow('Layout doesn\'t have a page');
}
return page;
},

/**
* @param {String} path
*/
Expand All @@ -21,7 +39,7 @@ var CM_Layout_Abstract = CM_View_Abstract.extend({

if (!this._$pagePlaceholder) {
this._$pagePlaceholder = $('<div class="router-placeholder" />');
var page = this.findChild('CM_Page_Abstract');
var page = this.getPage();
page.$el.replaceWith(this._$pagePlaceholder);
page.remove(true);
this._onPageTeardown();
Expand Down
Loading

0 comments on commit cb39a04

Please sign in to comment.