Merge branch 'cms-preview-history'

This commit is contained in:
Ingo Schommer 2011-07-08 15:37:28 +02:00
commit a30d31a16a
60 changed files with 6078 additions and 680 deletions

View File

@ -208,11 +208,13 @@ class CMSMenu extends Object implements IteratorAggregate, i18nEntityProvider
// checks on // checks on
if($menuItem->controller) { if($menuItem->controller) {
$controllerObj = singleton($menuItem->controller); $controllerObj = singleton($menuItem->controller);
if(Controller::has_curr()) {
// Necessary for canView() to have request data available, // Necessary for canView() to have request data available,
// e.g. to check permissions against LeftAndMain->currentPage() // e.g. to check permissions against LeftAndMain->currentPage()
$controllerObj->setRequest(Controller::curr()->getRequest()); $controllerObj->setRequest(Controller::curr()->getRequest());
if(!$controllerObj->canView($member)) continue; if(!$controllerObj->canView($member)) continue;
} }
}
$viewableMenuItems[$code] = $menuItem; $viewableMenuItems[$code] = $menuItem;
} }

View File

@ -69,6 +69,7 @@ class LeftAndMain extends Controller {
*/ */
static $allowed_actions = array( static $allowed_actions = array(
'index', 'index',
'save',
'savetreenode', 'savetreenode',
'getitem', 'getitem',
'getsubtree', 'getsubtree',
@ -241,6 +242,9 @@ class LeftAndMain extends Controller {
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.html4.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.adapter.jquery.js');
Requirements::javascript(THIRDPARTY_DIR . '/behaviour/behaviour.js'); Requirements::javascript(THIRDPARTY_DIR . '/behaviour/behaviour.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-cookie/jquery.cookie.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery-cookie/jquery.cookie.js');
@ -254,8 +258,12 @@ class LeftAndMain extends Controller {
Requirements::css(THIRDPARTY_DIR . '/jstree/themes/apple/style.css'); Requirements::css(THIRDPARTY_DIR . '/jstree/themes/apple/style.css');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Panel.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Ping.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Content.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.EditForm.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.EditForm.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Menu.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.AddForm.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.AddForm.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Preview.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Preview.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.BatchActions.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.BatchActions.js');
@ -296,6 +304,9 @@ class LeftAndMain extends Controller {
SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js', SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js', SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js', SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.adapter.jquery.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.html4.js',
THIRDPARTY_DIR . '/jstree/jquery.jstree.js', THIRDPARTY_DIR . '/jstree/jquery.jstree.js',
SAPPHIRE_ADMIN_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js', SAPPHIRE_ADMIN_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js',
SAPPHIRE_DIR . '/javascript/TreeDropdownField.js', SAPPHIRE_DIR . '/javascript/TreeDropdownField.js',
@ -310,8 +321,12 @@ class LeftAndMain extends Controller {
'leftandmain.js', 'leftandmain.js',
array( array(
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.js', SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Panel.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js', SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Ping.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Content.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.EditForm.js', SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.EditForm.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Menu.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.AddForm.js', SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.AddForm.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Preview.js', SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Preview.js',
SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.BatchActions.js', SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.BatchActions.js',
@ -326,6 +341,20 @@ class LeftAndMain extends Controller {
SSViewer::set_theme(null); SSViewer::set_theme(null);
} }
function handleRequest($request) {
$title = $this->Title();
$response = parent::handleRequest($request);
$response->addHeader('X-Controller', $this->class);
$response->addHeader('X-Title', $title);
return $response;
}
function index($request) {
return ($this->isAjax()) ? $this->show($request) : $this->getViewer('index')->process($this);
}
/** /**
* If this is set to true, the "switchView" context in the * If this is set to true, the "switchView" context in the
@ -375,11 +404,14 @@ class LeftAndMain extends Controller {
if($request->param('ID')) $this->setCurrentPageID($request->param('ID')); if($request->param('ID')) $this->setCurrentPageID($request->param('ID'));
if($this->isAjax()) { if($this->isAjax()) {
SSViewer::setOption('rewriteHashlinks', false); if($request->getVar('cms-view-form')) {
$form = $this->getEditForm($request->param('ID')); $form = $this->getEditForm();
$content = $form->formHtmlContent(); $content = $form->forTemplate();
} else { } else {
// Rendering is handled by template, which will call EditForm() eventually // Rendering is handled by template, which will call EditForm() eventually
$content = $this->renderWith($this->getTemplatesWithSuffix('_Content'));
}
} else {
$content = $this->renderWith($this->getViewer('show')); $content = $this->renderWith($this->getViewer('show'));
} }
@ -534,7 +566,7 @@ class LeftAndMain extends Controller {
$titleEval = ' $titleEval = '
"<li id=\"record-$child->ID\" data-id=\"$child->ID\" class=\"" . $child->CMSTreeClasses($extraArg) . "\">" . "<li id=\"record-$child->ID\" data-id=\"$child->ID\" class=\"" . $child->CMSTreeClasses($extraArg) . "\">" .
"<ins class=\"jstree-icon\">&nbsp;</ins>" . "<ins class=\"jstree-icon\">&nbsp;</ins>" .
"<a href=\"" . Controller::join_links(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" title=\"' "<a href=\"" . Controller::join_links($extraArg->Link("show"), $child->ID) . "\" title=\"'
. _t('LeftAndMain.PAGETYPE','Page type: ') . _t('LeftAndMain.PAGETYPE','Page type: ')
. '".$child->class."\" ><ins class=\"jstree-icon\">&nbsp;</ins>" . ($child->TreeTitle) . . '".$child->class."\" ><ins class=\"jstree-icon\">&nbsp;</ins>" . ($child->TreeTitle) .
"</a>" "</a>"
@ -628,7 +660,7 @@ class LeftAndMain extends Controller {
// write process might've changed the record, so we reload before returning // write process might've changed the record, so we reload before returning
$form = $this->getEditForm($record->ID); $form = $this->getEditForm($record->ID);
return $form->formHtmlContent(); return $form->forTemplate();
} }
public function delete($data, $form) { public function delete($data, $form) {
@ -640,7 +672,7 @@ class LeftAndMain extends Controller {
$record->delete(); $record->delete();
if($this->isAjax()) { if($this->isAjax()) {
return $this->EmptyForm()->formHtmlContent(); return $this->EmptyForm()->forTemplate();
} else { } else {
$this->redirectBack(); $this->redirectBack();
} }
@ -946,7 +978,7 @@ class LeftAndMain extends Controller {
return $record->ID; return $record->ID;
} else if($this->isAjax()) { } else if($this->isAjax()) {
$form = $this->getEditForm($record->ID); $form = $this->getEditForm($record->ID);
return $form->formHtmlContent(); return $form->forTemplate();
} else { } else {
return $this->redirect(Controller::join_links($this->Link('show'), $record->ID)); return $this->redirect(Controller::join_links($this->Link('show'), $record->ID));
} }
@ -1070,12 +1102,17 @@ class LeftAndMain extends Controller {
} }
/** /**
* Get the staus of a certain page and version. * URL to a previewable record which is shown through this controller.
* The controller might not have any previewable content, in which case
* this method returns FALSE.
* *
* This function is used for concurrent editing, and providing alerts * @return String|boolean
* when multiple users are editing a single page. It echoes a json
* encoded string to the UA.
*/ */
public function PreviewLink() {
$record = $this->getRecord($this->currentPageID());
$baseLink = ($record && $record instanceof Page) ? $record->Link('?stage=Stage') : Director::absoluteBaseURL();
return Controller::join_links($baseLink, '?cms-preview-disabled=1');
}
/** /**
* Return the version number of this application. * Return the version number of this application.
@ -1143,6 +1180,13 @@ class LeftAndMain extends Controller {
return self::$application_name; return self::$application_name;
} }
/**
* @return String
*/
function Title() {
return sprintf('%s | %s', $this->getApplicationName(), $this->SectionTitle());
}
/** /**
* Return the title of the current section, as shown on the main menu * Return the title of the current section, as shown on the main menu
*/ */
@ -1162,6 +1206,21 @@ class LeftAndMain extends Controller {
return MCE_ROOT; return MCE_ROOT;
} }
/**
* Same as {@link ViewableData->CSSClasses()}, but with a changed name
* to avoid problems when using {@link ViewableData->customise()}
* (which always returns "ArrayData" from the $original object).
*
* @return String
*/
function BaseCSSClasses() {
return $this->CSSClasses();
}
function IsPreviewExpanded() {
return ($this->request->getVar('cms-preview-expanded'));
}
/** /**
* Register the given javascript file as required in the CMS. * Register the given javascript file as required in the CMS.
* Filenames should be relative to the base, eg, SAPPHIRE_DIR . '/javascript/loader.js' * Filenames should be relative to the base, eg, SAPPHIRE_DIR . '/javascript/loader.js'

View File

@ -664,7 +664,7 @@ class ModelAdmin_CollectionController extends Controller {
$msg = _t('ModelAdmin.NORESULTS',"Your search didn't return any matching items"); $msg = _t('ModelAdmin.NORESULTS',"Your search didn't return any matching items");
} }
return new SS_HTTPResponse( return new SS_HTTPResponse(
$resultsForm->formHtmlContent(), $resultsForm->forTemplate(),
200, 200,
$msg $msg
); );
@ -794,7 +794,7 @@ class ModelAdmin_CollectionController extends Controller {
*/ */
function add($request) { function add($request) {
return new SS_HTTPResponse( return new SS_HTTPResponse(
$this->AddForm()->formHtmlContent(), $this->AddForm()->forTemplate(),
200, 200,
sprintf( sprintf(
_t('ModelAdmin.ADDFORM', "Fill out this form to add a %s to the database."), _t('ModelAdmin.ADDFORM', "Fill out this form to add a %s to the database."),
@ -845,6 +845,7 @@ class ModelAdmin_CollectionController extends Controller {
$form = new Form($this, "AddForm", $fields, $actions, $validator); $form = new Form($this, "AddForm", $fields, $actions, $validator);
$form->loadDataFrom($newRecord); $form->loadDataFrom($newRecord);
$form->addExtraClass('cms-edit-form');
return $form; return $form;
} }
@ -862,7 +863,7 @@ class ModelAdmin_CollectionController extends Controller {
$class = $this->parentController->getRecordControllerClass($this->getModelClass()); $class = $this->parentController->getRecordControllerClass($this->getModelClass());
$recordController = new $class($this, $request, $model->ID); $recordController = new $class($this, $request, $model->ID);
return new SS_HTTPResponse( return new SS_HTTPResponse(
$recordController->EditForm()->formHtmlContent(), $recordController->EditForm()->forTemplate(),
200, 200,
sprintf( sprintf(
_t('ModelAdmin.LOADEDFOREDITING', "Loaded '%s' for editing."), _t('ModelAdmin.LOADEDFOREDITING', "Loaded '%s' for editing."),
@ -912,7 +913,7 @@ class ModelAdmin_RecordController extends Controller {
function edit($request) { function edit($request) {
if ($this->currentRecord) { if ($this->currentRecord) {
if($this->isAjax()) { if($this->isAjax()) {
$this->response->setBody($this->EditForm()->formHtmlContent()); $this->response->setBody($this->EditForm()->forTemplate());
$this->response->setStatusCode( $this->response->setStatusCode(
200, 200,
sprintf( sprintf(
@ -924,10 +925,10 @@ class ModelAdmin_RecordController extends Controller {
} else { } else {
// This is really quite ugly; to fix will require a change in the way that customise() works. :-( // This is really quite ugly; to fix will require a change in the way that customise() works. :-(
return $this->parentController->parentController->customise(array( return $this->parentController->parentController->customise(array(
'Right' => $this->parentController->parentController->customise(array( 'Content' => $this->parentController->parentController->customise(array(
'EditForm' => $this->EditForm() 'EditForm' => $this->EditForm()
))->renderWith(array("{$this->class}_right",'LeftAndMain_right')) ))->renderWith(array("{$this->class}_Content",'ModelAdmin_Content', 'LeftAndMain_Content'))
))->renderWith(array('ModelAdmin','LeftAndMain')); ))->renderWith(array('ModelAdmin', 'LeftAndMain'));
} }
} else { } else {
return _t('ModelAdmin.ITEMNOTFOUND', "I can't find that item"); return _t('ModelAdmin.ITEMNOTFOUND', "I can't find that item");
@ -963,6 +964,7 @@ class ModelAdmin_RecordController extends Controller {
$form = new Form($this, "EditForm", $fields, $actions, $validator); $form = new Form($this, "EditForm", $fields, $actions, $validator);
$form->loadDataFrom($this->currentRecord); $form->loadDataFrom($this->currentRecord);
$form->addExtraClass('cms-edit-form');
return $form; return $form;
} }
@ -1017,7 +1019,7 @@ class ModelAdmin_RecordController extends Controller {
function view($request) { function view($request) {
if($this->currentRecord) { if($this->currentRecord) {
$form = $this->ViewForm(); $form = $this->ViewForm();
return $form->formHtmlContent(); return $form->forTemplate();
} else { } else {
return _t('ModelAdmin.ITEMNOTFOUND'); return _t('ModelAdmin.ITEMNOTFOUND');
} }

View File

@ -17,18 +17,21 @@ a img { border: none; }
@charset "UTF-8"; @charset "UTF-8";
html, body { width: 100%; height: 100%; padding: 0; margin: 0; overflow: hidden; } html, body { width: 100%; height: 100%; padding: 0; margin: 0; overflow: hidden; }
.cms-preview { width: 1px; overflow: hidden; } .cms-preview { width: 1px; }
.cms-preview .cms-preview-toggle { width: 10px; } .cms-preview .cms-preview-toggle { width: 10px; }
.cms-preview iframe { width: 100%; height: 100%; } .cms-preview iframe { width: 100%; height: 100%; }
.cms-container { height: 100%; } .cms-container { height: 100%; }
.cms-menu { width: 250px; overflow: auto; } .cms-menu { width: 250px; overflow: auto; }
.cms-menu .cms-panel-content { width: 250px; }
.cms-menu.collapsed { width: 40px; }
.cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-form { display: -moz-inline-box; -moz-box-orient: vertical; display: inline-block; vertical-align: middle; *vertical-align: auto; } .cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-form, .cms-edit-form { display: -moz-inline-box; -moz-box-orient: vertical; display: inline-block; vertical-align: middle; *vertical-align: auto; }
.cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-form { *display: inline; } .cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-form, .cms-edit-form { *display: inline; }
.cms-content-tools { width: 230px; padding: 10px; overflow: auto; } .cms-content-tools { width: 230px; overflow: auto; }
.cms-content-tools .cms-panel-header, .cms-content-tools .cms-panel-content { padding: 10px; }
.cms-content-form { overflow: auto; } .cms-content-form { overflow: auto; }
@ -38,6 +41,8 @@ html, body { width: 100%; height: 100%; padding: 0; margin: 0; overflow: hidden;
.cms-content-actions { padding: 10px; } .cms-content-actions { padding: 10px; }
.cms-header { padding: 7px 0 7px 7px; }
.cms-logo { height: 30px; overflow: hidden; vertical-align: middle; } .cms-logo { height: 30px; overflow: hidden; vertical-align: middle; }
.cms-login-status { height: 30px; overflow: hidden; vertical-align: middle; } .cms-login-status { height: 30px; overflow: hidden; vertical-align: middle; }

View File

@ -1,292 +1,638 @@
/** This file is the central collection of included modules, links to custom SCSS files, and any global SCSS variable definitions. DO NOT ADD stylesheet rules to this file directly! Note: By prefixing files with an underscore, they won't create individual CSS files. */ /** This file is the central collection of included modules, links to custom SCSS files, and any global SCSS variable definitions. DO NOT ADD stylesheet rules to this file directly! Note: By prefixing files with an underscore, they won't create individual CSS files. */
/** ----------------------------- Core Compass Libraries ------------------------------ */ /** ----------------------------- Core Compass Libraries ------------------------------ */
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; } /* line 17, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }
body { line-height: 1; color: black; background: white; } /* line 20, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
body { line-height: 1; }
/* line 22, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
ol, ul { list-style: none; } ol, ul { list-style: none; }
table { border-collapse: separate; border-spacing: 0; vertical-align: middle; } /* line 24, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
table { border-collapse: collapse; border-spacing: 0; }
/* line 26, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; }
q, blockquote { quotes: "" ""; } /* line 28, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after { content: ""; } q, blockquote { quotes: none; }
/* line 101, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; }
/* line 30, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
a img { border: none; } a img { border: none; }
@charset "UTF-8"; /* line 115, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
/** ----------------------------- Theme ------------------------------ */ /** ----------------------------- Theme ------------------------------ */
/** This file contains the default theme definitions for the admin interface. @package sapphire @subpackage admin */ /** This file contains the default theme definitions for the admin interface. Please put mostly SCSS variable definitions in here, and leave the actual styling to _style.scss and auxilliary files. */
/** ----------------------------------------------- Colours ------------------------------------------------ */ /** ----------------------------------------------- Colours ------------------------------------------------ */
/** ----------------------------------------------- Typography ------------------------------------------------ */ /** ----------------------------------------------- Typography ------------------------------------------------ */
/** ----------------------------------------------- Application Logo (CMS Logo) ------------------------------------------------ */ /** ----------------------------------------------- Application Logo (CMS Logo) ------------------------------------------------ */
/** ----------------------------- CMS Components ------------------------------ */ /** ----------------------------- CMS Components ------------------------------ */
/** This file defines the jstree base styling (see http://jstree.com), as well as any customizations (see bottom of file). The styles are usually added through jstree.js on DOM load, but we need it earlier in order to correctly display the uninitialized tree. */ /** This file defines the jstree base styling (see http://jstree.com), as well as any customizations (see bottom of file). The styles are usually added through jstree.js on DOM load, but we need it earlier in order to correctly display the uninitialized tree. */
/* line 10, ../scss/_tree.scss */
.jstree ul { display: block; margin: 0 0 0 0; padding: 0 0 0 0; list-style-type: none; } .jstree ul { display: block; margin: 0 0 0 0; padding: 0 0 0 0; list-style-type: none; }
/* line 16, ../scss/_tree.scss */
.jstree li { display: block; margin: 0 0 0 0; padding: 0 0 0 0; list-style-type: none; display: block; min-height: 18px; line-height: 18px; white-space: nowrap; margin-left: 18px; min-width: 18px; } .jstree li { display: block; margin: 0 0 0 0; padding: 0 0 0 0; list-style-type: none; display: block; min-height: 18px; line-height: 18px; white-space: nowrap; margin-left: 18px; min-width: 18px; }
.jstree ins { display: inline-block; text-decoration: none; width: 18px; height: 18px; margin: 0 0 0 0; padding: 0; } /* line 28, ../scss/_tree.scss */
.jstree ins { display: inline-block; text-decoration: none; width: 18px; height: 18px; margin: 0 0 0 0; padding: 0; float: left; }
/* line 37, ../scss/_tree.scss */
.jstree a { display: inline-block; line-height: 16px; height: 16px; color: black; white-space: nowrap; text-decoration: none; padding: 1px 2px; margin: 0; } .jstree a { display: inline-block; line-height: 16px; height: 16px; color: black; white-space: nowrap; text-decoration: none; padding: 1px 2px; margin: 0; }
/* line 46, ../scss/_tree.scss */
.jstree a:focus { outline: none; } .jstree a:focus { outline: none; }
/* line 50, ../scss/_tree.scss */
.jstree a > ins { height: 16px; width: 16px; } .jstree a > ins { height: 16px; width: 16px; }
/* line 54, ../scss/_tree.scss */
.jstree a > .jstree-icon { margin-right: 3px; } .jstree a > .jstree-icon { margin-right: 3px; }
/* line 62, ../scss/_tree.scss */
.jstree li.jstree-open > ul { display: block; } .jstree li.jstree-open > ul { display: block; }
/* line 65, ../scss/_tree.scss */
.jstree li.jstree-closed > ul { display: none; } .jstree li.jstree-closed > ul { display: none; }
/* line 70, ../scss/_tree.scss */
.jstree li.disabled a { color: #aaaaaa; } .jstree li.disabled a { color: #aaaaaa; }
/* line 77, ../scss/_tree.scss */
.jstree-rtl a > .jstree-icon { margin-left: 3px; margin-right: 0; } .jstree-rtl a > .jstree-icon { margin-left: 3px; margin-right: 0; }
/* line 81, ../scss/_tree.scss */
.jstree-rtl li { margin-left: 0; margin-right: 18px; } .jstree-rtl li { margin-left: 0; margin-right: 18px; }
/* line 88, ../scss/_tree.scss */
.jstree-rtl > ul > li { margin-right: 0px; } .jstree-rtl > ul > li { margin-right: 0px; }
/* line 92, ../scss/_tree.scss */
.jstree > ul > li { margin-left: 0px; } .jstree > ul > li { margin-left: 0px; }
/* line 96, ../scss/_tree.scss */
#vakata-dragged { display: block; margin: 0 0 0 0; padding: 4px 4px 4px 24px; position: absolute; top: -2000px; line-height: 16px; z-index: 10000; } #vakata-dragged { display: block; margin: 0 0 0 0; padding: 4px 4px 4px 24px; position: absolute; top: -2000px; line-height: 16px; z-index: 10000; }
/* line 105, ../scss/_tree.scss */
#vakata-contextmenu { display: block; visibility: hidden; left: 0; top: -200px; position: absolute; margin: 0; padding: 0; min-width: 180px; background: #ebebeb; border: 1px solid silver; z-index: 10000; *width: 180px; } #vakata-contextmenu { display: block; visibility: hidden; left: 0; top: -200px; position: absolute; margin: 0; padding: 0; min-width: 180px; background: #ebebeb; border: 1px solid silver; z-index: 10000; *width: 180px; }
/* line 118, ../scss/_tree.scss */
#vakata-contextmenu ul { min-width: 180px; *width: 180px; } #vakata-contextmenu ul { min-width: 180px; *width: 180px; }
/* line 121, ../scss/_tree.scss */
#vakata-contextmenu ul, #vakata-contextmenu li { margin: 0; padding: 0; list-style-type: none; display: block; } #vakata-contextmenu ul, #vakata-contextmenu li { margin: 0; padding: 0; list-style-type: none; display: block; }
/* line 127, ../scss/_tree.scss */
#vakata-contextmenu li { line-height: 20px; min-height: 20px; position: relative; padding: 0px; } #vakata-contextmenu li { line-height: 20px; min-height: 20px; position: relative; padding: 0px; }
/* line 133, ../scss/_tree.scss */
#vakata-contextmenu li a { padding: 1px 6px; line-height: 17px; display: block; text-decoration: none; margin: 1px 1px 0 1px; } #vakata-contextmenu li a { padding: 1px 6px; line-height: 17px; display: block; text-decoration: none; margin: 1px 1px 0 1px; }
/* line 140, ../scss/_tree.scss */
#vakata-contextmenu li ins { float: left; width: 16px; height: 16px; text-decoration: none; margin-right: 2px; } #vakata-contextmenu li ins { float: left; width: 16px; height: 16px; text-decoration: none; margin-right: 2px; }
/* line 147, ../scss/_tree.scss */
#vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background: gray; color: white; } #vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background: gray; color: white; }
/* line 151, ../scss/_tree.scss */
#vakata-contextmenu li ul { display: none; position: absolute; top: -2px; left: 100%; background: #ebebeb; border: 1px solid gray; } #vakata-contextmenu li ul { display: none; position: absolute; top: -2px; left: 100%; background: #ebebeb; border: 1px solid gray; }
/* line 159, ../scss/_tree.scss */
#vakata-contextmenu .right { right: 100%; left: auto; } #vakata-contextmenu .right { right: 100%; left: auto; }
/* line 163, ../scss/_tree.scss */
#vakata-contextmenu .bottom { bottom: -1px; top: auto; } #vakata-contextmenu .bottom { bottom: -1px; top: auto; }
/* line 167, ../scss/_tree.scss */
#vakata-contextmenu li.vakata-separator { min-height: 0; height: 1px; line-height: 1px; font-size: 1px; overflow: hidden; margin: 0 2px; background: silver; /* border-top:1px solid #fefefe; */ padding: 0; } #vakata-contextmenu li.vakata-separator { min-height: 0; height: 1px; line-height: 1px; font-size: 1px; overflow: hidden; margin: 0 2px; background: silver; /* border-top:1px solid #fefefe; */ padding: 0; }
/* line 177, ../scss/_tree.scss */
.jstree ul, .jstree li { display: block; margin: 0 0 0 0; padding: 0 0 0 0; list-style-type: none; } .jstree ul, .jstree li { display: block; margin: 0 0 0 0; padding: 0 0 0 0; list-style-type: none; }
/* line 183, ../scss/_tree.scss */
.jstree li { display: block; min-height: 18px; line-height: 18px; white-space: nowrap; margin-left: 18px; min-width: 18px; } .jstree li { display: block; min-height: 18px; line-height: 18px; white-space: nowrap; margin-left: 18px; min-width: 18px; }
/* line 191, ../scss/_tree.scss */
.jstree-rtl li { margin-left: 0; margin-right: 18px; } .jstree-rtl li { margin-left: 0; margin-right: 18px; }
/* line 195, ../scss/_tree.scss */
.jstree > ul > li { margin-left: 0px; } .jstree > ul > li { margin-left: 0px; }
/* line 198, ../scss/_tree.scss */
.jstree-rtl > ul > li { margin-right: 0px; } .jstree-rtl > ul > li { margin-right: 0px; }
/* line 201, ../scss/_tree.scss */
.jstree ins { display: inline-block; text-decoration: none; width: 18px; height: 18px; margin: 0 0 0 0; padding: 0; } .jstree ins { display: inline-block; text-decoration: none; width: 18px; height: 18px; margin: 0 0 0 0; padding: 0; }
/* line 209, ../scss/_tree.scss */
.jstree a { display: inline-block; line-height: 16px; height: 16px; color: black; white-space: nowrap; text-decoration: none; padding: 1px 2px; margin: 0; } .jstree a { display: inline-block; line-height: 16px; height: 16px; color: black; white-space: nowrap; text-decoration: none; padding: 1px 2px; margin: 0; }
/* line 219, ../scss/_tree.scss */
.jstree a:focus { outline: none; } .jstree a:focus { outline: none; }
/* line 222, ../scss/_tree.scss */
.jstree a > ins { height: 16px; width: 16px; } .jstree a > ins { height: 16px; width: 16px; }
/* line 226, ../scss/_tree.scss */
.jstree a > .jstree-icon { margin-right: 3px; } .jstree a > .jstree-icon { margin-right: 3px; }
/* line 229, ../scss/_tree.scss */
.jstree-rtl a > .jstree-icon { margin-left: 3px; margin-right: 0; } .jstree-rtl a > .jstree-icon { margin-left: 3px; margin-right: 0; }
/* line 233, ../scss/_tree.scss */
li.jstree-open > ul { display: block; } li.jstree-open > ul { display: block; }
/* line 236, ../scss/_tree.scss */
li.jstree-closed > ul { display: none; } li.jstree-closed > ul { display: none; }
/* line 239, ../scss/_tree.scss */
#vakata-dragged ins { display: block; text-decoration: none; width: 16px; height: 16px; margin: 0 0 0 0; padding: 0; position: absolute; top: 4px; left: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-border-radius: 4px; } #vakata-dragged ins { display: block; text-decoration: none; width: 16px; height: 16px; margin: 0 0 0 0; padding: 0; position: absolute; top: 4px; left: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-border-radius: 4px; }
/* line 253, ../scss/_tree.scss */
#vakata-dragged .jstree-ok { background: green; } #vakata-dragged .jstree-ok { background: green; }
/* line 256, ../scss/_tree.scss */
#vakata-dragged .jstree-invalid { background: red; } #vakata-dragged .jstree-invalid { background: red; }
/* line 259, ../scss/_tree.scss */
#jstree-marker { padding: 0; margin: 0; font-size: 12px; overflow: hidden; height: 12px; width: 8px; position: absolute; top: -30px; z-index: 10001; background-repeat: no-repeat; display: none; background-color: transparent; text-shadow: 1px 1px 1px white; color: black; line-height: 10px; } #jstree-marker { padding: 0; margin: 0; font-size: 12px; overflow: hidden; height: 12px; width: 8px; position: absolute; top: -30px; z-index: 10001; background-repeat: no-repeat; display: none; background-color: transparent; text-shadow: 1px 1px 1px white; color: black; line-height: 10px; }
/* line 276, ../scss/_tree.scss */
#jstree-marker-line { padding: 0; margin: 0; line-height: 0%; font-size: 1px; overflow: hidden; height: 1px; width: 100px; position: absolute; top: -30px; z-index: 10000; background-repeat: no-repeat; display: none; background-color: #456c43; cursor: pointer; border: 1px solid #eeeeee; border-left: 0; -moz-box-shadow: 0px 0px 2px #666; -webkit-box-shadow: 0px 0px 2px #666; box-shadow: 0px 0px 2px #666; -moz-border-radius: 1px; border-radius: 1px; -webkit-border-radius: 1px; } #jstree-marker-line { padding: 0; margin: 0; line-height: 0%; font-size: 1px; overflow: hidden; height: 1px; width: 100px; position: absolute; top: -30px; z-index: 10000; background-repeat: no-repeat; display: none; background-color: #456c43; cursor: pointer; border: 1px solid #eeeeee; border-left: 0; -moz-box-shadow: 0px 0px 2px #666; -webkit-box-shadow: 0px 0px 2px #666; box-shadow: 0px 0px 2px #666; -moz-border-radius: 1px; border-radius: 1px; -webkit-border-radius: 1px; }
/* line 300, ../scss/_tree.scss */
.jstree .jstree-real-checkbox { display: none; } .jstree .jstree-real-checkbox { display: none; }
/* line 303, ../scss/_tree.scss */
.jstree-themeroller .ui-icon { overflow: visible; } .jstree-themeroller .ui-icon { overflow: visible; }
/* line 306, ../scss/_tree.scss */
.jstree-themeroller a { padding: 0 2px; } .jstree-themeroller a { padding: 0 2px; }
/* line 309, ../scss/_tree.scss */
.jstree-themeroller .jstree-no-icon { display: none; } .jstree-themeroller .jstree-no-icon { display: none; }
/* line 312, ../scss/_tree.scss */
.jstree .jstree-wholerow-real { position: relative; z-index: 1; } .jstree .jstree-wholerow-real { position: relative; z-index: 1; }
/* line 316, ../scss/_tree.scss */
.jstree .jstree-wholerow-real li { cursor: pointer; } .jstree .jstree-wholerow-real li { cursor: pointer; }
/* line 319, ../scss/_tree.scss */
.jstree .jstree-wholerow-real a { border-left-color: transparent !important; border-right-color: transparent !important; } .jstree .jstree-wholerow-real a { border-left-color: transparent !important; border-right-color: transparent !important; }
/* line 323, ../scss/_tree.scss */
.jstree .jstree-wholerow { position: relative; z-index: 0; height: 0; } .jstree .jstree-wholerow { position: relative; z-index: 0; height: 0; }
/* line 328, ../scss/_tree.scss */
.jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { width: 100%; } .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { width: 100%; }
/* line 331, ../scss/_tree.scss */
.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li, .jstree .jstree-wholerow a { margin: 0 !important; padding: 0 !important; } .jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li, .jstree .jstree-wholerow a { margin: 0 !important; padding: 0 !important; }
/* line 335, ../scss/_tree.scss */
.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { background: transparent !important; } .jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { background: transparent !important; }
/* line 338, ../scss/_tree.scss */
.jstree .jstree-wholerow ins, .jstree .jstree-wholerow span, .jstree .jstree-wholerow input { display: none !important; } .jstree .jstree-wholerow ins, .jstree .jstree-wholerow span, .jstree .jstree-wholerow input { display: none !important; }
/* line 341, ../scss/_tree.scss */
.jstree .jstree-wholerow a, .jstree .jstree-wholerow a:hover { text-indent: -9999px !important; width: 100%; padding: 0 !important; border-right-width: 0px !important; border-left-width: 0px !important; } .jstree .jstree-wholerow a, .jstree .jstree-wholerow a:hover { text-indent: -9999px !important; width: 100%; padding: 0 !important; border-right-width: 0px !important; border-left-width: 0px !important; }
/* line 348, ../scss/_tree.scss */
.jstree .jstree-wholerow-span { position: absolute; left: 0; margin: 0px; padding: 0; height: 18px; border-width: 0; padding: 0; z-index: 0; } .jstree .jstree-wholerow-span { position: absolute; left: 0; margin: 0px; padding: 0; height: 18px; border-width: 0; padding: 0; z-index: 0; }
/* line 361, ../scss/_tree.scss */
.cms .jstree-apple.jstree-focused { background: none; } .cms .jstree-apple.jstree-focused { background: none; }
/* line 364, ../scss/_tree.scss */
.cms .jstree-apple > ul { background: none; } .cms .jstree-apple > ul { background: none; }
/* line 369, ../scss/_tree.scss */
.jstree li { line-height: 25px; }
/* line 373, ../scss/_tree.scss */
.cms-tree.jstree-apple { /* comment speech bubble - ccs3 only - source: http://nicolasgallagher.com/pure-css-speech-bubbles/demo/ */ }
/* line 376, ../scss/_tree.scss */
.cms-tree.jstree-apple li.Root strong { font-weight: bold; padding-left: 1px; }
/* line 381, ../scss/_tree.scss */
.cms-tree.jstree-apple li.Root > a .jstree-icon { background-position: -56px -36px; }
/* line 386, ../scss/_tree.scss */
.cms-tree.jstree-apple a, .cms-tree.jstree-apple a:link { color: #1556b2; padding: 3px 6px 3px 3px; border: none; display: inline-block; margin-right: 5px; }
/* line 394, ../scss/_tree.scss */
.cms-tree.jstree-apple a span.status:after, .cms-tree.jstree-apple a:link span.status:after { clear: both; text-transform: uppercase; display: inline-block; padding: 0px 3px; font-size: 0.75em; line-height: 1em; margin-left: 3px; margin-right: 6px; margin-top: -1px; -webkit-border-radius: 2px 2px; -moz-border-radius: 2px / 2px; -o-border-radius: 2px / 2px; -ms-border-radius: 2px / 2px; -khtml-border-radius: 2px / 2px; border-radius: 2px / 2px; }
/* line 408, ../scss/_tree.scss */
.cms-tree.jstree-apple span.modified:after { content: "draft"; color: #7E7470; border: 1px solid #C9B800; background-color: #FFF0BC; }
/* line 415, ../scss/_tree.scss */
.cms-tree.jstree-apple span.new:after { content: "new"; color: #7E7470; border: 1px solid #C9B800; background-color: #FFF0BC; }
/* line 422, ../scss/_tree.scss */
.cms-tree.jstree-apple span.private:after { content: "private"; color: #636363; border: 1px solid #E49393; background-color: #F2DADB; }
/* line 429, ../scss/_tree.scss */
.cms-tree.jstree-apple span.workflow-approval:after { content: "awaiting approval"; color: #56660C; border: 1px solid #7C8816; background-color: #DAE79A; }
/* line 437, ../scss/_tree.scss */
.cms-tree.jstree-apple span.comment-count { clear: both; position: relative; text-transform: uppercase; display: inline-block; overflow: visible; padding: 0px 3px; font-size: 0.75em; line-height: 1em; margin-left: 3px; margin-right: 6px; -webkit-border-radius: 2px 2px; -moz-border-radius: 2px / 2px; -o-border-radius: 2px / 2px; -ms-border-radius: 2px / 2px; -khtml-border-radius: 2px / 2px; border-radius: 2px / 2px; color: #7E7470; border: 1px solid #C9B800; background-color: #FFF0BC; }
/* line 454, ../scss/_tree.scss */
.cms-tree.jstree-apple span.comment-count:before { content: ""; position: absolute; bottom: -4px; /* value = - border-top-width - border-bottom-width */ left: 3px; /* controls horizontal position */ border-width: 4px 4px 0; border-style: solid; border-color: #C9B800 transparent; /* reduce the damage in FF3.0 */ display: block; width: 0; }
/* line 467, ../scss/_tree.scss */
.cms-tree.jstree-apple span.comment-count:after { content: ""; position: absolute; bottom: -3px; /* value = - border-top-width - border-bottom-width */ left: 4px; /* value = (:before left) + (:before border-left) - (:after border-left) */ border-width: 3px 3px 0; border-style: solid; border-color: #FFF0BC transparent; /* reduce the damage in FF3.0 */ display: block; width: 0; }
/* line 480, ../scss/_tree.scss */
.cms-tree.jstree-apple .jstree-hovered { text-shadow: none; text-decoration: none; }
/* line 485, ../scss/_tree.scss */
.cms-tree.jstree-apple li { padding: 0px; clear: left; }
/* line 490, ../scss/_tree.scss */
.cms-tree.jstree-apple li, .cms-tree.jstree-apple ins { background-color: transparent; background-image: url(../images/sitetree_ss_default_icons.png); }
/* line 495, ../scss/_tree.scss */
.cms-tree.jstree-apple li.jstree-checked a, .cms-tree.jstree-apple li.jstree-checked a:link { background-color: #efe999; }
/* line 500, ../scss/_tree.scss */
.jstree-apple #record-0.jstree-open > ins { display: none; }
/* line 504, ../scss/_tree.scss */
a .jstree-pageicon { display: block; float: left; width: 16px; height: 16px; margin-right: 4px; background-color: transparent; background-image: url(../images/sitetree_ss_pageclass_icons_default.png); background-repeat: no-repeat; }
/* line 515, ../scss/_tree.scss */
li.class-HomePage a .jstree-pageicon { background-position: 0 -48px; }
/* line 519, ../scss/_tree.scss */
li.class-RedirectorPage a .jstree-pageicon { background-position: 0 -16px; }
/* line 523, ../scss/_tree.scss */
li.class-VirtualPage a .jstree-pageicon { background-position: 0 -32px; }
/* line 527, ../scss/_tree.scss */
li.class-ErrorPage a .jstree-pageicon { background-position: 0 -112px; }
/** Styles for the left hand side menu @package sapphire @subpackage admin */ /** Styles for the left hand side menu @package sapphire @subpackage admin */
/** ------------------------------------------------------- CMS Menu Bar -------------------------------------------------------- */ /** ------------------------------------------------------- CMS Menu Bar -------------------------------------------------------- */
@charset "UTF-8"; /* line 12, ../scss/_menu.scss */
.cms-menu { z-index: 10; background: #c6d7df; border-right: 1px solid #8c99a1; width: 250px; overflow: auto; -moz-box-shadow: rgba(107, 120, 123, 0.5) 2px 0 6px 0; -webkit-box-shadow: rgba(107, 120, 123, 0.5) 2px 0 6px 0; -o-box-shadow: rgba(107, 120, 123, 0.5) 2px 0 6px 0; box-shadow: rgba(107, 120, 123, 0.5) 2px 0 6px 0; } .cms-menu { z-index: 10; background: #c6d7df; border-right: 1px solid #8c99a1; width: 250px; overflow: auto; -moz-box-shadow: 2px 0 6px rgba(107, 120, 123, 0.5); -webkit-box-shadow: 2px 0 6px rgba(107, 120, 123, 0.5); -o-box-shadow: 2px 0 6px rgba(107, 120, 123, 0.5); box-shadow: 2px 0 6px rgba(107, 120, 123, 0.5); }
/* line 21, ../scss/_menu.scss */
.cms-menu a { text-decoration: none; } .cms-menu a { text-decoration: none; }
/* line 25, ../scss/_menu.scss */
.cms-menu .cms-panel-content { width: 250px; }
/* line 30, ../scss/_menu.scss */
.cms-menu.collapsed { width: 40px; cursor: auto; }
/* line 36, ../scss/_menu.scss */
.cms-menu.collapsed .cms-menu-list li span.text { display: none; }
/* line 39, ../scss/_menu.scss */
.cms-menu.collapsed .cms-menu-list li ul { display: none; }
/* line 44, ../scss/_menu.scss */
.cms-menu.collapsed.cms-panel .cms-panel-content { display: block; }
.cms-menu-list li a { display: block; height: 30px; line-height: 30px; vertical-align: middle; font-size: 13px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-shadow: #ced7dc 1px 1px 0; color: #1f1f1f; padding: 5px; background-color: #b0bec7; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #b0bec7), color-stop(100%, #98aab6)); background-image: -moz-linear-gradient(top, #b0bec7 0%, #98aab6 100%); background-image: linear-gradient(top, #b0bec7 0%, #98aab6 100%); border-top: 1px solid #ced7dc; border-bottom: 1px solid #748d9d; } /* line 54, ../scss/_menu.scss */
.cms-menu-list li a:hover { text-decoration: none; background-color: #b6c3cb; border-bottom: 1px solid #8399a7; color: #2c2c2c; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #bfcad2), color-stop(100%, #b0bec7)); background-image: -moz-linear-gradient(top, #bfcad2 0%, #b0bec7 100%); background-image: linear-gradient(top, #bfcad2 0%, #b0bec7 100%); } .cms-menu-list li a { display: block; height: 30px; line-height: 30px; vertical-align: middle; font-size: 13px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-shadow: #bfcad2 1px 1px 0; color: #1f1f1f; padding: 5px 5px 5px 12px; background-color: #b0bec7; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b0bec7), color-stop(100%, #8ca1ae)); background-image: -webkit-linear-gradient(top, #b0bec7, #8ca1ae); background-image: -moz-linear-gradient(top, #b0bec7, #8ca1ae); background-image: -o-linear-gradient(top, #b0bec7, #8ca1ae); background-image: -ms-linear-gradient(top, #b0bec7, #8ca1ae); background-image: linear-gradient(top, #b0bec7, #8ca1ae); border-top: 1px solid #ced7dc; border-bottom: 1px solid #748d9d; }
.cms-menu-list li a:focus { border-top: 1px solid #a1b2bc; text-decoration: none; background-color: #a1b2bc; color: #393939; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #92a5b2), color-stop(100%, #a1b2bc)); background-image: -moz-linear-gradient(top, #92a5b2 0%, #a1b2bc 100%); background-image: linear-gradient(top, #92a5b2 0%, #a1b2bc 100%); } /* line 76, ../scss/_menu.scss */
.cms-menu-list li a .icon { display: block; float: left; margin-right: 4px; background: url('../images/icons-32.png') no-repeat; width: 32px; height: 32px; overflow: hidden; background-position: 0px 0px; } .cms-menu-list li a:hover { text-decoration: none; background-color: #b6c3cb; border-bottom: 1px solid #8399a7; color: #2c2c2c; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #bfcad2), color-stop(100%, #b0bec7)); background-image: -webkit-linear-gradient(top, #bfcad2, #b0bec7); background-image: -moz-linear-gradient(top, #bfcad2, #b0bec7); background-image: -o-linear-gradient(top, #bfcad2, #b0bec7); background-image: -ms-linear-gradient(top, #bfcad2, #b0bec7); background-image: linear-gradient(top, #bfcad2, #b0bec7); }
/* line 87, ../scss/_menu.scss */
.cms-menu-list li a:focus { border-top: 1px solid #a1b2bc; text-decoration: none; background-color: #a1b2bc; color: #393939; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #92a5b2), color-stop(100%, #a1b2bc)); background-image: -webkit-linear-gradient(top, #92a5b2, #a1b2bc); background-image: -moz-linear-gradient(top, #92a5b2, #a1b2bc); background-image: -o-linear-gradient(top, #92a5b2, #a1b2bc); background-image: -ms-linear-gradient(top, #92a5b2, #a1b2bc); background-image: linear-gradient(top, #92a5b2, #a1b2bc); }
/* line 99, ../scss/_menu.scss */
.cms-menu-list li a .icon { display: block; float: left; margin-right: 4px; }
/* line 107, ../scss/_menu.scss */
.cms-menu-list li a .text { display: block; } .cms-menu-list li a .text { display: block; }
.cms-menu-list li.current a { color: white; text-shadow: #1e5270 0 -1px 0; border-top: 1px solid #55a4d2; border-bottom: 1px solid #1e5270; background-color: #338dc1; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #338dc1), color-stop(100%, #287099)); background-image: -moz-linear-gradient(top, #338dc1 0%, #287099 100%); background-image: linear-gradient(top, #338dc1 0%, #287099 100%); } /* line 113, ../scss/_menu.scss */
.cms-menu-list li.current a { color: white; text-shadow: #1e5270 0 -1px 0; border-top: 1px solid #55a4d2; border-bottom: 1px solid #1e5270; background-color: #338dc1; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #338dc1), color-stop(100%, #287099)); background-image: -webkit-linear-gradient(top, #338dc1, #287099); background-image: -moz-linear-gradient(top, #338dc1, #287099); background-image: -o-linear-gradient(top, #338dc1, #287099); background-image: -ms-linear-gradient(top, #338dc1, #287099); background-image: linear-gradient(top, #338dc1, #287099); }
/* line 125, ../scss/_menu.scss */
.cms-menu-list li.current ul { border-top: 1px solid #1e5270; } .cms-menu-list li.current ul { border-top: 1px solid #1e5270; }
/* line 129, ../scss/_menu.scss */
.cms-menu-list li.current li { background-color: #287099; } .cms-menu-list li.current li { background-color: #287099; }
.cms-menu-list li.current li a { font-size: 11px; padding: 0 10px 0 36px; height: 32px; line-height: 32px; color: #e2f0f7; background: none; border-top: 1px solid #338dc1; border-bottom: 1px solid #1e5270; } /* line 132, ../scss/_menu.scss */
.cms-menu-list li.current li a { font-size: 12px; padding: 0 10px 0 36px; height: 32px; line-height: 32px; color: #e2f0f7; background: none; border-top: 1px solid #338dc1; border-bottom: 1px solid #1e5270; }
/* line 143, ../scss/_menu.scss */
.cms-menu-list li.current li a.current, .cms-menu-list li.current li a:hover { background: #2e7ead; border-top: 1px solid #2e7ead; color: white; } .cms-menu-list li.current li a.current, .cms-menu-list li.current li a:hover { background: #2e7ead; border-top: 1px solid #2e7ead; color: white; }
/* line 149, ../scss/_menu.scss */
.cms-menu-list li.current li a:focus { background: #236184; border-top: 1px solid #1e5270; color: white; } .cms-menu-list li.current li a:focus { background: #236184; border-top: 1px solid #1e5270; color: white; }
/* line 157, ../scss/_menu.scss */
.cms-menu-list li.current li.current a { font-weight: bold; color: white; } .cms-menu-list li.current li.current a { font-weight: bold; color: white; }
/* line 162, ../scss/_menu.scss */
.cms-menu-list li.current li.first a { border-top: none; } .cms-menu-list li.current li.first a { border-top: none; }
/* line 169, ../scss/_menu.scss */
.cms-menu-list li#Menu-CMSMain a .icon { background-position: 0px 0px; }
/* line 170, ../scss/_menu.scss */
.cms-menu-list li#Menu-CMSMain.current a .icon, .cms-menu-list li#Menu-CMSMain a:hover .icon { background-position: -32px 0px; }
/* line 171, ../scss/_menu.scss */
.cms-menu-list li#Menu-AssetAdmin a .icon { background-position: 0px -96px; }
/* line 172, ../scss/_menu.scss */
.cms-menu-list li#Menu-AssetAdmin.current a .icon, .cms-menu-list li#Menu-AssetAdmin a:hover .icon { background-position: -32px -96px; }
/* line 173, ../scss/_menu.scss */
.cms-menu-list li#Menu-SecurityAdmin a .icon { background-position: 0px -128px; }
/* line 174, ../scss/_menu.scss */
.cms-menu-list li#Menu-SecurityAdmin.current a .icon, .cms-menu-list li#Menu-SecurityAdmin a:hover .icon { background-position: -32px -128px; }
/* line 175, ../scss/_menu.scss */
.cms-menu-list li#Menu-CMSPagesController a .icon { background-position: 0px -32px; }
/* line 176, ../scss/_menu.scss */
.cms-menu-list li#Menu-CMSPagesController.current a .icon, .cms-menu-list li#Menu-CMSPagesController a:hover .icon { background-position: -32px -32px; }
/* line 179, ../scss/_menu.scss */
.cms-menu-list.collapsed li .text { display: none; }
/* line 183, ../scss/_menu.scss */
.cms-menu-list.collapsed li > li { display: none; }
/** This file defines common styles for form elements used throughout the CMS interface. It is an addition to the base styles defined in sapphire/css/Form.css. */ /** This file defines common styles for form elements used throughout the CMS interface. It is an addition to the base styles defined in sapphire/css/Form.css. */
.field { display: block; padding: 10px 0; border-bottom: 1px solid rgba(201, 205, 206, 0.8); } /** ---------------------------------------------------- Basic form fields ---------------------------------------------------- */
.field label { float: left; width: 10em; } /* line 10, ../scss/_forms.scss */
.field .middleColumn { margin-left: 10em; } .field { display: block; padding: 10px 0; border-bottom: 1px solid rgba(201, 205, 206, 0.8); overflow: hidden; }
/* line 16, ../scss/_forms.scss */
.field label.left { float: left; width: 170px; padding: 8px 20px 8px 4px; line-height: 16px; }
/* line 24, ../scss/_forms.scss */
.field .middleColumn { margin-left: 15em; }
/* line 27, ../scss/_forms.scss */
.field .middleColumn .field { display: inline; padding: 0; border: none; } .field .middleColumn .field { display: inline; padding: 0; border: none; }
/* line 33, ../scss/_forms.scss */
.field .middleColumn label { float: none; width: auto; } .field .middleColumn label { float: none; width: auto; }
/* line 42, ../scss/_forms.scss */
form.nostyle .field { display: inline; padding: 0; border: 0; } form.nostyle .field { display: inline; padding: 0; border: 0; }
/* line 48, ../scss/_forms.scss */
form.nostyle label { float: none; width: auto; } form.nostyle label { float: none; width: auto; }
/* line 53, ../scss/_forms.scss */
form.nostyle .middleColumn { margin-left: 0; } form.nostyle .middleColumn { margin-left: 0; }
/* line 59, ../scss/_forms.scss */
.field.nolabel .middleColumn { margin-left: 0; } .field.nolabel .middleColumn { margin-left: 0; }
input, textarea { -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; -ms-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #eceff1), color-stop(50%, #ffffff), color-stop(100%, #eceff1)); background-image: -moz-linear-gradient(top, #eceff1 0%, #ffffff 50%, #eceff1 100%); background-image: linear-gradient(top, #eceff1 0%, #ffffff 50%, #eceff1 100%); border: 1px solid rgba(201, 205, 206, 0.8); padding: 3px; } /* line 64, ../scss/_forms.scss */
.field.text input, textarea { -moz-border-radius: 4px; -webkit-border-radius: 4px; -o-border-radius: 4px; -ms-border-radius: 4px; -khtml-border-radius: 4px; border-radius: 4px; background: #fff; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #efefef), color-stop(10%, #ffffff), color-stop(90%, #ffffff), color-stop(100%, #efefef)); background-image: -webkit-linear-gradient(top, #efefef, #ffffff 10%, #ffffff 90%, #efefef); background-image: -moz-linear-gradient(top, #efefef, #ffffff 10%, #ffffff 90%, #efefef); background-image: -o-linear-gradient(top, #efefef, #ffffff 10%, #ffffff 90%, #efefef); background-image: -ms-linear-gradient(top, #efefef, #ffffff 10%, #ffffff 90%, #efefef); background-image: linear-gradient(top, #efefef, #ffffff 10%, #ffffff 90%, #efefef); border: 1px solid #b3b3b3; padding: 7px; }
input.loading, input.ui-state-default.loading, .ui-widget-content input.ui-state-default.loading, .ui-widget-header input.ui-state-default.loading { padding-left: 16px; background: #eceff1 url(../../images/network-save.gif) no-repeat center left; } /** ---------------------------------------------------- Buttons ---------------------------------------------------- */
/* line 84, ../scss/_forms.scss */
.ss-ui-button.ss-ui-action-constructive, .ui-widget-content .ss-ui-button.ss-ui-action-constructive, .ui-widget-header .ss-ui-button.ss-ui-action-constructive { background: none; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #77b53f), color-stop(100%, #456925)); background-image: -moz-linear-gradient(top, #77b53f 0%, #456925 100%); background-image: linear-gradient(top, #77b53f 0%, #456925 100%); color: white; } .cms input.loading, .cms input.ui-state-default.loading, .cms .ui-widget-content input.ui-state-default.loading, .cms .ui-widget-header input.ui-state-default.loading { padding-left: 16px; background: #eceff1 url(../../images/network-save.gif) no-repeat center left; }
/* line 91, ../scss/_forms.scss */
.ss-ui-button.ss-ui-action-destructive, .ui-widget-content .ss-ui-button.ss-ui-action-destructive, .ui-widget-header .ss-ui-button.ss-ui-action-destructive { color: red; } .cms .ss-ui-button.ss-ui-action-constructive, .cms .ui-widget-content .ss-ui-button.ss-ui-action-constructive, .cms .ui-widget-header .ss-ui-button.ss-ui-action-constructive { padding-left: 23px; color: white; border-color: #118021; background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #84be3f), color-stop(100%, #128945)); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -webkit-linear-gradient(#84be3f, #128945); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -moz-linear-gradient(#84be3f, #128945); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -o-linear-gradient(#84be3f, #128945); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -ms-linear-gradient(#84be3f, #128945); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, linear-gradient(#84be3f, #128945); background-color: #84be3f; text-shadow: #475964 1px 1px 0; -moz-box-shadow: #748d9d 1px 1px 2px; -webkit-box-shadow: #748d9d 1px 1px 2px; -o-box-shadow: #748d9d 1px 1px 2px; box-shadow: #748d9d 1px 1px 2px; }
/* line 106, ../scss/_forms.scss */
.ss-ui-button.ss-ui-action-minor, .ui-widget-content .ss-ui-button.ss-ui-action-minor .ui-widget-header .ss-ui-button.ss-ui-action-minor { background: none; padding: 0; border: 0; color: #1f1f1f; text-decoration: underline; } .cms .ss-ui-button.ss-ui-action-constructive.ui-state-hover { background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #7fb63c), color-stop(100%, #107b3e)); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -webkit-linear-gradient(#7fb63c, #107b3e); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -moz-linear-gradient(#7fb63c, #107b3e); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -o-linear-gradient(#7fb63c, #107b3e); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, -ms-linear-gradient(#7fb63c, #107b3e); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px 6px, linear-gradient(#7fb63c, #107b3e); background-color: #128945; -moz-box-shadow: #92a5b2 1px 1px 1px; -webkit-box-shadow: #92a5b2 1px 1px 1px; -o-box-shadow: #92a5b2 1px 1px 1px; box-shadow: #92a5b2 1px 1px 1px; }
/* line 117, ../scss/_forms.scss */
.cms .ss-ui-button.ss-ui-action-constructive.cms-page-add-button { background-position: 5px -155px; }
/* line 123, ../scss/_forms.scss */
.cms .ss-ui-button.ss-ui-action-destructive, .cms .ui-widget-content .ss-ui-button.ss-ui-action-destructive, .cms .ui-widget-header .ss-ui-button.ss-ui-action-destructive { color: red; background-color: #f5f5f5; }
/* line 128, ../scss/_forms.scss */
.cms .ss-ui-button.ss-ui-action-destructive.delete { padding-left: 23px; color: red; border-color: #ababab; background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f5f5f5), color-stop(100%, #c3c3c3)); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -webkit-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -moz-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -o-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -ms-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, linear-gradient(#f5f5f5, #c3c3c3); text-shadow: none; -moz-box-shadow: #aab9c3 1px 1px 2px; -webkit-box-shadow: #aab9c3 1px 1px 2px; -o-box-shadow: #aab9c3 1px 1px 2px; box-shadow: #aab9c3 1px 1px 2px; }
/* line 142, ../scss/_forms.scss */
.cms .ss-ui-button.ss-ui-action-destructive.delete.ui-state-hover { background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f0f0f0), color-stop(100%, #bbbbbb)); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -webkit-linear-gradient(#f0f0f0, #bbbbbb); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -moz-linear-gradient(#f0f0f0, #bbbbbb); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -o-linear-gradient(#f0f0f0, #bbbbbb); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, -ms-linear-gradient(#f0f0f0, #bbbbbb); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 5px -26px, linear-gradient(#f0f0f0, #bbbbbb); background-color: #c3c3c3; -moz-box-shadow: #92a5b2 1px 1px 1px; -webkit-box-shadow: #92a5b2 1px 1px 1px; -o-box-shadow: #92a5b2 1px 1px 1px; box-shadow: #92a5b2 1px 1px 1px; }
/* line 155, ../scss/_forms.scss */
.cms .ss-ui-button.ss-ui-action-minor, .cms .ui-widget-content .ss-ui-button.ss-ui-action-minor .ui-widget-header .ss-ui-button.ss-ui-action-minor { background: none; padding: 0; border: 0; color: #1f1f1f; text-decoration: underline; }
/* line 164, ../scss/_forms.scss */
.cms-edit-form { padding-bottom: 20px; } .cms-edit-form { padding-bottom: 20px; }
.cms-edit-form .text input, .cms-edit-form textarea { width: 300px; } /* line 167, ../scss/_forms.scss */
.cms-edit-form .text input, .cms-edit-form textarea { width: 300px; font-family: Arial, sans-serif; font-size: 13px; }
/* line 173, ../scss/_forms.scss */
.cms-edit-form .Actions { text-align: right; } .cms-edit-form .Actions { text-align: right; }
.cms-content-tools .field label { float: none; width: auto; } /** ---------------------------------------------------- Specific field overrides ---------------------------------------------------- */
.cms-content-tools .field .middleColumn { margin-left: 0; } /* line 183, ../scss/_forms.scss */
.htmleditor label { display: block; float: none; padding-bottom: 10px; }
/* line 189, ../scss/_forms.scss */
.htmleditor .middleColumn { margin-left: 0px; clear: left; }
/* line 196, ../scss/_forms.scss */
.field#ViewerGroups label, .field#EditorGroups label, .field#CreateTopLevelGroups label { display: none; } .field#ViewerGroups label, .field#EditorGroups label, .field#CreateTopLevelGroups label { display: none; }
/* line 201, ../scss/_forms.scss */
.action-hidden { display: none; }
/** This file defines CMS-specific customizations to the jQuery UI theme. Every rule in this file should be wrapped in the '.cms' selector (to make it more specific), and contain ONLY overwritten jQuery UI rules (with 'ui-' prefix). This file should be fairly short, as we're using our own custom jQuery UI theme already. TODO Add theme reference Use _style.scss to add more generic style information, and read the jQuery UI theming API: http://jqueryui.com/docs/Theming/API */ /** This file defines CMS-specific customizations to the jQuery UI theme. Every rule in this file should be wrapped in the '.cms' selector (to make it more specific), and contain ONLY overwritten jQuery UI rules (with 'ui-' prefix). This file should be fairly short, as we're using our own custom jQuery UI theme already. TODO Add theme reference Use _style.scss to add more generic style information, and read the jQuery UI theming API: http://jqueryui.com/docs/Theming/API */
/* line 14, ../scss/_uitheme.scss */
.cms .ui-tabs { padding: 0; } .cms .ui-tabs { padding: 0; }
/* line 17, ../scss/_uitheme.scss */
.cms .ui-tabs .ui-widget-header { border: 0; background: none; } .cms .ui-tabs .ui-widget-header { border: 0; background: none; }
.cms .ui-widget-content, .cms .ui-tabs .ui-tabs-panel { color: #444444; font-size: 1em; border: 0; background: #eceff1; } /* line 22, ../scss/_uitheme.scss */
.cms .ui-tabs .ui-tabs-nav { margin: 0; padding: 0; }
/* line 26, ../scss/_uitheme.scss */
.cms .ui-tabs .ui-tabs-nav li { top: 0; }
/* line 29, ../scss/_uitheme.scss */
.cms .ui-tabs .ui-tabs-nav li a { padding: 0 15px; }
/* line 34, ../scss/_uitheme.scss */
.cms .ui-tabs .ui-tabs-nav.ui-state-active { border-color: gray; }
/* line 41, ../scss/_uitheme.scss */
.cms .ui-widget-content, .cms .ui-tabs .ui-tabs-panel { color: #444444; font-size: 13px; border: 0; }
/* line 47, ../scss/_uitheme.scss */
.cms .ui-widget-header { background: #eceff1; border: 0; padding: 0; } .cms .ui-widget-header { background: #eceff1; border: 0; padding: 0; }
/* line 53, ../scss/_uitheme.scss */
.cms .ss-ui-button { padding: 5px; text-decoration: none; } .cms .ss-ui-button { padding: 5px; text-decoration: none; }
/* line 59, ../scss/_uitheme.scss */
.cms .ui-state-hover { cursor: pointer; }
/* line 65, ../scss/_uitheme.scss */
.cms .ss-ui-button, .cms .ui-widget-content .ss-ui-button, .cms .ui-widget-header .ss-ui-button { padding: 5px 7px 5px 7px; color: #1f1f1f; background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 999px 999px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f5f5f5), color-stop(100%, #c3c3c3)); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 999px 999px, -webkit-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 999px 999px, -moz-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 999px 999px, -o-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 999px 999px, -ms-linear-gradient(#f5f5f5, #c3c3c3); background: url('../images/../images/btn_icons_sprite.png?1310018832') no-repeat 999px 999px, linear-gradient(#f5f5f5, #c3c3c3); background-color: #f5f5f5; -moz-box-shadow: #748d9d 1px 1px 2px; -webkit-box-shadow: #748d9d 1px 1px 2px; -o-box-shadow: #748d9d 1px 1px 2px; box-shadow: #748d9d 1px 1px 2px; }
/** This file defines the 'theme' of the CMS: Colors, fonts, backgrounds, and detailed alignments. Together with _layout.css it provides the presentational backbone to the CMS. Ideally a developer should be able to exchange this file with his own theme easily. Please don't put any dimension, display or float information on major structural components like '.cms-container' or '.cms-header' in here, use the _layout.scss file instead. Use SCSS variable definitions in screen.css to avoid repeating styles like background colours or padding dimensions. See _colours.scss to get started. To avoid this file getting too large and complicated, it is encouraged to create new SCSS files for larger components like the CMS menu or tree (see _tree.scss and _menu.scss). */ /* line 80, ../scss/_uitheme.scss */
.cms-content-form { overflow: auto; background: transparent url(../images/textures/bg_cms_main_content.png) repeat top left !important; }
/** This file defines most styles of the CMS: Colors, fonts, backgrounds, alignments, dimensions. Use SCSS variable definitions in screen.css to avoid repeating styles like background colours or padding dimensions. See themes/_default.scss to get started. To avoid this file getting too large and complicated, it is encouraged to create new SCSS files for larger components like the CMS menu or tree (see _tree.scss and _menu.scss). */
/** ---------------------------------------------------- Core Styles ---------------------------------------------------- */ /** ---------------------------------------------------- Core Styles ---------------------------------------------------- */
html, body { width: 100%; height: 100%; overflow: hidden; font-size: 13px; font-family: Verdana, Arial, sans-serif; color: #444444; } /* line 15, ../scss/_style.scss */
html html, html body, html div, html span, html applet, html object, html iframe, html h1, html h2, html h3, html h4, html h5, html h6, html p, html blockquote, html pre, html a, html abbr, html acronym, html address, html big, html cite, html code, html del, html dfn, html em, html font, html img, html ins, html kbd, html q, html s, html samp, html small, html strike, html strong, html sub, html sup, html tt, html var, html dl, html dt, html dd, html ol, html ul, html li, html fieldset, html form, html label, html legend, html table, html caption, html tbody, html tfoot, html thead, html tr, html th, html td, body html, body body, body div, body span, body applet, body object, body iframe, body h1, body h2, body h3, body h4, body h5, body h6, body p, body blockquote, body pre, body a, body abbr, body acronym, body address, body big, body cite, body code, body del, body dfn, body em, body font, body img, body ins, body kbd, body q, body s, body samp, body small, body strike, body strong, body sub, body sup, body tt, body var, body dl, body dt, body dd, body ol, body ul, body li, body fieldset, body form, body label, body legend, body table, body caption, body tbody, body tfoot, body thead, body tr, body th, body td { margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; } html, body { width: 100%; height: 100%; overflow: hidden; font-size: 13px; font-family: Arial, sans-serif; color: #444444; }
html body, body body { line-height: 1; color: black; background: white; } /* line 17, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html html, html body, html div, html span, html applet, html object, html iframe, html h1, html h2, html h3, html h4, html h5, html h6, html p, html blockquote, html pre, html a, html abbr, html acronym, html address, html big, html cite, html code, html del, html dfn, html em, html img, html ins, html kbd, html q, html s, html samp, html small, html strike, html strong, html sub, html sup, html tt, html var, html b, html u, html i, html center, html dl, html dt, html dd, html ol, html ul, html li, html fieldset, html form, html label, html legend, html table, html caption, html tbody, html tfoot, html thead, html tr, html th, html td, html article, html aside, html canvas, html details, html embed, html figure, html figcaption, html footer, html header, html hgroup, html menu, html nav, html output, html ruby, html section, html summary, html time, html mark, html audio, html video, body html, body body, body div, body span, body applet, body object, body iframe, body h1, body h2, body h3, body h4, body h5, body h6, body p, body blockquote, body pre, body a, body abbr, body acronym, body address, body big, body cite, body code, body del, body dfn, body em, body img, body ins, body kbd, body q, body s, body samp, body small, body strike, body strong, body sub, body sup, body tt, body var, body b, body u, body i, body center, body dl, body dt, body dd, body ol, body ul, body li, body fieldset, body form, body label, body legend, body table, body caption, body tbody, body tfoot, body thead, body tr, body th, body td, body article, body aside, body canvas, body details, body embed, body figure, body figcaption, body footer, body header, body hgroup, body menu, body nav, body output, body ruby, body section, body summary, body time, body mark, body audio, body video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }
/* line 20, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html body, body body { line-height: 1; }
/* line 22, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html ol, html ul, body ol, body ul { list-style: none; } html ol, html ul, body ol, body ul { list-style: none; }
html table, body table { border-collapse: separate; border-spacing: 0; vertical-align: middle; } /* line 24, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html table, body table { border-collapse: collapse; border-spacing: 0; }
/* line 26, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html caption, html th, html td, body caption, body th, body td { text-align: left; font-weight: normal; vertical-align: middle; } html caption, html th, html td, body caption, body th, body td { text-align: left; font-weight: normal; vertical-align: middle; }
html q, html blockquote, body q, body blockquote { quotes: "" ""; } /* line 28, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html q:before, html q:after, html blockquote:before, html blockquote:after, body q:before, body q:after, body blockquote:before, body blockquote:after { content: ""; } html q, html blockquote, body q, body blockquote { quotes: none; }
/* line 101, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html q:before, html q:after, html blockquote:before, html blockquote:after, body q:before, body q:after, body blockquote:before, body blockquote:after { content: ""; content: none; }
/* line 30, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html a img, body a img { border: none; } html a img, body a img { border: none; }
/* line 115, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html article, html aside, html details, html figcaption, html figure, html footer, html header, html hgroup, html menu, html nav, html section, body article, body aside, body details, body figcaption, body figure, body footer, body header, body hgroup, body menu, body nav, body section { display: block; }
/* line 27, ../scss/_style.scss */
a { color: #3ebae0; text-decoration: none; } a { color: #3ebae0; text-decoration: none; }
/* line 32, ../scss/_style.scss */
a:hover, a:focus { text-decoration: underline; } a:hover, a:focus { text-decoration: underline; }
body .ui-widget { font-size: 13px; } /* line 36, ../scss/_style.scss */
body .ui-widget { font-family: Arial, sans-serif; font-size: 13px; }
/* line 41, ../scss/_style.scss */
.cms-container { height: 100%; } .cms-container { height: 100%; }
.cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-form { display: -moz-inline-box; -moz-box-orient: vertical; display: inline-block; vertical-align: middle; *vertical-align: auto; } /* line 51, ../scss/_style.scss */
.cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-form { *display: inline; } .cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-fields, .cms-edit-form { display: -moz-inline-box; -moz-box-orient: vertical; display: inline-block; vertical-align: middle; *vertical-align: auto; }
/* line 7, ../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.11.4/frameworks/compass/stylesheets/compass/css3/_inline-block.scss */
.cms-preview, .cms-menu, .cms-content, .cms-content-header, .cms-content-tools, .cms-content-fields, .cms-edit-form { *display: inline; }
/* line 56, ../scss/_style.scss */
strong { font-weight: bold; } strong { font-weight: bold; }
.cms-content-header { background-color: #b1bec6; padding: 8px; height: 32px; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #b1bec6), color-stop(100%, #94a5b0)); background-image: -moz-linear-gradient(top, #b1bec6 0%, #94a5b0 100%); background-image: linear-gradient(top, #b1bec6 0%, #94a5b0 100%); } /** -------------------------------------------- Misc Panels -------------------------------------------- */
.cms-content-header h2 { float: left; padding: 8px; font-size: 14px; font-weight: bold; width: 230px; } /* line 64, ../scss/_style.scss */
.cms-content-header { background-color: #b0bec7; padding: 8px 8px 6px 8px; height: 32px; border-bottom: 2px solid #8399a7; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dde3e7), color-stop(100%, #92a5b2)); background-image: -webkit-linear-gradient(top, #dde3e7, #92a5b2); background-image: -moz-linear-gradient(top, #dde3e7, #92a5b2); background-image: -o-linear-gradient(top, #dde3e7, #92a5b2); background-image: -ms-linear-gradient(top, #dde3e7, #92a5b2); background-image: linear-gradient(top, #dde3e7, #92a5b2); border-bottom: 1px solid #5c7382; padding: 10px; height: 32px; }
/* line 80, ../scss/_style.scss */
.cms-content-header h2 { float: left; padding: 12px 0 0 8px; font-size: 13px; font-weight: bold; text-shadow: #ced7dc 1px 1px 0; width: 230px; }
/* line 89, ../scss/_style.scss */
.cms-content-header > div { width: 9999em; overflow: hidden; } .cms-content-header > div { width: 9999em; overflow: hidden; }
/* line 94, ../scss/_style.scss */
.cms-content-header .cms-content-header-tabs { float: left; } .cms-content-header .cms-content-header-tabs { float: left; }
.ui-tabs .cms-content-header .ui-tabs-nav li { height: 40px; } /* line 101, ../scss/_style.scss */
.ui-tabs .cms-content-header .ui-tabs-nav li a { font-weight: bold; font-size: 11px; padding-top: 8px; } .ui-tabs .cms-content-header .ui-tabs-nav li a { font-weight: bold; font-size: 13px; padding: 11px 15px 9px; border-bottom: 2px solid #b3b3b3; }
.ui-tabs .cms-content-header .ui-state-default, .ui-tabs .cms-content-header .ui-widget-content .ui-state-default, .ui-tabs .cms-content-header .ui-widget-header .ui-state-default { background-color: #feffff; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #feffff), color-stop(100%, #d6d9da)); background-image: -moz-linear-gradient(top, #feffff 0%, #d6d9da 100%); background-image: linear-gradient(top, #feffff 0%, #d6d9da 100%); } /* line 111, ../scss/_style.scss */
.ui-tabs .cms-content-header .ui-state-default, .ui-tabs .cms-content-header .ui-widget-content .ui-state-default, .ui-tabs .cms-content-header .ui-widget-header .ui-state-default { background-color: #d9d9d9; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #d9d9d9), color-stop(100%, #c0c0c0)); background-image: -webkit-linear-gradient(top, #d9d9d9, #c0c0c0); background-image: -moz-linear-gradient(top, #d9d9d9, #c0c0c0); background-image: -o-linear-gradient(top, #d9d9d9, #c0c0c0); background-image: -ms-linear-gradient(top, #d9d9d9, #c0c0c0); background-image: linear-gradient(top, #d9d9d9, #c0c0c0); border-color: #a6a6a6; margin: 0 3px 0 0; text-shadow: white 0 1px 0; }
/* line 125, ../scss/_style.scss */
.ui-tabs .cms-content-header .ui-state-active, .ui-tabs .cms-content-header .ui-widget-content .ui-state-active, .ui-tabs .cms-content-header .ui-widget-header .ui-state-active { background: #eceff1; } .ui-tabs .cms-content-header .ui-state-active, .ui-tabs .cms-content-header .ui-widget-content .ui-state-active, .ui-tabs .cms-content-header .ui-widget-header .ui-state-active { background: #eceff1; }
/* line 128, ../scss/_style.scss */
.ui-tabs .cms-content-header .ui-state-active a, .ui-tabs .cms-content-header .ui-widget-content .ui-state-active a, .ui-tabs .cms-content-header .ui-widget-header .ui-state-active a { border-bottom: 2px solid #eceff1; }
.cms-content-tools { background-color: #dde3e6; padding: 10px; width: 230px; overflow: auto; } /* line 134, ../scss/_style.scss */
.cms-content-tools { background-color: #dde3e7; padding: 8px; width: 230px; overflow: auto; }
/* line 141, ../scss/_style.scss */
.cms-content-tools .cms-panel-header, .cms-content-tools .cms-panel-content { padding: 10px; }
/* line 147, ../scss/_style.scss */
.cms-content.loading { background: url(../images/spinner.gif) no-repeat 50% 50%; }
/** ------------------------------------------------------- Top Left Header and logo area -------------------------------------------------------- */ /** ------------------------------------------------------- Top Left Header and logo area -------------------------------------------------------- */
.cms-header { background-color: #00111d; position: relative; padding: 16px 8px 8px; line-height: 24px; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #00111d), color-stop(50%, #003050), color-stop(100%, #00111d)); background-image: -moz-linear-gradient(top, #00111d 0%, #003050 50%, #00111d 100%); background-image: linear-gradient(top, #00111d 0%, #003050 50%, #00111d 100%); } /* line 156, ../scss/_style.scss */
.cms-header { background-color: #00111d; position: relative; padding: 16px 8px 8px; line-height: 24px; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #00111d), color-stop(50%, #003050), color-stop(100%, #00111d)); background-image: -webkit-linear-gradient(top, #00111d, #003050, #00111d); background-image: -moz-linear-gradient(top, #00111d, #003050, #00111d); background-image: -o-linear-gradient(top, #00111d, #003050, #00111d); background-image: -ms-linear-gradient(top, #00111d, #003050, #00111d); background-image: linear-gradient(top, #00111d, #003050, #00111d); }
/* line 168, ../scss/_style.scss */
.cms-header span { color: white; white-space: no-wrap; text-overflow: ellipsis; display: block; } .cms-header span { color: white; white-space: no-wrap; text-overflow: ellipsis; display: block; }
/* line 174, ../scss/_style.scss */
.cms-header span a { color: #3ebae0; display: inline; } .cms-header span a { color: #3ebae0; display: inline; }
/* line 181, ../scss/_style.scss */
.cms-logo { border-bottom: 1px solid #03090c; height: 31px; overflow: hidden; padding: 0 4px; vertical-align: middle; } .cms-logo { border-bottom: 1px solid #03090c; height: 31px; overflow: hidden; padding: 0 4px; vertical-align: middle; }
/* line 188, ../scss/_style.scss */
.cms-logo .version { display: none; } .cms-logo .version { display: none; }
.cms-logo a { display: inline-block; height: 25px; width: 25px; float: left; margin-right: 10px; background: url('../images/logo_small.png?1305762003') no-repeat; text-indent: -9999em; } /* line 192, ../scss/_style.scss */
.cms-logo a { display: inline-block; height: 25px; width: 25px; float: left; margin-right: 10px; background: url('../images/logo_small.png?1309939638') no-repeat; text-indent: -9999em; }
.cms-login-status { border-top: 1px solid #19435c; height: 23px; padding: 8px 0 0 14px; overflow: hidden; line-height: 16px; font-size: 11px; } /* line 203, ../scss/_style.scss */
.cms-login-status .logout-link { display: inline-block; height: 16px; width: 16px; float: left; margin-right: 10px; background: url(../images/logout.png) no-repeat; text-indent: -9999em; } .cms-login-status { border-top: 1px solid #19435c; height: 23px; padding: 8px 4px 0 4px; overflow: hidden; line-height: 16px; font-size: 11px; }
/* line 211, ../scss/_style.scss */
.cms-login-status .logout-link { display: inline-block; height: 16px; width: 16px; float: left; margin: 0 15px 0 5px; background: url(../images/logout.png) no-repeat; text-indent: -9999em; }
/** ----------------------------------------------- Loading Screen ------------------------------------------------ */
/* line 226, ../scss/_style.scss */
.ss-loading-screen, .ss-loading-screen .loading-logo { width: 100%; height: 100%; overflow: hidden; position: absolute; background: #fff; background: -moz-radial-gradient(50% 50% 180deg, circle cover, white, #efefef, #c7c7c7 100%); background: -webkit-gradient(radial, 50% 50%, 350, 50% 50%, 0, from(#e3e3e3), to(white)); z-index: 100000; margin: 0; padding: 0; } .ss-loading-screen, .ss-loading-screen .loading-logo { width: 100%; height: 100%; overflow: hidden; position: absolute; background: #fff; background: -moz-radial-gradient(50% 50% 180deg, circle cover, white, #efefef, #c7c7c7 100%); background: -webkit-gradient(radial, 50% 50%, 350, 50% 50%, 0, from(#e3e3e3), to(white)); z-index: 100000; margin: 0; padding: 0; }
/* line 241, ../scss/_style.scss */
.ss-loading-screen .loading-logo { background-url: url(../images/logo.gif); background-repeat: no-repeat; background-color: transparent; background-position: 50% 50%; } .ss-loading-screen .loading-logo { background-url: url(../images/logo.gif); background-repeat: no-repeat; background-color: transparent; background-position: 50% 50%; }
/* line 247, ../scss/_style.scss */
.ss-loading-screen p { width: 100%; text-align: center; position: absolute; bottom: 80px; } .ss-loading-screen p { width: 100%; text-align: center; position: absolute; bottom: 80px; }
/* line 253, ../scss/_style.scss */
.ss-loading-screen p span.notice { display: inline-block; font-size: 14px; padding: 10px 20px; color: #dc7f00; border: none; -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; -ms-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px; } .ss-loading-screen p span.notice { display: inline-block; font-size: 14px; padding: 10px 20px; color: #dc7f00; border: none; -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; -ms-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px; }
/* line 263, ../scss/_style.scss */
.ss-loading-screen .loading-animation { display: none; position: absolute; left: 49%; top: 75%; } .ss-loading-screen .loading-animation { display: none; position: absolute; left: 49%; top: 75%; }
.cms-content-actions { padding: 8px; } /** -------------------------------------------- Actions -------------------------------------------- */
/* line 275, ../scss/_style.scss */
.cms-content-actions { border-top: 1px solid #8399a7; padding: 8px; background: transparent url(../images/textures/bg_cms_main_content.png) repeat top left; }
/** Messages (see sapphire/css/Form.css) */ /** -------------------------------------------- Messages -------------------------------------------- */
/* line 285, ../scss/_style.scss */
.message { margin: 1em 0; padding: 0.5em; font-weight: bold; border: 1px black solid; } .message { margin: 1em 0; padding: 0.5em; font-weight: bold; border: 1px black solid; }
/* line 291, ../scss/_style.scss */
.message.notice { background-color: #ffbe66; border-color: #ff9300; } .message.notice { background-color: #ffbe66; border-color: #ff9300; }
/* line 296, ../scss/_style.scss */
.message.warning { background-color: #ffbe66; border-color: #ff9300; } .message.warning { background-color: #ffbe66; border-color: #ff9300; }
/* line 300, ../scss/_style.scss */
.message.error { background-color: #ffbe66; border-color: #ff9300; } .message.error { background-color: #ffbe66; border-color: #ff9300; }
/** -------------------------------------------- ModelAdmin -------------------------------------------- */
/* line 311, ../scss/_style.scss */
.ModelAdmin .cms-content-tools { width: 300px; } .ModelAdmin .cms-content-tools { width: 300px; }
/* line 316, ../scss/_style.scss */
.ModelAdmin .ResultAssemblyBlock { display: none; } .ModelAdmin .ResultAssemblyBlock { display: none; }
/** -------------------------------------------- "Add page" dialog -------------------------------------------- */
/* line 326, ../scss/_style.scss */
.cms-page-add-form-dialog #PageType li { clear: left; height: 40px; border-bottom: 1px solid rgba(107, 120, 123, 0.5); } .cms-page-add-form-dialog #PageType li { clear: left; height: 40px; border-bottom: 1px solid rgba(107, 120, 123, 0.5); }
/* line 331, ../scss/_style.scss */
.cms-page-add-form-dialog #PageType li:hover, .cms-page-add-form-dialog #PageType li.selected { background-color: #ffff99; } .cms-page-add-form-dialog #PageType li:hover, .cms-page-add-form-dialog #PageType li.selected { background-color: #ffff99; }
/* line 335, ../scss/_style.scss */
.cms-page-add-form-dialog #PageType li input, .cms-page-add-form-dialog #PageType li label, .cms-page-add-form-dialog #PageType li .icon, .cms-page-add-form-dialog #PageType li .title { float: left; } .cms-page-add-form-dialog #PageType li input, .cms-page-add-form-dialog #PageType li label, .cms-page-add-form-dialog #PageType li .icon, .cms-page-add-form-dialog #PageType li .title { float: left; }
/* line 339, ../scss/_style.scss */
.cms-page-add-form-dialog #PageType li .icon { width: 20px; } .cms-page-add-form-dialog #PageType li .icon { width: 20px; }
/* line 343, ../scss/_style.scss */
.cms-page-add-form-dialog #PageType li .title { width: 100px; font-weight: bold; } .cms-page-add-form-dialog #PageType li .title { width: 100px; font-weight: bold; }
/* line 348, ../scss/_style.scss */
.cms-page-add-form-dialog #PageType li .description { font-style: italic; } .cms-page-add-form-dialog #PageType li .description { font-style: italic; }
.cms-content-toolbar > * { display: inline-block; } /** -------------------------------------------- Content toolbar -------------------------------------------- */
/* line 358, ../scss/_style.scss */
.cms-content-toolbar { overflow: hidden; *zoom: 1; display: block; padding: 10px 0; margin: 0 0 15px 0; border-bottom-width: 2px; border-bottom: 2px groove rgba(255, 255, 255, 0.8); -webkit-border-image: url(../images/textures/bg_fieldset_elements_border.png) 2 stretch stretch; border-image: url(../images/textures/bg_fieldset_elements_border.png) 2 stretch stretch; }
/* line 369, ../scss/_style.scss */
.cms-content-toolbar > * { float: left; }
/* line 373, ../scss/_style.scss */
.cms-content-toolbar .cms-tree-view-modes * { display: inline-block; } .cms-content-toolbar .cms-tree-view-modes * { display: inline-block; }
/* line 377, ../scss/_style.scss */
.cms-content-toolbar .cms-content-batchactions form > * { display: inline-block; } .cms-content-toolbar .cms-content-batchactions form > * { display: inline-block; }
.cms-preview { width: 1px; overflow: hidden; } /* line 384, ../scss/_style.scss */
.cms-content-tools .field label { float: none; width: auto; }
/* line 389, ../scss/_style.scss */
.cms-content-tools .field .middleColumn { margin-left: 0; }
/* line 395, ../scss/_style.scss */
.cms-content-batchactions, .cms-content-constructive-actions { float: right; }
/* line 399, ../scss/_style.scss */
.cms-content-batchactions { float: right; position: relative; display: block; margin-right: 8px; }
/* line 406, ../scss/_style.scss */
form.cms-batch-actions { float: left; }
/* line 410, ../scss/_style.scss */
.cms-content-constructive-actions a { display: block; float: right; }
/** -------------------------------------------- Preview header (remove before release) -------------------------------------------- */
/* line 419, ../scss/_style.scss */
.cms-preview { width: 1px; }
/* line 422, ../scss/_style.scss */
.cms-preview .cms-preview-toggle { width: 10px; } .cms-preview .cms-preview-toggle { width: 10px; }
/* line 426, ../scss/_style.scss */
.cms-preview iframe { width: 100%; height: 100%; } .cms-preview iframe { width: 100%; height: 100%; }
/* line 432, ../scss/_style.scss */
.cms-preview-header { background-color: #FFBE66; padding: 10px; font-weight: bold; } .cms-preview-header { background-color: #FFBE66; padding: 10px; font-weight: bold; }
/** -------------------------------------------- Member Profile -------------------------------------------- */
/* line 444, ../scss/_style.scss */
form.member-profile-form #CsvFile .middleColumn { background: none !important; } form.member-profile-form #CsvFile .middleColumn { background: none !important; }
/* line 448, ../scss/_style.scss */
form.member-profile-form .advanced h4 { margin-bottom: .5em; } form.member-profile-form .advanced h4 { margin-bottom: .5em; }
/* line 452, ../scss/_style.scss */
form.member-profile-form .Actions { text-align: left; border: 0; } form.member-profile-form .Actions { text-align: left; border: 0; }
/* line 457, ../scss/_style.scss */
form.member-profile-form input.customFormat { border: 1px solid #ccc !important; padding: 3px; margin-left: 2px; } form.member-profile-form input.customFormat { border: 1px solid #ccc !important; padding: 3px; margin-left: 2px; }
/* line 462, ../scss/_style.scss */
form.member-profile-form .formattingHelpToggle { font-size: 11px; padding: 3px; } form.member-profile-form .formattingHelpToggle { font-size: 11px; padding: 3px; }
/* line 466, ../scss/_style.scss */
form.member-profile-form .formattingHelpText { margin: 5px auto; color: #333; padding: 5px 10px; width: 90%; background: #fff; border: 1px solid #ccc; } form.member-profile-form .formattingHelpText { margin: 5px auto; color: #333; padding: 5px 10px; width: 90%; background: #fff; border: 1px solid #ccc; }
/* line 474, ../scss/_style.scss */
form.member-profile-form .formattingHelpText ul { padding: 0; } form.member-profile-form .formattingHelpText ul { padding: 0; }
/* line 477, ../scss/_style.scss */
form.member-profile-form .formattingHelpText li { font-size: 11px; color: #333; margin-bottom: 2px; } form.member-profile-form .formattingHelpText li { font-size: 11px; color: #333; margin-bottom: 2px; }
.cms-content-form { overflow: auto; } /* line 485, ../scss/_style.scss */
.cms-content-fields { overflow: auto; background: transparent url(../images/textures/bg_cms_main_content.png) repeat top left; }
/** -------------------------------------------- Panels -------------------------------------------- */
/* line 494, ../scss/_style.scss */
.cms-panel { overflow: hidden; }
/* line 499, ../scss/_style.scss */
.cms-panel .toggle-expand, .cms-panel .toggle-collapse { display: block; position: absolute; bottom: 0; text-align: right; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b0bec7), color-stop(100%, #92a5b2)); background-image: -webkit-linear-gradient(top, #b0bec7, #92a5b2); background-image: -moz-linear-gradient(top, #b0bec7, #92a5b2); background-image: -o-linear-gradient(top, #b0bec7, #92a5b2); background-image: -ms-linear-gradient(top, #b0bec7, #92a5b2); background-image: linear-gradient(top, #b0bec7, #92a5b2); text-decoration: none; }
/* line 510, ../scss/_style.scss */
.cms-panel .toggle-expand span, .cms-panel .toggle-collapse span { display: inline-block; margin: 5px; color: #1f1f1f; font-size: 16px; }
/* line 518, ../scss/_style.scss */
.cms-panel .toggle-collapse { width: 100%; }
/* line 522, ../scss/_style.scss */
.cms-panel .toggle-expand { width: 40px; }
/* line 528, ../scss/_style.scss */
.cms-panel.collapsed .cms-panel-content { display: none; }
/* line 532, ../scss/_style.scss */
.cms-panel.collapsed .cms-panel-header { -moz-transform: rotate(-90deg); -webkit-transform: rotate(-90deg); -o-transform: rotate(-90deg); -ms-transform: rotate(-90deg); transform: rotate(-90deg); position: relative; top: 100px; }
/* line 542, ../scss/_style.scss */
.cms-content .cms-panel.collapsed { cursor: pointer; }
/** -------------------------------------------- Other -------------------------------------------- */
/* line 550, ../scss/_style.scss */
.cms-preview { background-color: #b0bec7; } .cms-preview { background-color: #b0bec7; }
/* line 553, ../scss/_style.scss */
.cms-preview .cms-preview-toggle { cursor: pointer; } .cms-preview .cms-preview-toggle { cursor: pointer; }
.cms-preview .cms-preview-toggle a { color: white; font-weight: bold; text-decoration: none; } /* line 556, ../scss/_style.scss */
.cms-preview .cms-preview-toggle a { display: block; width: 15px; height: 15px; position: relative; left: 10px; top: 48%; background-color: #b0bec7; color: white; font-weight: bold; text-decoration: none; z-index: 2000; }
/* line 573, ../scss/_style.scss */
.cms-preview.is-collapsed .cms-preview-toggle a { left: -15px; }
/* line 581, ../scss/_style.scss */
.cms-switch-view a { padding-right: 1em; } .cms-switch-view a { padding-right: 1em; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

View File

@ -91,8 +91,9 @@
data.push({name:button.attr('name'),value:button.val()}); data.push({name:button.attr('name'),value:button.val()});
// TODO Should be set by hiddenfield already // TODO Should be set by hiddenfield already
jQuery('.cms-edit-form').entwine('ss').loadForm( jQuery('.cms-content').entwine('ss').loadForm(
this.attr('action'), this.attr('action'),
null,
function() { function() {
// Tree updates are triggered by Form_EditForm load events // Tree updates are triggered by Form_EditForm load events
button.removeClass('loading'); button.removeClass('loading');
@ -129,7 +130,7 @@
dropdown.find('option').remove(); dropdown.find('option').remove();
//Use tree hints to find allowed children for this node //Use tree hints to find allowed children for this node
if (className && typeof siteTreeHints !== 'undefined') { if (className && siteTreeHints) {
disallowed = siteTreeHints[className].disallowedChildren; disallowed = siteTreeHints[className].disallowedChildren;
} }

View File

@ -0,0 +1,266 @@
(function($) {
$.entwine('ss', function($){
$('.cms-content, .cms-content *').entwine({
/**
* Triggered before a new URL is loaded, typically via ajax.
* Loading itself is handled by $('.cms-container') and window.history.
*
* @param {String}
*/
beforeLoad: function(url) {
this.addClass('loading');
this.cleanup();
},
/**
* Triggered after an ajax request with new HTML data.
*
* @param {String}
* @param {String}
* @param {XMLHTTPRequest}
*/
afterLoad: function(data, status, xhr) {
this.removeClass('loading');
this.replaceWith(data);
},
cleanup: function() {
this.empty();
}
});
/**
* The "content" area contains all of the section specific UI (excluding the menu).
* This area can be a form itself, as well as contain one or more forms.
* For example, a page edit form might fill the whole area,
* while a ModelAdmin layout shows a search form on the left, and edit form on the right.
*/
$('.cms-content').entwine({
onmatch: function() {
var self = this;
// Listen to tree selection events
this.find('.cms-tree').bind('select_node.jstree', function(e, data) {
var node = data.rslt.obj, loadedNodeID = self.find(':input[name=ID]').val(), origEvent = data.args[2];
// Don't trigger unless coming from a click event.
// Avoids problems with automated section switches from tree to detail view
// when JSTree auto-selects elements on first load.
if(!origEvent) return false;
// Don't allow checking disabled nodes
if($(node).hasClass('disabled')) return false;
// Don't allow reloading of currently selected node,
// mainly to avoid doing an ajax request on initial page load
if($(node).data('id') == loadedNodeID) return;
var url = $(node).find('a:first').attr('href');
if(url && url != '#') {
window.History.pushState({}, '', url);
} else {
self.removeForm();
}
});
this._super();
},
onunmatch: function() {
this._super();
},
/**
* Function: loadForm
*
* See $('.cms-container').handleStateChange() on a frequently used alternative
* to direct ajax loading of content, with support for the window.History object.
*
* Parameters:
* (String) url - ..
* (Function) callback - (Optional) Called after the form content as been loaded
* (Object) ajaxOptions - Object literal merged into the jQuery.ajax() call (Optional)
*
* Returns:
* (XMLHTTPRequest)
*/
loadForm: function(url, form, callback, ajaxOptions) {
var self = this;
if(!form || !form.length) var form = $('.cms-content-fields form:first');
// Alert when unsaved changes are present
if(form._checkChangeTracker(true) == false) return false;
// hide existing form - shown again through _loadResponse()
form.addClass('loading');
this.trigger('loadform', {form: form, url: url});
form.cleanup();
return jQuery.ajax(jQuery.extend({
url: url,
// Ensure that form view is loaded (rather than whole "Content" template)
data: {'cms-view-form': 1},
complete: function(xmlhttp, status) {
self.loadForm_responseHandler(form, xmlhttp.responseText, status, xmlhttp);
if(callback) callback.apply(self, arguments);
},
dataType: 'html'
}, ajaxOptions));
},
loadForm_responseHandler: function(oldForm, html, status, xmlhttp) {
oldForm.replaceWith(html); // triggers onmatch() on form
// set status message based on response
var _statusMessage = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.statusText;
},
/**
* Function: ajaxSubmit
*
* Parameters:
* {DOMElement} button - The pressed button (optional)
* {Function} callback - Called in complete() handler of jQuery.ajax()
* {Object} ajaxOptions - Object literal to merge into $.ajax() call
* {boolean} loadResponse - Render response through _loadResponse() (Default: true)
*
* Returns:
* (boolean)
*/
submitForm: function(form, button, callback, ajaxOptions, loadResponse) {
var self = this;
// look for save button
if(!button) button = this.find('.Actions :submit[name=action_save]');
// default to first button if none given - simulates browser behaviour
if(!button) button = this.find('.Actions :submit:first');
this.trigger('submitform', {form: form, button: button});
// set button to "submitting" state
$(button).addClass('loading');
// @todo TinyMCE coupling
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
// validate if required
if(!form.validate()) {
// TODO Automatically switch to the tab/position of the first error
statusMessage("Validation failed.", "bad");
$(button).removeClass('loading');
return false;
}
// save tab selections in order to reconstruct them later
var selectedTabs = [];
form.find('.ss-tabset').each(function(i, el) {
if($(el).attr('id')) selectedTabs.push({id:$(el).attr('id'), selected:$(el).tabs('option', 'selected')});
});
// get all data from the form
var formData = form.serializeArray();
// add button action
formData.push({name: $(button).attr('name'), value:'1'});
jQuery.ajax(jQuery.extend({
url: form.attr('action'),
data: formData,
type: 'POST',
complete: function(xmlhttp, status) {
$(button).removeClass('loading');
// TODO This should be using the plugin API
form.removeClass('changed');
if(callback) callback(xmlhttp, status);
// pass along original form data to enable old/new comparisons
if(loadResponse !== false) {
self.submitForm_responseHandler(form, xmlhttp.responseText, status, xmlhttp, formData);
}
// Re-init tabs (in case the form tag itself is a tabset)
if(self.hasClass('ss-tabset')) self.removeClass('ss-tabset').addClass('ss-tabset');
// re-select previously saved tabs
$.each(selectedTabs, function(i, selectedTab) {
form.find('#' + selectedTab.id).tabs('select', selectedTab.selected);
});
},
dataType: 'html'
}, ajaxOptions));
return false;
},
/**
* Function: _loadResponse
*
* Parameters:
* {String} data - Either HTML for straight insertion, or eval'ed JavaScript.
* If passed as HTML, it is assumed that everying inside the <form> tag is replaced,
* but the old <form> tag itself stays intact.
* {String} status
* {XMLHTTPRequest} xmlhttp - ..
* {Array} origData - The original submitted data, useful to do comparisons of changed
* values in new form output, e.g. to detect a URLSegment being changed on the serverside.
* Array in jQuery serializeArray() notation.
*/
submitForm_responseHandler: function(oldForm, data, status, xmlhttp, origData) {
if(status == 'success') {
var form = this.replaceForm(oldForm, data);
Behaviour.apply(); // refreshes ComplexTableField
this.trigger('loadnewpage', {form: form, origData: origData, xmlhttp: xmlhttp});
}
// set status message based on response
var _statusMessage = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.statusText;
},
/**
* @return {jQuery} New form element
*/
replaceForm: function(form, html) {
form.cleanup();
if(html) {
var parent = form.parent(), id = form.attr('id');
form.replaceWith(html);
// Try to get the new form by ID (assuming they're identical), otherwise fall back to the first form in the parent
return id ? $('#' + id) : parent.children('form:first');
} else {
this.removeForm(form);
return null;
}
},
/**
* Function: removeForm
*
* Remove everying inside the <form> tag
* with a custom HTML fragment. Useful e.g. for deleting a page in the CMS.
* Checks for unsaved changes before removing the form
*
* Parameters:
* {String} placeholderHtml - Short note why the form has been removed, displayed in <p> tags.
* Falls back to the default RemoveText() option (Optional)
*/
removeForm: function(form, placeholderHtml) {
if(!placeholderHtml) placeholderHtml = this.getPlaceholderHtml();
// Alert when unsaved changes are present
if(form._checkChangeTracker(true) == false) return;
this.trigger('removeform');
this.html(placeholderHtml);
// TODO This should be using the plugin API
this.removeClass('changed');
}
});
});
})(jQuery);

View File

@ -41,33 +41,64 @@
this._setupChangeTracker(); this._setupChangeTracker();
$('.cms-tree').bind('select_node.jstree', function(e, data) {
var node = data.rslt.obj, loadedNodeID = self.find(':input[name=ID]').val()
// Don't allow checking disabled nodes
if($(node).hasClass('disabled')) return false;
// Don't allow reloading of currently selected node,
// mainly to avoid doing an ajax request on initial page load
if($(node).data('id') == loadedNodeID) return;
var url = $(node).find('a:first').attr('href');
if(url && url != '#') {
var xmlhttp = self.loadForm(
url,
function(response) {}
);
} else {
self.removeForm();
}
});
// Can't bind this through jQuery // Can't bind this through jQuery
window.onbeforeunload = function(e) {return self._checkChangeTracker(false);}; window.onbeforeunload = function(e) {return self._checkChangeTracker(false);};
// focus input on first form element
this.find(':input:visible:first').focus();
// Optionally get the form attributes from embedded fields, see Form->formHtmlContent()
for(var overrideAttr in {'action':true,'method':true,'enctype':true,'name':true}) {
var el = this.find(':input[name='+ '_form_' + overrideAttr + ']');
if(el) {
this.attr(overrideAttr, el.val());
el.remove();
}
}
// TODO
// // Rewrite # links
// html = html.replace(/(<a[^>]+href *= *")#/g, '$1' + window.location.href.replace(/#.*$/,'') + '#');
//
// // Rewrite iframe links (for IE)
// html = html.replace(/(<iframe[^>]*src=")([^"]+)("[^>]*>)/g, '$1' + $('base').attr('href') + '$2$3');
// Show validation errors if necessary
if(this.hasClass('validationerror')) {
// TODO validation shouldnt need a special case
statusMessage(ss.i18n._t('ModelAdmin.VALIDATIONERROR', 'Validation Error'), 'bad');
}
this._super(); this._super();
}, },
onunmatch: function() {
// Prepare iframes for removal, otherwise we get loading bugs
this.find('iframe').each(function() {
this.contentWindow.location.href = 'about:blank';
$(this).remove();
});
// Remove all TinyMCE instances
if((typeof tinymce != 'undefined') && tinymce.editors) {
$(tinymce.editors).each(function() {
if(typeof(this.remove) == 'function') this.remove();
});
}
this._super();
},
beforeLoad: function(url) {
this.addClass('loading');
this.cleanup();
},
afterLoad: function(data, status, xhr) {
this.removeClass('loading');
this.replaceWith(data);
},
/** /**
* Function: _setupChangeTracker * Function: _setupChangeTracker
*/ */
@ -114,86 +145,7 @@
* Suppress submission unless it is handled through ajaxSubmit(). * Suppress submission unless it is handled through ajaxSubmit().
*/ */
onsubmit: function(e) { onsubmit: function(e) {
this.ajaxSubmit(); this.parents('.cms-content').submitForm(this);
return false;
},
/**
* Function: ajaxSubmit
*
* Parameters:
* {DOMElement} button - The pressed button (optional)
* {Function} callback - Called in complete() handler of jQuery.ajax()
* {Object} ajaxOptions - Object literal to merge into $.ajax() call
* {boolean} loadResponse - Render response through _loadResponse() (Default: true)
*
* Returns:
* (boolean)
*/
ajaxSubmit: function(button, callback, ajaxOptions, loadResponse) {
var self = this;
// look for save button
if(!button) button = this.find('.Actions :submit[name=action_save]');
// default to first button if none given - simulates browser behaviour
if(!button) button = this.find('.Actions :submit:first');
this.trigger('ajaxsubmit', {button: button});
// set button to "submitting" state
$(button).addClass('loading');
// @todo TinyMCE coupling
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
// validate if required
if(!this.validate()) {
// TODO Automatically switch to the tab/position of the first error
statusMessage("Validation failed.", "bad");
$(button).removeClass('loading');
return false;
}
// save tab selections in order to reconstruct them later
var selectedTabs = [];
this.find('.ss-tabset').each(function(i, el) {
if($(el).attr('id')) selectedTabs.push({id:$(el).attr('id'), selected:$(el).tabs('option', 'selected')});
});
// get all data from the form
var formData = this.serializeArray();
// add button action
formData.push({name: $(button).attr('name'), value:'1'});
jQuery.ajax(jQuery.extend({
url: this.attr('action'),
data: formData,
type: 'POST',
complete: function(xmlhttp, status) {
$(button).removeClass('loading');
// TODO This should be using the plugin API
self.removeClass('changed');
if(callback) callback(xmlhttp, status);
// pass along original form data to enable old/new comparisons
if(loadResponse !== false) {
self._loadResponse(xmlhttp.responseText, status, xmlhttp, formData);
}
// Re-init tabs (in case the form tag itself is a tabset)
if(self.hasClass('ss-tabset')) self.removeClass('ss-tabset').addClass('ss-tabset');
// re-select previously saved tabs
$.each(selectedTabs, function(i, selectedTab) {
self.find('#' + selectedTab.id).tabs('select', selectedTab.selected);
});
},
dataType: 'html'
}, ajaxOptions));
return false; return false;
}, },
@ -215,151 +167,6 @@
this.trigger('validate', {isValid: isValid}); this.trigger('validate', {isValid: isValid});
return isValid; return isValid;
},
/**
* Function: loadForm
*
* Parameters:
* (String) url - ..
* (Function) callback - (Optional) Called after the form content as been loaded
* (Object) ajaxOptions - Object literal merged into the jQuery.ajax() call (Optional)
*
* Returns:
* (XMLHTTPRequest)
*/
loadForm: function(url, callback, ajaxOptions) {
var self = this;
// Alert when unsaved changes are present
if(this._checkChangeTracker(true) == false) return false;
// hide existing form - shown again through _loadResponse()
this.addClass('loading');
this.trigger('load', {url: url});
this.cleanup();
return jQuery.ajax(jQuery.extend({
url: url,
complete: function(xmlhttp, status) {
// TODO This should be using the plugin API
self.removeClass('changed');
self._loadResponse(xmlhttp.responseText, status, xmlhttp);
self.removeClass('loading');
if(callback) callback.apply(self, arguments);
},
dataType: 'html'
}, ajaxOptions));
},
/**
* Function: removeForm
*
* Remove everying inside the <form> tag
* with a custom HTML fragment. Useful e.g. for deleting a page in the CMS.
* Checks for unsaved changes before removing the form
*
* Parameters:
* {String} placeholderHtml - Short note why the form has been removed, displayed in <p> tags.
* Falls back to the default RemoveText() option (Optional)
*/
removeForm: function(placeholderHtml) {
if(!placeholderHtml) placeholderHtml = this.getPlaceholderHtml();
// Alert when unsaved changes are present
if(this._checkChangeTracker(true) == false) return;
this.trigger('removeform');
this.html(placeholderHtml);
// TODO This should be using the plugin API
this.removeClass('changed');
},
/**
* Function: cleanup
*
* Remove all the currently active TinyMCE editors.
* Note: Everything that calls this externally has an inappropriate coupling to TinyMCE.
*/
cleanup: function() {
if((typeof tinymce != 'undefined') && tinymce.editors) {
$(tinymce.editors).each(function() {
if(typeof(this.remove) == 'function') {
this.remove();
}
});
}
},
/**
* Function: _loadResponse
*
* Parameters:
* {String} data - Either HTML for straight insertion, or eval'ed JavaScript.
* If passed as HTML, it is assumed that everying inside the <form> tag is replaced,
* but the old <form> tag itself stays intact.
* {String} status
* {XMLHTTPRequest} xmlhttp - ..
* {Array} origData - The original submitted data, useful to do comparisons of changed
* values in new form output, e.g. to detect a URLSegment being changed on the serverside.
* Array in jQuery serializeArray() notation.
*/
_loadResponse: function(data, status, xmlhttp, origData) {
if(status == 'success') {
this.cleanup();
var html = data;
// Rewrite # links
html = html.replace(/(<a[^>]+href *= *")#/g, '$1' + window.location.href.replace(/#.*$/,'') + '#');
// Rewrite iframe links (for IE)
html = html.replace(/(<iframe[^>]*src=")([^"]+)("[^>]*>)/g, '$1' + $('base').attr('href') + '$2$3');
// Prepare iframes for removal, otherwise we get loading bugs
this.find('iframe').each(function() {
this.contentWindow.location.href = 'about:blank';
$(this).remove();
});
// update form content
if(html) {
this.html(html);
} else {
this.removeForm();
}
// If the form itself is a tabset, force re-rendering
if(this.hasClass('ss-tabset')) this.tabs('destroy').tabs();
this._setupChangeTracker();
// Optionally get the form attributes from embedded fields, see Form->formHtmlContent()
for(var overrideAttr in {'action':true,'method':true,'enctype':true,'name':true}) {
var el = this.find(':input[name='+ '_form_' + overrideAttr + ']');
if(el) {
this.attr(overrideAttr, el.val());
el.remove();
}
}
Behaviour.apply(); // refreshes ComplexTableField
// focus input on first form element
this.find(':input:visible:first').focus();
this.trigger('loadnewpage', {data: data, origData: origData, xmlhttp: xmlhttp});
}
// set status message based on response
var _statusMessage = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.statusText;
if(this.hasClass('validationerror')) {
// TODO validation shouldnt need a special case
statusMessage(ss.i18n._t('ModelAdmin.VALIDATIONERROR', 'Validation Error'), 'bad');
}
} }
}); });
@ -376,7 +183,7 @@
* Function: onclick * Function: onclick
*/ */
onclick: function(e) { onclick: function(e) {
jQuery('.cms-edit-form').entwine('ss').ajaxSubmit(this); $('.cms-content').submitForm(this.parents('form'), this);
return false; return false;
} }
}); });

View File

@ -0,0 +1,114 @@
(function($) {
$.entwine('ss', function($){
/**
* Vertical CMS menu with two levels, built from a nested unordered list.
* The (optional) second level is collapsible, hiding its children.
* The whole menu (including second levels) is collapsible as well,
* exposing only a preview for every menu item in order to save space.
* In this "preview/collapsed" mode, the secondary menu hovers over the menu item,
* rather than expanding it.
*
* Example:
*
* <ul class="cms-menu-list">
* <li><a href="#">Item 1</a></li>
* <li class="current opened">
* <a href="#">Item 2</a>
* <ul>
* <li class="current opened"><a href="#">Item 2.1</a></li>
* <li><a href="#">Item 2.2</a></li>
* </ul>
* </li>
* </ul>
*/
$('.cms-menu-list').entwine({
onmatch: function() {
var self = this;
// TODO Fix icon etc.
// this.children('li').each(function() {
// $(this).find('a:first').append('<span class="toggle">o</span>');
// });
$('.cms-container').bind('afterstatechange', function(e, data) {
var controller = data.xhr.getResponseHeader('X-Controller');
if(controller) self.find('li#Menu-' + controller).select();
});
// Sync collapsed state with parent panel
this.parents('.cms-panel:first').bind('toggle', function(e) {
self.toggleClass('collapsed', $(this).hasClass('collapsed'));
});
this._super();
}
});
$('.cms-menu-list .toggle').entwine({
onclick: function(e) {
this.getMenuItem().toggle();
e.preventDefault();
}
});
$('.cms-menu-list li').entwine({
toggle: function() {
this[this.hasClass('opened') ? 'close' : 'open']();
},
open: function() {
var parent = this.getMenuItem();
if(parent) parent.open();
this.addClass('opened').find('ul').show();
},
close: function() {
this.removeClass('opened').find('ul').hide();
},
select: function() {
var parent = this.getMenuItem();
this.addClass('current').open();
// Remove "current" class from all siblings and their children
this.siblings().removeClass('current').close();
this.siblings().find('li').removeClass('current');
if(parent) parent.addClass('current').siblings().removeClass('current');
}
});
$('.cms-menu-list li *').entwine({
getMenuItem: function() {
return this.parents('li:first');
}
});
/**
* Both primary and secondary nav.
*/
$('.cms-menu-list li a').entwine({
onclick: function(e) {
// Only catch left clicks, in order to allow opening in tabs.
// Ignore external links, fallback to standard link behaviour
if(e.which > 1 || this.is(':external')) return;
e.preventDefault();
// Expand this, and collapse all other items
var item = this.getMenuItem();
item.select();
var children = item.find('li');
if(children.length) {
children.first().find('a').click();
} else {
// Active menu item is set based on X-Controller ajax header,
// which matches one class on the menu
window.History.pushState({}, '', this.attr('href'));
}
}
});
});
// Internal Helper
$.expr[':'].internal = function(obj){return obj.href.match(/^mailto\:/) || (obj.hostname == location.hostname);};
$.expr[':'].external = function(obj){return !$(obj).is(':internal')};
}(jQuery));

View File

@ -0,0 +1,108 @@
(function($) {
$.entwine('ss', function($){
// setup jquery.entwine
$.entwine.warningLevel = $.entwine.WARN_LEVEL_BESTPRACTISE;
/**
* Vertically collapsible panel. Generic enough to work with CMS menu as well as various "filter" panels.
*
* A panel consists of the following parts:
* - Container div: The outer element, with class ".cms-panel"
* - Header (optional)
* - Content
* - Expand and collapse toggle anchors (optional)
*
* Sample HTML:
* <div class="cms-panel">
* <div class="cms-panel-header">your header</div>
* <div class="cms-panel-content">your content here</div>
* <a href="#" class="toggle-expande">your toggle text</a>
* <a href="#" class="toggle-collapse">your toggle text</a>
* </div>
*/
$('.cms-panel').entwine({
WidthExpanded: null,
WidthCollapsed: null,
onmatch: function() {
if(!this.find('.cms-panel-content').length) throw new Exception('Content panel for ".cms-panel" not found');
// Create default controls unless they already exist
if(!this.find('.toggle-expand').length) this.append('<a class="toggle-expand" href="#"><span>&raquo;</span></a>');
if(!this.find('.toggle-collapse').length) this.append('<a class="toggle-collapse" href="#"><span>&laquo;</span></a>');
// Set panel width same as the content panel it contains. Assumes the panel has overflow: hidden.
this.setWidthExpanded(this.find('.cms-panel-content').width());
// Assumes the collasped width is indicated by the toggle, or by an optional collapsed view
var collapsedContent = this.find('.cms-panel-content-collapsed');
this.setWidthCollapsed(collapsedContent.length ? collapsedContent.widht() : this.find('.toggle-expand').width());
this.togglePanel(!jQuery(this).hasClass('collapsed'));
this._super();
},
onclick: function(e) {
// By default, the whole collapsed area serves as a trigger
if(this.data('expandOnClick') && jQuery(this).hasClass('collapsed')) {
e.preventDefault();
this.expandPanel();
}
},
togglePanel: function(bool) {
// if((!bool && this.hasClass('collapsed')) || (bool && !this.hasClass('collapsed'))) return;
this.toggleClass('collapsed', !bool);
var newWidth = bool ? this.getWidthExpanded() : this.getWidthCollapsed();
this.trigger('beforetoggle');
this.width(newWidth); // the content panel width always stays in "expanded state" to avoid floating elements
this.find('.toggle-collapse')[bool ? 'show' : 'hide']();
this.find('.toggle-expand')[bool ? 'hide' : 'show']();
// If an alternative collapsed view exists, toggle it as well
var collapsedContent = this.find('.cms-panel-content-collapsed');
if(collapsedContent.length) {
this.find('.cms-panel-content')[bool ? 'show' : 'hide']();
this.find('.cms-panel-content-collapsed')[bool ? 'hide' : 'show']();
}
this.trigger('toggle');
},
expandPanel: function() {
this.togglePanel(true);
},
collapsePanel: function() {
this.togglePanel(false);
}
});
$('.cms-panel *').entwine({
getPanel: function() {
return this.parents('.cms-panel:first');
}
});
$('.cms-panel .toggle-expand').entwine({
onclick: function(e) {
e.preventDefault();
this.getPanel().expandPanel();
}
});
$('.cms-panel .toggle-collapse').entwine({
onclick: function(e) {
this.getPanel().collapsePanel();
return false;
}
});
});
}(jQuery));

View File

@ -0,0 +1,50 @@
/**
* File: LeftAndMain.EditForm.js
*/
(function($) {
$.entwine('ss', function($){
$('.cms-container').entwine(/** @lends ss.Form_EditForm */{
/**
* Variable: PingIntervalSeconds
* (Number) Interval in which /Security/ping will be checked for a valid login session.
*/
PingIntervalSeconds: 5*60,
// onmatch: function() {
// this._super();
//
// this._setupPinging();
// },
/**
* Function: _setupPinging
*
* This function is called by prototype when it receives notification that the user was logged out.
* It uses /Security/ping for this purpose, which should return '1' if a valid user session exists.
* It redirects back to the login form if the URL is either unreachable, or returns '0'.
*/
_setupPinging: function() {
var onSessionLost = function(xmlhttp, status) {
if(xmlhttp.status > 400 || xmlhttp.responseText == 0) {
// TODO will pile up additional alerts when left unattended
if(window.open('Security/login')) {
alert("Please log in and then try again");
} else {
alert("Please enable pop-ups for this site");
}
}
};
// setup pinging for login expiry
setInterval(function() {
jQuery.ajax({
url: "Security/ping",
global: false,
complete: onSessionLost
});
}, this.getPingIntervalSeconds() * 1000);
}
});
});
}(jQuery));

View File

@ -1,7 +1,10 @@
(function($) { (function($) {
$.entwine('ss', function($){
$('.LeftAndMain .cms-preview').entwine({
$.entwine('ss', function($){
$('.cms-preview').entwine({
// Minimum width to keep the CMS operational
SharedWidth: null, SharedWidth: null,
onmatch: function() { onmatch: function() {
@ -17,19 +20,32 @@
this.setSharedWidth(500); this.setSharedWidth(500);
// Create layout and controls // Create layout and controls
this.prepend('<div class="cms-preview-toggle west"><a href="#">&lt;</a></div>'); this.prepend('<div class="cms-preview-toggle west"><a href="#">&laquo;</a></div>');
this.find('iframe').addClass('center'); this.find('iframe').addClass('center');
this.layout({type: 'border'}); this.layout({type: 'border'});
this.find('iframe').bind('load', function() {self._fixIframeLinks();}); this.find('iframe').bind('load', function() {
self._fixIframeLinks();
self.loadCurrentPage();
});
self._fixIframeLinks(); self._fixIframeLinks();
// Limit to CMS forms for the moment
$('.cms-edit-form').bind('loadnewpage', function(e, ui) { $('.cms-edit-form').bind('loadnewpage', function(e, ui) {
// var url = ui.xmlhttp.getResponseHeader('x-frontend-url'); // var url = ui.xmlhttp.getResponseHeader('x-frontend-url');
var url = $(this).find(':input[name=StageURLSegment]').val(); var url = $(this).find(':input[name=StageURLSegment]').val();
if(url) self.loadUrl(url); if(url) self.loadUrl(url + '&cms-preview-disabled=1');
}); });
$('.cms-container').bind('afterstatechange', function(e) {
// var url = ui.xmlhttp.getResponseHeader('x-frontend-url');
var url = $('.cms-edit-form').find(':input[name=StageURLSegment]').val();
if(url) self.loadUrl(url + '&cms-preview-disabled=1');
});
if(this.hasClass('is-expanded')) this.expand();
else this.collapse();
this._super(); this._super();
}, },
@ -37,6 +53,22 @@
this.find('iframe').attr('src', url); this.find('iframe').attr('src', url);
}, },
loadCurrentPage: function() {
var doc = this.find('iframe')[0].contentDocument,
containerEl = this.getLayoutContainer(),
contentEl = containerEl.find('.cms-content');
// Only load if we're in the "edit page" view
if(!contentEl.hasClass('CMSMain') || contentEl.hasClass('CMSPagesController') || contentEl.hasClass('CMSSettingsController')) return;
// Load this page in the admin interface if appropriate
var id = $(doc).find('meta[name=x-page-id]').attr('content'), contentPanel = $('.cms-content');
// TODO Remove hardcoding
if(id && contentPanel.find(':input[name=ID]').val() != id) {
window.History.pushState({}, '', 'admin/page/edit/show/' + id);
}
},
_fixIframeLinks: function() { _fixIframeLinks: function() {
var doc = this.find('iframe')[0].contentDocument; var doc = this.find('iframe')[0].contentDocument;
@ -46,64 +78,63 @@
var href = links[i].getAttribute('href'); var href = links[i].getAttribute('href');
if (href && href.match(/^http:\/\//)) { if (href && href.match(/^http:\/\//)) {
links[i].setAttribute('href', 'javascript:false'); links[i].setAttribute('href', 'javascript:false');
} else {
links[i].setAttribute('href', href + '?cms-preview-disabled=1');
} }
} }
},
// Load this page in the admin interface if appropriate expand: function() {
var id = $(doc).find('meta[name=x-page-id]').attr('content'), form = $('.cms-edit-form'); var self = this, containerEl = this.getLayoutContainer(), contentEl = containerEl.find('.cms-content');
// TODO Remove hardcoding this.removeClass('east').addClass('center').removeClass('is-collapsed');
if(id && form.find(':input[name=ID]').val() != id) form.loadForm('admin/page/edit/show/' + id); // this.css('overflow', 'auto');
contentEl.removeClass('center').hide();
this.find('iframe').show();
containerEl.find('.cms-menu').collapsePanel();
this.find('.cms-preview-toggle a').html('&raquo;');
containerEl.redraw();
},
collapse: function() {
var self = this, containerEl = this.getLayoutContainer(), contentEl = containerEl.find('.cms-content');
this.addClass('east').removeClass('center').addClass('is-collapsed').width(10);
// this.css('overflow', 'hidden');
contentEl.addClass('center').show();
this.find('iframe').hide();
containerEl.find('.cms-menu').expandPanel();
this.find('.cms-preview-toggle a').html('&laquo;');
containerEl.redraw();
},
getLayoutContainer: function() {
return this.parents('.cms-container');
}, },
toggle: function(bool) { toggle: function(bool) {
var self = this, this[this.hasClass('is-collapsed') ? 'expand' : 'collapse']();
width = this.width(),
relayout = function() {$('.cms-container').layout({resize: false});},
minWidth = this.find('.cms-preview-toggle').width(),
wasCollapsed = (bool === true || bool === false) ? bool : (width <= minWidth),
newWidth = wasCollapsed ? this.getSharedWidth() : minWidth,
newOverflow = wasCollapsed ? 'auto' : 'hidden';
this.css('overflow', newOverflow).width(newWidth);
this.toggleClass('collapsed', !wasCollapsed).toggleClass('expanded', wasCollapsed);
this.find('iframe').toggle(wasCollapsed);
relayout();
// this.css('overflow', newOverflow).animate(
// {width: newWidth+'px'},
// {
// duration: 500,
// complete: function() {
// relayout();
// self.toggleClass('collapsed', !wasCollapsed).toggleClass('expanded', wasCollapsed);
// self.find('iframe').toggle(wasCollapsed);
// },
// step: relayout
// }
// );
} }
}); });
$('.LeftAndMain .cms-preview.collapsed').entwine({ $('.cms-preview.collapsed').entwine({
onmatch: function() { onmatch: function() {
this.find('a').text('<'); this.find('a').text('<');
} }
}); });
$('.LeftAndMain .cms-preview.expanded').entwine({ $('.cms-preview.expanded').entwine({
onmatch: function() { onmatch: function() {
this.find('a').text('>'); this.find('a').text('>');
} }
}); });
$('.LeftAndMain .cms-preview .cms-preview-toggle').entwine({ $('.cms-preview .cms-preview-toggle').entwine({
onclick: function(e) { onclick: function(e) {
e.preventDefault(); e.preventDefault();
this.parents('.cms-preview').toggle(); this.parents('.cms-preview').toggle();
} }
}); });
$('.LeftAndMain .cms-switch-view a').entwine({ $('.cms-switch-view a').entwine({
onclick: function(e) { onclick: function(e) {
e.preventDefault(); e.preventDefault();
var preview = $('.cms-preview'); var preview = $('.cms-preview');
@ -111,5 +142,16 @@
preview.loadUrl($(e.target).attr('href')); preview.loadUrl($(e.target).attr('href'));
} }
}); });
$('.cms-menu li').entwine({
onclick: function(e) {
// Prevent reloading of interface when opening the edit panel
if(this.hasClass('Menu-CMSMain')) {
var preview = $('.cms-preview');
preview.toggle(true);
e.preventDefault();
}
}
});
}); });
}(jQuery)); }(jQuery));

View File

@ -31,8 +31,6 @@
}); });
/** /**
* Class: .LeftAndMain
*
* Main LeftAndMain interface with some control panel and an edit form. * Main LeftAndMain interface with some control panel and an edit form.
* *
* Events: * Events:
@ -40,13 +38,9 @@
* validate - ... * validate - ...
* loadnewpage - ... * loadnewpage - ...
*/ */
$('.LeftAndMain').entwine({ $('.cms-container').entwine({
/** CurrentXHR: null,
* Variable: PingIntervalSeconds
* (Number) Interval in which /Security/ping will be checked for a valid login session.
*/
PingIntervalSeconds: 5*60,
/** /**
* Constructor: onmatch * Constructor: onmatch
@ -65,66 +59,96 @@
} }
// Initialize layouts, inner to outer // Initialize layouts, inner to outer
var doInnerLayout = function() {$('.cms-content').layout();} this.redraw();
var outer = $('.cms-container'); $(window).resize(function() {self.redraw()});
var doOuterLayout = function() {outer.layout({resize: false});}
doInnerLayout();
doOuterLayout();
$(window).resize(doOuterLayout);
// Remove loading screen // Remove loading screen
$('.ss-loading-screen').hide(); $('.ss-loading-screen').hide();
$('body').removeClass('loading'); $('body').removeClass('loading');
$(window).unbind('resize', positionLoadingSpinner); $(window).unbind('resize', positionLoadingSpinner);
this._setupPinging(); $('.cms-edit-form').live('loadnewpage', function() {self.redraw()});
$('.cms-edit-form').live('loadnewpage', function() { History.Adapter.bind(window,'statechange',function(){
doInnerLayout(); self.handleStateChange();
doOuterLayout();
}); });
this._super(); this._super();
}, },
redraw: function() {
// Not all edit forms are layouted
var editForm = $('.cms-edit-form[data-layout]').layout();
$('.cms-content').layout();
$('.cms-container').layout({resize: false})
},
/** /**
* Function: _setupPinging * Handles ajax loading of new panels through the window.History object.
* To trigger loading, pass a new URL to window.History.pushState().
* *
* This function is called by prototype when it receives notification that the user was logged out. * Due to the nature of history management, no callbacks are allowed.
* It uses /Security/ping for this purpose, which should return '1' if a valid user session exists. * Use the 'beforestatechange' and 'afterstatechange' events instead,
* It redirects back to the login form if the URL is either unreachable, or returns '0'. * or overwrite the beforeLoad() and afterLoad() methods on the
* DOM element you're loading the new content into.
* Although you can pass data into pushState(), it shouldn't contain
* DOM elements or callback closures.
*
* The passed URL should allow reconstructing important interface state
* without additional parameters, in the following use cases:
* - Explicit loading through History.pushState()
* - Implicit loading through browser navigation event triggered by the user (forward or back)
* - Full window refresh without ajax
* For example, a ModelAdmin search event should contain the search terms
* as URL parameters, and the result display should automatically appear
* if the URL is loaded without ajax.
*
* Alternatively, you can load new content via $('.cms-content').loadForm(<url>).
* In this case, the action won't be recorded in the browser history.
*/ */
_setupPinging: function() { handleStateChange: function() {
var onSessionLost = function(xmlhttp, status) { var self = this, h = window.History, state = h.getState();
if(xmlhttp.status > 400 || xmlhttp.responseText == 0) {
// TODO will pile up additional alerts when left unattended
if(window.open('Security/login')) {
alert("Please log in and then try again");
} else {
alert("Please enable pop-ups for this site");
}
}
};
// setup pinging for login expiry // Don't allow parallel loading to avoid edge cases
setInterval(function() { if(this.getCurrentXHR()) this.getCurrentXHR().abort();
jQuery.ajax({
url: "Security/ping", var contentEl = $(state.data.selector || '.cms-content');
global: false, this.trigger('beforestatechange', {state: state});
complete: onSessionLost contentEl.beforeLoad(state.url);
var xhr = $.ajax({
url: state.url,
success: function(data, status, xhr) {
// Update title
var title = xhr.getResponseHeader('X-Title');
if(title) document.title = title;
// Update panels
contentEl.afterLoad(data, status, xhr);
self.redraw();
self.trigger('afterstatechange', {data: data, status: status, xhr: xhr});
}
}); });
}, this.getPingIntervalSeconds() * 1000); this.setCurrentXHR(xhr);
}
});
/**
* Monitor all panels for layout changes
*/
$('.cms-panel').entwine({
ontoggle: function(e) {
this.parents('.cms-container').redraw();
} }
}); });
/** /**
* Class: .LeftAndMain :submit, .LeftAndMain button, .LeftAndMain :reset
*
* Make all buttons "hoverable" with jQuery theming. * Make all buttons "hoverable" with jQuery theming.
* Also sets the clicked button on a form submission, making it available through * Also sets the clicked button on a form submission, making it available through
* a new 'clickedButton' property on the form DOM element. * a new 'clickedButton' property on the form DOM element.
*/ */
$('.LeftAndMain :submit, .LeftAndMain button, .LeftAndMain :reset').entwine({ $('.cms-container :submit, .cms-container button, .cms-container :reset').entwine({
onmatch: function() { onmatch: function() {
// TODO Adding classes in onmatch confuses entwine // TODO Adding classes in onmatch confuses entwine
var self = this; var self = this;
@ -139,7 +163,7 @@
* *
* Link for editing the profile for a logged-in member through a modal dialog. * Link for editing the profile for a logged-in member through a modal dialog.
*/ */
$('.LeftAndMain .profile-link').entwine({ $('.cms-container .profile-link').entwine({
/** /**
* Constructor: onmatch * Constructor: onmatch
@ -281,7 +305,7 @@
* the DOM element on creation, rather than onclick - which allows us to decorate * the DOM element on creation, rather than onclick - which allows us to decorate
* the field with a calendar icon * the field with a calendar icon
*/ */
$('.LeftAndMain .field.date input.text').entwine({ $('.cms-container .field.date input.text').entwine({
onmatch: function() { onmatch: function() {
var holder = $(this).parents('.field.date:first'), config = holder.metadata({type: 'class'}); var holder = $(this).parents('.field.date:first'), config = holder.metadata({type: 'class'});
if(!config.showcalendar) return; if(!config.showcalendar) return;
@ -300,6 +324,7 @@
}) })
}); });
}(jQuery)); }(jQuery));
// Backwards compatibility // Backwards compatibility

View File

@ -66,6 +66,8 @@
redraw: function() { redraw: function() {
this.find('.historyNav .forward').toggle(Boolean(this.getFuture().length > 0)); this.find('.historyNav .forward').toggle(Boolean(this.getFuture().length > 0));
this.find('.historyNav .back').toggle(Boolean(this.getHistory().length > 1)); this.find('.historyNav .back').toggle(Boolean(this.getHistory().length > 1));
this._super();
}, },
/** /**
@ -116,7 +118,7 @@
this.trigger('historyGoBack', {url:previousPage}); this.trigger('historyGoBack', {url:previousPage});
// load new location // load new location
$('.cms-edit-form').loadForm(previousPage); $('.cms-content').loadForm(previousPage);
this.redraw(); this.redraw();
} }
@ -136,7 +138,7 @@
this.trigger('historyGoForward', {url:nextPage}); this.trigger('historyGoForward', {url:nextPage});
// load new location // load new location
$('.cms-edit-form').loadForm(nextPage); $('.cms-content').loadForm(nextPage);
this.redraw(); this.redraw();
} }

View File

@ -71,8 +71,9 @@
var btn = $(this[0].clickedButton); var btn = $(this[0].clickedButton);
btn.addClass('loading'); btn.addClass('loading');
$('.cms-edit-form').loadForm( $('.cms-content').loadForm(
this.attr('action'), this.attr('action'),
null,
function() { function() {
btn.removeClass('loading'); btn.removeClass('loading');
}, },
@ -135,7 +136,8 @@
onclick: function(e) { onclick: function(e) {
var firstLink = this.find('a[href]'); var firstLink = this.find('a[href]');
if(!firstLink) return; if(!firstLink) return;
$('.cms-edit-form').loadForm(firstLink.attr('href'));
window.History.pushState({selector: '.cms-content-fields form:first'}, '', firstLink.attr('href'));
return false; return false;
} }
}); });
@ -153,8 +155,9 @@
className = $('select option:selected', this).val(); className = $('select option:selected', this).val();
requestPath = this.attr('action').replace('ManagedModelsSelect', className + '/add'); requestPath = this.attr('action').replace('ManagedModelsSelect', className + '/add');
var $button = $(':submit', this); var $button = $(':submit', this);
$('.cms-edit-form').loadForm( $('.cms-content').loadForm(
requestPath, requestPath,
null,
function() { function() {
$button.removeClass('loading'); $button.removeClass('loading');
$button = null; $button = null;

View File

@ -3,19 +3,26 @@
* It is an addition to the base styles defined in sapphire/css/Form.css. * It is an addition to the base styles defined in sapphire/css/Form.css.
*/ */
/** ----------------------------------------------------
* Basic form fields
* ---------------------------------------------------- */
.field { .field {
display: block; display: block;
padding: 10px 0; padding: 10px 0;
border-bottom: 1px solid $color-shadow-light; border-bottom: 1px solid $color-shadow-light;
overflow: hidden;
label { label.left {
float: left; float: left;
width: 10em; width: 170px;
padding: 8px 20px 8px 4px;
line-height: $font-base-lineheight;
} }
// Don't float inner/contained fields // Don't float inner/contained fields
.middleColumn { .middleColumn {
margin-left: 10em; margin-left: 15em;
.field { .field {
display: inline; display: inline;
@ -54,50 +61,104 @@ form.nostyle {
} }
} }
input, textarea { .field.text input, textarea {
@include border-radius(5px); @include border-radius(4px);
background: #fff;
@include linear-gradient(color-stops( @include linear-gradient(color-stops(
$color-widget-bg, #efefef,
lighten($color-widget-bg, 10%), #fff 10%,
$color-widget-bg #fff 90%,
#efefef
)); ));
border: 1px solid $color-shadow-light; border: 1px solid lighten($color-medium-separator, 20%);
padding: 3px; padding: 7px;
} }
input.loading, /** ----------------------------------------------------
input.ui-state-default.loading, .ui-widget-content input.ui-state-default.loading, * Buttons
.ui-widget-header input.ui-state-default.loading { * ---------------------------------------------------- */
.cms {
input.loading,
input.ui-state-default.loading, .ui-widget-content input.ui-state-default.loading,
.ui-widget-header input.ui-state-default.loading {
padding-left: 16px; padding-left: 16px;
background: $color-widget-bg url(../../images/network-save.gif) no-repeat center left; background: $color-widget-bg url(../../images/network-save.gif) no-repeat center left;
} }
// Buttons .ss-ui-button.ss-ui-action-constructive,
.ss-ui-button.ss-ui-action-constructive, .ui-widget-content .ss-ui-button.ss-ui-action-constructive,
.ui-widget-content .ss-ui-button.ss-ui-action-constructive, .ui-widget-header .ss-ui-button.ss-ui-action-constructive {
.ui-widget-header .ss-ui-button.ss-ui-action-constructive { padding-left: 23px;
background: none; // avoid overwritten gradient from jQuery UI styles
@include linear-gradient(color-stops(
$color-button-constructive,
darken($color-button-constructive, 20%)
));
color: $color-text-light; color: $color-text-light;
} border-color: $color-button-constructive-border;
@include background(image-url("../images/btn_icons_sprite.png") no-repeat 5px 6px,
linear-gradient(color-stops(
$color-button-constructive-light,
$color-button-constructive-dark
))
);
background-color: $color-button-constructive-light;
@include text-shadow(darken($color-base, 40%) 1px 1px 0);
@include box-shadow(darken($color-base, 20%) 1px 1px 2px);
}
.ss-ui-button.ss-ui-action-destructive, .ss-ui-button.ss-ui-action-constructive.ui-state-hover {
.ui-widget-content .ss-ui-button.ss-ui-action-destructive, @include background(image-url("../images/btn_icons_sprite.png") no-repeat 5px 6px,
.ui-widget-header .ss-ui-button.ss-ui-action-destructive { linear-gradient(color-stops(
darken($color-button-constructive-light, 2%),
darken($color-button-constructive-dark, 3%)
))
);
background-color: $color-button-constructive-dark;
@include box-shadow(darken($color-base, 10%) 1px 1px 1px);
}
.ss-ui-button.ss-ui-action-constructive.cms-page-add-button {
background-position: 5px -155px;
}
.ss-ui-button.ss-ui-action-destructive,
.ui-widget-content .ss-ui-button.ss-ui-action-destructive,
.ui-widget-header .ss-ui-button.ss-ui-action-destructive {
color: $color-button-destructive; color: $color-button-destructive;
} background-color: $color-button-generic-light;
}
.ss-ui-button.ss-ui-action-minor, .ss-ui-button.ss-ui-action-destructive.delete {
.ui-widget-content .ss-ui-button.ss-ui-action-minor padding-left: 23px;
.ui-widget-header .ss-ui-button.ss-ui-action-minor { color: $color-button-destructive;
border-color: $color-button-generic-border;
@include background(image-url("../images/btn_icons_sprite.png") no-repeat 5px -26px,
linear-gradient(color-stops(
$color-button-generic-light,
$color-button-generic-dark
))
);
@include text-shadow(none);
@include box-shadow(darken($color-base, 2%) 1px 1px 2px);
}
.ss-ui-button.ss-ui-action-destructive.delete.ui-state-hover {
@include background(image-url("../images/btn_icons_sprite.png") no-repeat 5px -26px,
linear-gradient(color-stops(
darken($color-button-generic-light, 2%),
darken($color-button-generic-dark, 3%)
))
);
background-color: $color-button-generic-dark;
@include box-shadow(darken($color-base, 10%) 1px 1px 1px);
}
.ss-ui-button.ss-ui-action-minor,
.ui-widget-content .ss-ui-button.ss-ui-action-minor
.ui-widget-header .ss-ui-button.ss-ui-action-minor {
background: none; background: none;
padding: 0; padding: 0;
border: 0; border: 0;
color: $color-text-dark; color: $color-text-dark;
text-decoration: underline; text-decoration: underline;
}
} }
.cms-edit-form { .cms-edit-form {
@ -105,24 +166,29 @@ input.ui-state-default.loading, .ui-widget-content input.ui-state-default.loadin
.text input, textarea { .text input, textarea {
width: 300px; width: 300px;
font-family: $font-family;
font-size: $font-base-size;
} }
// TODO Unclear if "button bar" concept is edit form specific
.Actions { .Actions {
text-align: right; text-align: right;
} }
} }
.cms-content-tools { /** ----------------------------------------------------
.field { * Specific field overrides
* ---------------------------------------------------- */
.htmleditor {
label { label {
display: block;
float: none; float: none;
width: auto; padding-bottom: 10px;
} }
.middleColumn { .middleColumn {
margin-left: 0; margin-left: 0px;
} clear: left;
} }
} }
@ -131,3 +197,7 @@ input.ui-state-default.loading, .ui-widget-content input.ui-state-default.loadin
display: none; display: none;
} }
} }
.action-hidden {
display: none;
}

View File

@ -21,9 +21,34 @@
a { a {
text-decoration: none; text-decoration: none;
} }
.cms-panel-content {
width: 250px; // avoids floating of elements when collapsed
}
// toggled via JS
&.collapsed {
width: 40px;
cursor: auto;
.cms-menu-list {
li span.text {
display: none;
}
li ul {
display: none;
}
}
&.cms-panel .cms-panel-content {
display: block; // override panel defaults
}
}
} }
.cms-menu-list { .cms-menu-list {
li { li {
a { a {
@ -35,14 +60,14 @@
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
text-shadow: lighten($color-base, 10%) 1px 1px 0; text-shadow: lighten($color-base, 5%) 1px 1px 0;
color: $color-text-dark; color: $color-text-dark;
padding: 5px; padding: 5px 5px 5px 12px; //left aligning with SS logo at top
background-color: $color-base; background-color: $color-base;
@include linear-gradient(color-stops( @include linear-gradient(color-stops(
$color-base, $color-base,
darken($color-base, 8%) darken($color-base, 12%)
)); ));
border-top: 1px solid lighten($color-base, 10%); border-top: 1px solid lighten($color-base, 10%);
@ -75,8 +100,8 @@
display: block; display: block;
float: left; float: left;
margin-right: 4px; margin-right: 4px;
@include sprite-background("icons-32.png"); //@include sprite-background("icons-32.png");
@include sprite-position(1, 1); //@include sprite-position(1, 1);
} }
.text { .text {
@ -105,7 +130,7 @@
background-color: darken($color-menu-button, 10%); background-color: darken($color-menu-button, 10%);
a { a {
font-size: $font-small-size; font-size: $font-base-size - 1;
padding: 0 10px 0 36px; padding: 0 10px 0 36px;
height: 32px; height: 32px;
line-height: 32px; line-height: 32px;
@ -140,4 +165,23 @@
} }
} }
} }
li#Menu-CMSMain a .icon {@include sprite-position(1, 1);}
li#Menu-CMSMain.current a .icon, li#Menu-CMSMain a:hover .icon {@include sprite-position(2, 1);}
li#Menu-AssetAdmin a .icon {@include sprite-position(1, 4);}
li#Menu-AssetAdmin.current a .icon, li#Menu-AssetAdmin a:hover .icon {@include sprite-position(2, 4);}
li#Menu-SecurityAdmin a .icon {@include sprite-position(1, 5);}
li#Menu-SecurityAdmin.current a .icon, li#Menu-SecurityAdmin a:hover .icon {@include sprite-position(2, 5);}
li#Menu-CMSPagesController a .icon {@include sprite-position(1, 2);}
li#Menu-CMSPagesController.current a .icon, li#Menu-CMSPagesController a:hover .icon {@include sprite-position(2, 2);}
&.collapsed {
li .text {
display: none;
}
li > li {
display: none;
}
}
} }

View File

@ -1,13 +1,8 @@
/** /**
* This file defines the 'theme' of the CMS: Colors, fonts, backgrounds, and detailed alignments. * This file defines most styles of the CMS: Colors, fonts, backgrounds, alignments, dimensions.
* Together with _layout.css it provides the presentational backbone to the CMS.
* Ideally a developer should be able to exchange this file with his own theme easily.
*
* Please don't put any dimension, display or float information on major structural components
* like '.cms-container' or '.cms-header' in here, use the _layout.scss file instead.
* *
* Use SCSS variable definitions in screen.css to avoid repeating styles like background colours * Use SCSS variable definitions in screen.css to avoid repeating styles like background colours
* or padding dimensions. See _colours.scss to get started. * or padding dimensions. See themes/_default.scss to get started.
* *
* To avoid this file getting too large and complicated, it is encouraged to create new SCSS files * To avoid this file getting too large and complicated, it is encouraged to create new SCSS files
* for larger components like the CMS menu or tree (see _tree.scss and _menu.scss). * for larger components like the CMS menu or tree (see _tree.scss and _menu.scss).
@ -39,6 +34,7 @@ a {
} }
} }
body .ui-widget { body .ui-widget {
font-family: $font-family;
font-size: $font-base-size; font-size: $font-base-size;
} }
@ -51,7 +47,8 @@ body .ui-widget {
.cms-content, .cms-content,
.cms-content-header, .cms-content-header,
.cms-content-tools, .cms-content-tools,
.cms-content-form { .cms-content-fields,
.cms-edit-form {
@include inline-block; @include inline-block;
} }
@ -60,24 +57,32 @@ strong {
font-weight: bold; font-weight: bold;
} }
// ######################### Misc Panels ######################### /** --------------------------------------------
* Misc Panels
* -------------------------------------------- */
.cms-content-header { .cms-content-header {
background-color: darken($color-widget-bg, 20%); background-color: darken($color-widget-bg, 20%);
padding: 8px; padding: 8px 8px 6px 8px;
height: 32px; height: 32px;
border-bottom: 2px solid darken($color-widget-bg, 35%);
@include linear-gradient(color-stops( @include linear-gradient(color-stops(
darken($color-widget-bg, 20%), darken($color-widget-bg, 5%),
darken($color-widget-bg, 30%) darken($color-widget-bg, 30%)
)); ));
border-bottom: 1px solid darken($color-widget-bg, 50%);
padding: 10px;
height: 32px;
h2 { h2 {
float: left; float: left;
padding: 8px; padding: 12px 0 0 8px;
font-size: 14px; font-size: $font-base-size;
font-weight: bold; font-weight: bold;
text-shadow: lighten($color-base, 10%) 1px 1px 0;
width: 250px - (10px*2); width: 250px - (10px*2);
} }
@ -93,39 +98,56 @@ strong {
.ui-tabs .cms-content-header { .ui-tabs .cms-content-header {
.ui-tabs-nav li { .ui-tabs-nav li {
height: 40px;
a { a {
font-weight: bold; font-weight: bold;
font-size: 11px; font-size: $font-base-size;
padding-top: 8px; padding: 11px 15px 9px;
border-bottom: 2px solid darken($color-tab, 15%);
} }
} }
.ui-state-default, .ui-state-default,
.ui-widget-content .ui-state-default, .ui-widget-content .ui-state-default,
.ui-widget-header .ui-state-default { .ui-widget-header .ui-state-default {
background-color: lighten($color-shadow-light, 20%); background-color: $color-tab;
@include linear-gradient(color-stops( @include linear-gradient(color-stops(
lighten($color-shadow-light, 20%), $color-tab,
lighten($color-shadow-light, 5%) darken($color-tab, 10%)
)); ));
border-color: darken($color-tab, 20%);
margin: 0 3px 0 0;
text-shadow: lighten($color-tab, 60%) 0 1px 0;
} }
.ui-state-active, .ui-state-active,
.ui-widget-content .ui-state-active, .ui-widget-content .ui-state-active,
.ui-widget-header .ui-state-active { .ui-widget-header .ui-state-active {
background: $color-widget-bg; background: $color-widget-bg;
a {
border-bottom: 2px solid $color-widget-bg;
}
} }
} }
.cms-content-tools { .cms-content-tools {
background-color: darken($color-widget-bg, 5%); background-color: darken($color-widget-bg, 5%);
padding: 10px; padding: 8px;
width: 230px; width: 230px;
overflow: auto; overflow: auto;
.cms-panel-header,
.cms-panel-content {
padding: 10px;
}
} }
.cms-content {
&.loading {
background: url(../images/spinner.gif) no-repeat 50% 50%;
}
}
/** ------------------------------------------------------- /** -------------------------------------------------------
* Top Left Header and logo area * Top Left Header and logo area
@ -181,24 +203,25 @@ strong {
.cms-login-status { .cms-login-status {
border-top: 1px solid $color-dark-separator; border-top: 1px solid $color-dark-separator;
height: 23px; height: 23px;
padding: 8px 0 0 14px; padding: 8px 4px 0 4px;
overflow: hidden; overflow: hidden;
line-height: 16px; line-height: 16px;
font-size: 11px; font-size: $font-base-size - 2;
.logout-link { .logout-link {
display: inline-block; display: inline-block;
height: 16px; height: 16px;
width: 16px; width: 16px;
float: left; float: left;
margin-right: 10px; margin: 0 15px 0 5px;
background: url(../images/logout.png) no-repeat; background: url(../images/logout.png) no-repeat;
text-indent: -9999em; text-indent: -9999em;
} }
} }
// ######################### Loading Screen ######################### /** -----------------------------------------------
* Loading Screen
* ------------------------------------------------ */
.ss-loading-screen, .ss-loading-screen,
.ss-loading-screen .loading-logo { .ss-loading-screen .loading-logo {
width: 100%; width: 100%;
@ -245,17 +268,20 @@ strong {
} }
} }
// ######################### Actions ######################### /** --------------------------------------------
* Actions
* -------------------------------------------- */
.cms-content-actions { .cms-content-actions {
border-top: 1px solid darken($color-widget-bg, 35%);
padding: 8px; padding: 8px;
background: transparent url(../images/textures/bg_cms_main_content.png) repeat top left;
} }
// ######################### Messages ######################### /** --------------------------------------------
* Messages
* -------------------------------------------- */
/**
* Messages (see sapphire/css/Form.css)
*/
.message { .message {
margin: 1em 0; margin: 1em 0;
padding: 0.5em; padding: 0.5em;
@ -277,7 +303,9 @@ strong {
} }
} }
// ######################### ModelAdmin ######################### /** --------------------------------------------
* ModelAdmin
* -------------------------------------------- */
.ModelAdmin { .ModelAdmin {
.cms-content-tools { .cms-content-tools {
@ -290,7 +318,10 @@ strong {
} }
} }
// ######################### "Add page" dialog ######################### /** --------------------------------------------
* "Add page" dialog
* -------------------------------------------- */
.cms-page-add-form-dialog { .cms-page-add-form-dialog {
#PageType li { #PageType li {
clear: left; clear: left;
@ -320,10 +351,23 @@ strong {
} }
} }
// ######################### Content toolbar ######################### /** --------------------------------------------
* Content toolbar
* -------------------------------------------- */
.cms-content-toolbar { .cms-content-toolbar {
@include clearfix;
display: block;
padding: 10px 0;
margin: 0 0 15px 0;
border-bottom-width: 2px;
border-bottom: 2px groove lighten($color-shadow-light, 95%);
-webkit-border-image: url(../images/textures/bg_fieldset_elements_border.png) 2 stretch stretch;
border-image: url(../images/textures/bg_fieldset_elements_border.png) 2 stretch stretch;
//TODO: use single border line with shadow instead:: http://daverupert.com/2011/06/two-tone-borders-with-css3/
& > * { & > * {
display: inline-block; float: left;
} }
.cms-tree-view-modes * { .cms-tree-view-modes * {
@ -335,10 +379,45 @@ strong {
} }
} }
// ######################### Preview header (remove before release) ######################### .cms-content-tools {
.field {
label {
float: none;
width: auto;
}
.middleColumn {
margin-left: 0;
}
}
}
.cms-content-batchactions, .cms-content-constructive-actions {
float: right;
}
.cms-content-batchactions {
float: right;
position: relative;
display: block;
margin-right: 8px;
}
form.cms-batch-actions {
float: left;
}
.cms-content-constructive-actions a {
display: block;
float: right;
}
/** --------------------------------------------
* Preview header (remove before release)
* -------------------------------------------- */
.cms-preview { .cms-preview {
width: 1px; // collapsed by default width: 1px; // collapsed by default
overflow: hidden;
.cms-preview-toggle { .cms-preview-toggle {
width: 10px; width: 10px;
@ -356,7 +435,9 @@ strong {
font-weight: bold; font-weight: bold;
} }
// ######################### Member Profile ######################### /** --------------------------------------------
* Member Profile
* -------------------------------------------- */
form.member-profile-form { form.member-profile-form {
@ -401,10 +482,71 @@ form.member-profile-form {
} }
.cms-content-form { .cms-content-fields {
overflow: auto; overflow: auto;
background: transparent url(../images/textures/bg_cms_main_content.png) repeat top left;
} }
/** --------------------------------------------
* Panels
* -------------------------------------------- */
.cms-panel {
overflow: hidden;
.toggle-expand,
.toggle-collapse {
display: block;
position: absolute;
bottom: 0;
text-align: right;
@include linear-gradient(color-stops(
darken($color-widget-bg, 20%),
darken($color-widget-bg, 30%)
));
text-decoration: none;
span {
display: inline-block;
margin: 5px;
color: $color-text-dark;
font-size: 16px;
}
}
.toggle-collapse {
width: 100%;
}
.toggle-expand {
width: 40px; // will set the collapsed width
}
&.collapsed {
.cms-panel-content {
display: none;
}
.cms-panel-header {
@include rotate(-90deg);
// TODO How to reflow container to correct height?
position: relative;
top: 100px;
}
}
}
.cms-content .cms-panel.collapsed {
cursor: pointer;
}
/** --------------------------------------------
* Other
* -------------------------------------------- */
.cms-preview { .cms-preview {
background-color: $color-base; background-color: $color-base;
@ -412,9 +554,25 @@ form.member-profile-form {
cursor: pointer; cursor: pointer;
a { a {
display: block;
width: 15px;
height: 15px;
position: relative;
left: 10px; // point right (width of toggle)
top: 48%;
background-color: $color-base;
color: $color-text-light; color: $color-text-light;
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
z-index: 2000;
}
}
&.is-collapsed {
.cms-preview-toggle {
a {
left: -15px; // point left
}
} }
} }
} }

View File

@ -32,6 +32,7 @@
height: 18px; height: 18px;
margin: 0 0 0 0; margin: 0 0 0 0;
padding: 0; padding: 0;
float: left;
} }
a { a {
display: inline-block; display: inline-block;
@ -364,3 +365,165 @@ li.jstree-closed > ul {
background: none; background: none;
} }
} }
.jstree li {
line-height: 25px;
}
.cms-tree.jstree-apple {
& li.Root {
& strong {
font-weight: bold;
padding-left: 1px;
}
& > a .jstree-icon {
background-position: -56px -36px;
}
}
& a, a:link {
color: $color-text-blue-link;
padding: 3px 6px 3px 3px;
border: none;
display: inline-block;
margin-right: 5px;
& span.status:after {
clear: both;
text-transform: uppercase;
display: inline-block;
padding: 0px 3px;
font-size: 0.75em;
line-height: 1em;
margin-left: 3px;
margin-right: 6px;
margin-top: -1px;
@include border-radius(2px, 2px);
}
}
& span.modified:after {
content: "draft";
color: #7E7470;
border: 1px solid #C9B800;
background-color: #FFF0BC;
}
& span.new:after {
content: "new";
color: #7E7470;
border: 1px solid #C9B800;
background-color: #FFF0BC;
}
& span.private:after {
content: "private";
color: #636363;
border: 1px solid #E49393;
background-color: #F2DADB;
}
& span.workflow-approval:after {
content: "awaiting approval";
color: #56660C;
border: 1px solid #7C8816;
background-color: #DAE79A;
}
/* comment speech bubble - ccs3 only - source: http://nicolasgallagher.com/pure-css-speech-bubbles/demo/ */
& span.comment-count {
clear: both;
position: relative;
text-transform: uppercase;
display: inline-block;
overflow: visible;
padding: 0px 3px;
font-size: 0.75em;
line-height: 1em;
margin-left: 3px;
margin-right: 6px;
@include border-radius(2px, 2px);
color: #7E7470;
border: 1px solid #C9B800;
background-color: #FFF0BC;
}
& span.comment-count:before {
content:"";
position:absolute;
bottom:-4px; /* value = - border-top-width - border-bottom-width */
left:3px; /* controls horizontal position */
border-width:4px 4px 0;
border-style:solid;
border-color:#C9B800 transparent;
/* reduce the damage in FF3.0 */
display:block;
width:0;
}
& span.comment-count:after {
content:"";
position:absolute;
bottom:-3px; /* value = - border-top-width - border-bottom-width */
left:4px; /* value = (:before left) + (:before border-left) - (:after border-left) */
border-width:3px 3px 0;
border-style:solid;
border-color:#FFF0BC transparent;
/* reduce the damage in FF3.0 */
display:block;
width:0;
}
.jstree-hovered {
text-shadow: none;
text-decoration: none;
}
& li {
padding: 0px;
clear: left;
}
& li, ins {
background-color: transparent;
background-image: url(../images/sitetree_ss_default_icons.png);
}
& li.jstree-checked a, li.jstree-checked a:link {
background-color: $color-cms-batchactions-menu-selected-background;
}
}
.jstree-apple #record-0.jstree-open > ins {
display: none;
}
a .jstree-pageicon {
display: block;
float: left;
width: 16px;
height: 16px;
margin-right: 4px;
background-color: transparent;
background-image: url(../images/sitetree_ss_pageclass_icons_default.png);
background-repeat: no-repeat;
}
li.class-HomePage a .jstree-pageicon {
background-position: 0 -48px;
}
li.class-RedirectorPage a .jstree-pageicon {
background-position: 0 -16px;
}
li.class-VirtualPage a .jstree-pageicon {
background-position: 0 -32px;
}
li.class-ErrorPage a .jstree-pageicon {
background-position: 0 -112px;
}

View File

@ -18,14 +18,30 @@
border: 0; border: 0;
background: none; background: none;
} }
.ui-tabs-nav {
margin: 0;
padding: 0;
li {
top: 0;
a {
padding: 0 15px;
}
}
&.ui-state-active {
border-color: $color-medium-separator;
}
}
} }
.ui-widget-content, .ui-widget-content,
.ui-tabs .ui-tabs-panel { .ui-tabs .ui-tabs-panel {
color: $color-text; color: $color-text;
font-size: 1em; font-size: $font-base-size;
border: 0; border: 0;
background: $color-widget-bg;
} }
.ui-widget-header { .ui-widget-header {
@ -38,4 +54,30 @@
padding: 5px; padding: 5px;
text-decoration: none; text-decoration: none;
} }
// Buttons
.ui-state-hover {
cursor: pointer;
}
.ss-ui-button,
.ui-widget-content .ss-ui-button,
.ui-widget-header .ss-ui-button {
padding: 5px 7px 5px 7px;
color: $color-text-dark;
@include background(image-url("../images/btn_icons_sprite.png") no-repeat 999px 999px,
linear-gradient(color-stops(
$color-button-generic-light,
$color-button-generic-dark
))
);
background-color: $color-button-generic-light;
@include box-shadow(darken($color-base, 20%) 1px 1px 2px);
}
}
.cms-content-form {
overflow: auto;
background: transparent url(../images/textures/bg_cms_main_content.png) repeat top left !important;
} }

View File

@ -13,6 +13,7 @@
@import "compass/reset"; @import "compass/reset";
@import "compass/css3"; @import "compass/css3";
@import "compass/utilities/sprites/sprite-img"; @import "compass/utilities/sprites/sprite-img";
@import "compass/utilities/general";
/** ----------------------------- /** -----------------------------
* Theme * Theme

View File

@ -1,8 +1,7 @@
/** /**
* This file contains the default theme definitions for the admin interface. * This file contains the default theme definitions for the admin interface.
* * Please put mostly SCSS variable definitions in here,
* @package sapphire * and leave the actual styling to _style.scss and auxilliary files.
* @subpackage admin
*/ */
/** ----------------------------------------------- /** -----------------------------------------------
@ -14,6 +13,9 @@ $color-widget-bg: lighten($color-base, 20%);
$color-dark-bg: #003050; $color-dark-bg: #003050;
$color-dark-separator: #19435c; $color-dark-separator: #19435c;
$color-medium-separator: #808080;
$color-tab: #d9d9d9;
$color-shadow-light: rgba(201, 205, 206, 0.8); $color-shadow-light: rgba(201, 205, 206, 0.8);
$color-shadow-dark: rgba(107, 120, 123, 0.5); $color-shadow-dark: rgba(107, 120, 123, 0.5);
@ -29,20 +31,29 @@ $color-text-light: white;
$color-text-light-link: white; $color-text-light-link: white;
$color-text-dark: #1f1f1f; $color-text-dark: #1f1f1f;
$color-text-dark-link: #3EBAE0; $color-text-dark-link: #3EBAE0;
$color-text-blue-link:#1556B2;
$color-button-constructive: #77b53f; $color-button-generic-dark: #c3c3c3;
$color-button-generic-light:#f5f5f5;
$color-button-generic-border: #ABABAB;
$color-button-constructive-dark: #128945;
$color-button-constructive-light:#84BE3F;
$color-button-constructive-border: #118021;
$color-button-destructive: #f00; $color-button-destructive: #f00;
$color-warning: #FF9300; $color-warning: #FF9300;
$color-error: #FF9300; $color-error: #FF9300;
$color-notice: #FF9300; $color-notice: #FF9300;
$color-cms-batchactions-menu-background: #f5f5f5;
$color-cms-batchactions-menu-selected-background: #efe999;
/** ----------------------------------------------- /** -----------------------------------------------
* Typography * Typography
* ------------------------------------------------ */ * ------------------------------------------------ */
$font-family: Verdana, Arial, sans-serif; $font-family: Arial, sans-serif;
$font-base-size: 13px; $font-base-size: 13px;
$font-small-size: 11px;
$font-base-lineheight: 16px; $font-base-lineheight: 16px;
/** ----------------------------------------------- /** -----------------------------------------------

View File

@ -1,33 +1,49 @@
/** /**
* This file contains the grayscale theme definitions for the admin interface. * Sample alternative theme without colors (grayscale only).
*
*
* @package sapphire
* @subpackage admin
*/ */
/** ----------------------------------------------- /** -----------------------------------------------
* Colours * Colours
* ------------------------------------------------ */ * ------------------------------------------------ */
$color-base: grayscale(#B0BFC6); $color-base: grayscale(#b0bec7);
$color-widget-bg: grayscale(lighten($color-base, 20%)); $color-widget-bg: grayscale(lighten($color-base, 20%));
$color-dark-bg: grayscale(#003050); $color-dark-bg: grayscale(#003050);
$color-shadow-light: grayscale(#aaa); $color-dark-separator: grayscale(#19435c);
$color-shadow-dark: grayscale(#333);
$color-shadow-light: grayscale(rgba(201, 205, 206, 0.8));
$color-shadow-dark: grayscale(rgba(107, 120, 123, 0.5));
$color-highlight: grayscale(#FFFF66); $color-highlight: grayscale(#FFFF66);
$color-menu-button: grayscale(#338DC1); $color-menu-button: grayscale(#338DC1);
$color-text: grayscale(#444); $color-menu-background: grayscale(#c6d7df);
$color-menu-border: grayscale(#8c99a1);
$color-text: #444;
$color-text-light: white; $color-text-light: white;
$color-text-light-link: white; $color-text-light-link: white;
$color-text-dark: grayscale(#333); $color-text-dark: #1f1f1f;
$color-text-dark-link: grayscale(#3EBAE0); $color-text-dark-link: grayscale(#3EBAE0);
$color-button-constructive: grayscale(#77b53f);
$color-button-destructive: grayscale(#f00); $color-button-constructive: #77b53f;
$color-warning: grayscale(#FF9300); $color-button-destructive: #f00;
$color-error: grayscale(#FF9300);
$color-notice: grayscale(#FF9300); $color-warning: #FF9300;
$color-error: #FF9300;
$color-notice: #FF9300;
/** ----------------------------------------------- /** -----------------------------------------------
* Typography * Typography
* ------------------------------------------------ */ * ------------------------------------------------ */
$default-fonts: Verdana, Arial, sans-serif; $font-family: Arial, sans-serif;
$font-base-size: 13px;
$font-base-lineheight: 16px;
/** -----------------------------------------------
* Application Logo (CMS Logo)
* ------------------------------------------------ */
$application-logo-small: image-url("logo_small.png");
$application-logo-small-ysize: 25px;
$application-logo-small-xsize: 25px;

View File

@ -2,9 +2,9 @@
<form $FormAttributes data-layout="{type: 'border'}"> <form $FormAttributes data-layout="{type: 'border'}">
<% end_if %> <% end_if %>
<div class="cms-content-header north"> <div class="cms-content-header north">
<div> <div>
<h2>My Page Title</h2> <h2> My Page Title</h2>
<% if Fields.hasTabset %> <% if Fields.hasTabset %>
<% with Fields.fieldByName('Root') %> <% with Fields.fieldByName('Root') %>
<div class="cms-content-header-tabs"> <div class="cms-content-header-tabs">
@ -19,13 +19,13 @@
<!-- <div class="cms-content-search">...</div> --> <!-- <div class="cms-content-search">...</div> -->
</div> </div>
</div> </div>
<!-- <div class="cms-content-tools west"> <div class="cms-content-fields center">
<!-- <div class="cms-content-tools west">
$Left $Left
</div> --> </div> -->
<div class="cms-content-form center">
<% if Message %> <% if Message %>
<p id="{$FormName}_error" class="message $MessageType">$Message</p> <p id="{$FormName}_error" class="message $MessageType">$Message</p>
@ -41,9 +41,9 @@
<div class="clear"><!-- --></div> <div class="clear"><!-- --></div>
</fieldset> </fieldset>
</div> </div>
<div class="cms-content-actions south"> <div class="cms-content-actions south">
<% if Actions %> <% if Actions %>
<div class="Actions"> <div class="Actions">
<% control Actions %> <% control Actions %>
@ -51,7 +51,7 @@
<% end_control %> <% end_control %>
</div> </div>
<% end_if %> <% end_if %>
</div> </div>
<% if IncludeFormTag %> <% if IncludeFormTag %>
</form> </form>

View File

@ -1,4 +1,6 @@
<div class="cms-menu west"> <div class="cms-menu cms-panel west">
<div class="cms-panel-content">
<div class="cms-header"> <div class="cms-header">
<div class="cms-logo"> <div class="cms-logo">
@ -22,23 +24,23 @@
<ul class="cms-menu-list"> <ul class="cms-menu-list">
<% control MainMenu %> <% control MainMenu %>
<li class="$LinkingMode $FirstLast" id="Menu-$Code"> <li class="$LinkingMode $FirstLast <% if LinkingMode == 'current' %>opened<% end_if %>" id="Menu-$Code">
<a href="$Link"> <a href="$Link">
<span class="icon">&nbsp;</span> <span class="icon">&nbsp;</span>
<span class="text">$Title</span> <span class="text">$Title</span>
</a> </a>
<% if Code == 'CMSMain' && LinkingMode == 'current' %> <% if Code == 'CMSMain' %>
<ul> <ul>
<li class="first <% if Top.class == 'CMSPageEditController' %>current<% end_if %>"><a href="admin/page/edit/show/$Top.CurrentPageID"> <li class="first <% if Top.class == 'CMSPageEditController' || Top.class == 'CMSMain' %>current<% end_if %>" id="Menu-CMSPageEditController"><a href="admin/page/edit/show/$Top.CurrentPageID">
<span class="text">Content</span> <span class="text">Content</span>
</a></li> </a></li>
<li <% if Top.class == 'CMSPageSettingsController' %>class="current"<% end_if %>><a href="admin/page/settings/show/$Top.CurrentPageID"> <li <% if Top.class == 'CMSPageSettingsController' %>class="current"<% end_if %> id="Menu-CMSPageSettingsController"><a href="admin/page/settings/show/$Top.CurrentPageID">
<span class="text">Settings</span> <span class="text">Settings</span>
</a></li> </a></li>
<li <% if Top.class == 'CMSPageReportsController' %>class="current"<% end_if %>><a href="admin/page/reports/show/$Top.CurrentPageID"> <li <% if Top.class == 'CMSPageReportsController' %>class="current"<% end_if %> id="Menu-CMSPageReportsController"><a href="admin/page/reports/show/$Top.CurrentPageID">
<span class="text">Reports</span> <span class="text">Reports</span>
</a></li> </a></li>
<li <% if Top.class == 'CMSPageHistoryController' %>class="current"<% end_if %>><a href="admin/page/history/show/$Top.CurrentPageID"> <li <% if Top.class == 'CMSPageHistoryController' %>class="current"<% end_if %> id="Menu-CMSPageHistoryController"><a href="admin/page/history/show/$Top.CurrentPageID">
<span class="text">History</span> <span class="text">History</span>
</a></li> </a></li>
</ul> </ul>
@ -47,4 +49,6 @@
<% end_control %> <% end_control %>
</ul> </ul>
</div>
</div> </div>

View File

@ -1,4 +1,4 @@
<div class="cms-content center" data-layout="{type: 'border'}"> <div class="cms-content center $BaseCSSClasses" data-layout="{type: 'border'}">
<div class="cms-content-header north"> <div class="cms-content-header north">
<div> <div>
@ -6,9 +6,11 @@
</div> </div>
</div> </div>
<div class="cms-content-tools west cms-panel" data-expandOnClick="true">
<div class="cms-content-tools west"> <h3 class="cms-panel-header">Filter</h3>
<div class="cms-panel-content">
<div id="SearchForm_holder" class="leftbottom ss-tabset"> <div id="SearchForm_holder" class="leftbottom ss-tabset">
<% if SearchClassSelector = tabs %> <% if SearchClassSelector = tabs %>
<ul> <ul>
@ -35,10 +37,11 @@
</div> </div>
<% end_control %> <% end_control %>
</div> </div>
</div>
</div> </div>
<div class="cms-content-form center ui-widget-content"> <div class="cms-content-fields center ui-widget-content">
$EditForm $EditForm
</div> </div>

View File

@ -1,4 +1,4 @@
<div class="cms-content center" data-layout="{type: 'border'}"> <div class="cms-content center $BaseCSSClasses" data-layout="{type: 'border'}">
<div class="cms-content-header north"> <div class="cms-content-header north">
<div> <div>
@ -31,7 +31,7 @@
</div> </div>
<div class="cms-content-form center ui-widget-content"> <div class="cms-content-fields center ui-widget-content">
$EditForm $EditForm
</div> </div>

View File

@ -4,10 +4,10 @@
<meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-language" content="$i18nLocale" /> <meta http-equiv="Content-language" content="$i18nLocale" />
<% base_tag %> <% base_tag %>
<title>$ApplicationName | $SectionTitle</title> <title>$Title</title>
</head> </head>
<body class="loading cms $CSSClasses"> <body class="loading cms">
<% include CMSLoadingScreen %> <% include CMSLoadingScreen %>
@ -25,11 +25,9 @@
$Content $Content
<% if currentPage %> <div class="cms-preview east <% if IsPreviewExpanded %>is-expanded<% else %>is-collapsed<% end_if %>">
<div class="cms-preview east"> <iframe src="$PreviewLink"></iframe>
<iframe src="$currentPage.Link/?stage=Stage"></iframe>
</div> </div>
<% end_if %>
</div> </div>

View File

@ -0,0 +1,8 @@
---
format: 1
handler:
commit: 861b4b1f7240b9d5e50d560ba5b94de78aa439e5
branch: master
lock: false
repository_class: Piston::Git::Repository
repository_url: https://github.com/balupton/history.js.git

311
admin/thirdparty/history-js/README.md vendored Normal file
View File

@ -0,0 +1,311 @@
Welcome to History.js (v1.7.0 - April 01 2011)
==================
This project is the successor of [jQuery History](http://balupton.com/projects/jquery-history), it aims to:
- Follow the [HTML5 History API](https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history) as much as possible
- Provide a cross-compatible experience for all HTML5 Browsers (they all implement the HTML5 History API a little bit differently causing different behaviours and sometimes bugs - History.js fixes this ensuring the experience is as expected / the same / great throughout the HTML5 browsers)
- Provide a backwards-compatible experience for all HTML4 Browsers using a hash-fallback (including continued support for the HTML5 History API's `data`, `title`, `pushState` and `replaceState`) with the option to [remove HTML4 support if it is not right for your application](https://github.com/balupton/History.js/wiki/Intelligent-State-Handling)
- Provide a forwards-compatible experience for HTML4 States to HTML5 States (so if a hash-fallbacked url is accessed by a HTML5 browser it is naturally transformed into its non-hashed url equivalent)
- Provide support for as many javascript frameworks as possible via adapters; especially [jQuery](http://jquery.com/), [MooTools](http://mootools.net/), [Prototype](http://www.prototypejs.org/) and [Zepto](http://zeptojs.com/)
Licensed under the [New BSD License](http://creativecommons.org/licenses/BSD/)
Copyright 2011 [Benjamin Arthur Lupton](http://balupton.com)
## Usage
### Working with History.js:
(function(window,undefined){
// Prepare
var History = window.History; // Note: We are using a capital H instead of a lower h
if ( !History.enabled ) {
// History.js is disabled for this browser.
// This is because we can optionally choose to support HTML4 browsers or not.
return false;
}
// Bind to StateChange Event
History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
var State = History.getState(); // Note: We are using History.getState() instead of event.state
History.log(State.data, State.title, State.url);
});
// Change our States
History.pushState({state:1}, "State 1", "?state=1"); // logs {state:1}, "State 1", "?state=1"
History.pushState({state:2}, "State 2", "?state=2"); // logs {state:2}, "State 2", "?state=2"
History.replaceState({state:3}, "State 3", "?state=3"); // logs {state:3}, "State 3", "?state=3"
History.pushState(null, null, "?state=4"); // logs {}, '', "?state=4"
History.back(); // logs {state:3}, "State 3", "?state=3"
History.back(); // logs {state:1}, "State 1", "?state=1"
History.back(); // logs {}, "Home Page", "?"
History.go(2); // logs {state:3}, "State 3", "?state=3"
})(window);
To ajaxify your entire website with the HTML5 History API, History.js and jQuery [this snippet of code](https://gist.github.com/854622) is all you need. It's that easy.
### How would the above operations look in a HTML5 Browser?
1. www.mysite.com
1. www.mysite.com/?state=1
1. www.mysite.com/?state=2
1. www.mysite.com/?state=3
1. www.mysite.com/?state=4
1. www.mysite.com/?state=3
1. www.mysite.com/?state=1
1. www.mysite.com
1. www.mysite.com/?state=3
> Note: These urls also work in HTML4 browsers and Search Engines. So no need for the hashbang (`#!`) fragment-identifier that google ["recommends"](https://github.com/balupton/History.js/wiki/Intelligent-State-Handling).
### How would they look in a HTML4 Browser?
1. www.mysite.com
1. www.mysite.com/#?state=1&_suid=1
1. www.mysite.com/#?state=2&_suid=2
1. www.mysite.com/#?state=3&_suid=3
1. www.mysite.com/#?state=4
1. www.mysite.com/#?state=3&_suid=3
1. www.mysite.com/#?state=1&_suid=1
1. www.mysite.com
1. www.mysite.com/#?state=3&_suid=3
> Note 1: These urls also work in HTML5 browsers - we use `replaceState` to transform these HTML4 states into their HTML5 equivalents so the user won't even notice :-)
>
> Note 2: These urls will be automatically url-encoded in IE6 to prevent certain browser-specific bugs.
>
> Note 3: Support for HTML4 browsers (this hash fallback) is optional [- why supporting HTML4 browsers could be either good or bad based on my app's use cases](https://github.com/balupton/History.js/wiki/Intelligent-State-Handling)
### What's the deal with the SUIDs used in the HTML4 States?
- SUIDs (State Unique Identifiers) are used when we utilise a `title` and/or `data` in our state. Adding a SUID allows us to associate particular states with data and titles while keeping the urls as simple as possible (don't worry it's all tested, working and a lot smarter than I'm making it out to be).
- If you aren't utilising `title` or `data` then we don't even include a SUID (as there is no need for it) - as seen by State 4 above :-)
- We also shrink the urls to make sure that the smallest url will be used. For instance we will adjust `http://www.mysite.com/#http://www.mysite.com/projects/History.js` to become `http://www.mysite.com/#/projects/History.js` automatically. (again tested, working, and smarter).
- It works with domains, subdomains, subdirectories, whatever - doesn't matter where you put it. It's smart.
- Safari 5 will also have a SUID appended to the URL, it is entirely transparent but just a visible side-effect. It is required to fix a bug with Safari 5.
### Is there a working demo?
- Sure is, give it a download and navigate to the demo directory in your browser :-)
- If you are after something a bit more adventurous than a end-user demo, open up the tests directory in your browser and editor - it'll rock your world and show all the vast use cases that History.js supports.
## Download & Installation
1. Download History.js and upload it to your webserver. Download links: [tar.gz](https://github.com/balupton/History.js/tarball/master) or [zip](https://github.com/balupton/History.js/zipball/master)
2. Include [JSON2](http://www.json.org/js.html) for HTML4 Browsers Only *(replace www.yourwebsite.com)*
<script>if ( typeof window.JSON === 'undefined' ) { document.write('<script src="http://www.yourwebsite.com/history.js/scripts/compressed/json2.js"><\/script>'); }</script>
3. Include [Amplify.js Store](http://amplifyjs.com/) for Data Persistance and Synchronisation Support (optional but recommended)
<script src="http://www.yourwebsite.com/history.js/scripts/compressed/amplify.store.js"></script>
4. Include the Adapter for your Framework:
- [jQuery](http://jquery.com/) v1.3+
<script src="http://www.yourwebsite.com/history.js/scripts/compressed/history.adapter.jquery.js"></script>
- [Mootools](http://mootools.net/) v1.3+
<script src="http://www.yourwebsite.com/history.js/scripts/compressed/history.adapter.mootools.js"></script>
- [Prototype](http://www.prototypejs.org/) v1.7+ (does not support versions of IE prior to 9 due to a bug in the prototype library)
<script src="http://www.yourwebsite.com/history.js/scripts/compressed/history.adapter.prototype.js"></script>
- [Zepto](http://zeptojs.com/) v0.5+
<script src="http://www.yourwebsite.com/history.js/scripts/compressed/history.adapter.zepto.js"></script>
- _Would you like to support another framework? No problem! It's very easy to create adapters, and I'll be happy to include them or help out if you [let me know](https://github.com/balupton/history.js/issues) :-)_
5. Include History.js
<script src="http://www.yourwebsite.com/history.js/scripts/compressed/history.js"></script>
<script src="http://www.yourwebsite.com/history.js/scripts/compressed/history.html4.js"></script>
> Note: If you want to only support HTML5 Browsers and not HTML4 Browsers (so no hash fallback support) then just remove the `history.html4.js` file include in step #5 and the JSON2 (`json2.js`) file include in step #2 [- why supporting HTML4 browsers could be either good or bad based on my app's use cases](https://github.com/balupton/History.js/wiki/Intelligent-State-Handling)
## Subscribe to Updates
- For Email Updates:
- You can subscribe via the subscription form included in the demo page
- For Commit RSS/Atom Updates:
- You can subscribe via the [GitHub Commit Atom Feed](https://github.com/balupton/History.js/commits/master.atom)
- For GitHub News Feed Updates:
- You can click the "watch" button up the top right of History.js's [GitHub Project Page](https://github.com/balupton/History.js)
## Getting Support
History.js is an actively developed, supported and maintained project. You can grab support via its [GitHub Issue Tracker](https://github.com/balupton/History.js/issues). Alternatively you can reach [Benjamin Lupton](http://balupton.com) (the core developer) via [twitter](http://twitter.com/balupton), skype (balupton) or email (contact@balupton.com).
## Giving Support
If you'd love to give some support back and make a difference; here are a few great ways you can give back!
- Give it your honest rating on its [jQuery Plugin's Page](http://plugins.jquery.com/project/history-js) and its [Ohloh Page](https://www.ohloh.net/p/history-js)
- If you have any feedback or suggestions let me know via its [Issue Tracker](https://github.com/balupton/History.js/issues) - so that I can ensure you get the best experience!
- Spread the word via tweets, blogs, tumblr, whatever - the more people talking about it the better!
- Donate via the donation form at the bottom right of [balupton.com](http://balupton.com) - every cent truly does help!
- Make it easier for me to let you know about future releases and updates by subscribing via the signup form inside the demo page
- Watch it via clicking the "watch" button up the top of its [Project Page](https://github.com/balupton/History.js)
Thanks! every bit of help really does make a difference. Again thank you.
## Browsers: Tested and Working In
### HTML5 Browsers
- Chrome 8,9,10
- Firefox 4
- Safari 5
- Safari iOS 4.3
### HTML4 Browsers
- IE 6,7,8,9
- Firefox 3
- Opera 10,11
- Safari 4
- Safari iOS prior to version 4.3
## Exposed API
### Functions
- `History.pushState(data,title,url)` <br/> Pushes a new state to the browser; `data` can be null or an object, `title` can be null or a string, `url` must be a string
- `History.replaceState(data,title,url)` <br/> Replaces the existing state with a new state to the browser; `data` can be null or an object, `title` can be null or a string, `url` must be a string
- `History.getState()` <br/> Gets the current state of the browser, returns an object with `data`, `title` and `url`
- `History.getHash()` <br/> Gets the current hash of the browser
- `History.Adapter.bind(element,event,callback)` <br/> A framework independent event binder, you may either use this or your framework's native event binder.
- `History.Adapter.trigger(element,event)` <br/> A framework independent event trigger, you may either use this or your framework's native event trigger.
- `History.Adapter.onDomLoad(callback)` <br/> A framework independent onDomLoad binder, you may either use this or your framework's native onDomLoad binder.
- `History.back()` <br/> Go back once through the history (same as hitting the browser's back button)
- `History.forward()` <br/> Go forward once through the history (same as hitting the browser's forward button)
- `History.go(X)` <br/> If X is negative go back through history X times, if X is positive go forwards through history X times
- `History.log(...)` <br/> Logs messages to the console, the log element, and fallbacks to alert if neither of those two exist
- `History.debug(...)` <br/> Same as `History.log` but only runs if `History.debug.enable === true`
### Events
- `window.onstatechange` <br/> Fired when the state of the page changes (does not include hash changes)
- `window.onanchorchange` <br/> Fired when the anchor of the page changes (does not include state hashes)
## Notes on Compatibility
- History.js **solves** the following browser bugs:
- HTML5 Browsers
- Chrome 8 sometimes does not contain the correct state data when traversing back to the initial state
- Safari 5, Safari iOS 4 and Firefox 3 and 4 do not fire the `onhashchange` event when the page is loaded with a hash
- Safari 5 and Safari iOS 4 do not fire the `onpopstate` event when the hash has changed unlike the other browsers
- Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call / [bug report](https://bugs.webkit.org/show_bug.cgi?id=56249)
- Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions / [bug report](https://bugs.webkit.org/show_bug.cgi?id=42940)
- Google Chrome 8,9,10 and Firefox 4 prior to the RC will always fire `onpopstate` once the page has loaded / [change recommendation](http://hacks.mozilla.org/2011/03/history-api-changes-in-firefox-4/)
- Safari iOS 4.0, 4.1, 4.2 have a working HTML5 History API - although the actual back buttons of the browsers do not work, therefore we treat them as HTML4 browsers
- None of the HTML5 browsers actually utilise the `title` argument to the `pushState` and `replaceState` calls
- HTML4 Browsers
- Old browsers like MSIE 6,7 and Firefox 2 do not have a `onhashchange` event
- MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
- Non-Opera HTML4 browsers sometimes do not apply the hash when the hash is not `urlencoded`
- All Browsers
- State data and titles do not persist once the site is left and then returned (includes page refreshes)
- State titles are never applied to the `document.title`
- ReplaceState functionality is emulated in HTML4 browsers by discarding the replaced state, so when the discarded state is accessed it is skipped using the appropriate `History.back()` / `History.forward()` call
- Data persistance and synchronisation works like so: Every second or so, the SUIDs and URLs of the states will synchronise between the store and the local session. When a new session opens a familiar state (via the SUID or the URL) and it is not found locally then it will attempt to load the last known stored state with that information.
- URLs will be unescaped to the maximum, so for instance the URL `?key=a%20b%252c` will become `?key=a b c`. This is to ensure consistency between browser url encodings.
- Changing the hash of the page causes `onpopstate` to fire (this is expected/standard functionality). To ensure correct compatibility between HTML5 and HTML4 browsers the following events have been created:
- `window.onstatechange`: this is the same as the `onpopstate` event except it does not fire for traditional anchors
- `window.onanchorchange`: this is the same as the `onhashchange` event except it does not fire for states
- Known Issues
- Opera 11 fails to create history entries when under stressful loads (events fire perfectly, just the history events fail) - there is nothing we can do about this
- Mercury iOS fails to apply url changes (hashes and HTML5 History API states) - there is nothing we can do about this
## Changelog
- v1.7.0 - April 01 2011
- Added `History.enabled` property (refer to usage section). This reflects whether or not History.js is enabled for our particular browser. For instance, if we have not included support for a HTML4 browser and we are accessing through a HTML4 browser then `History.enabled` will be `false`.
- Added (optional but recommended) Data Persistance and Synchronisation Support thanks to [AppendTo's](http://appendto.com/) [Amplify.js](http://amplifyjs.com/) (refer to installation and compatibility sections for details)
- Made HTML5 SUIDs more transparent - [Reported](https://github.com/balupton/History.js/issues#issue/34) by [azago](https://github.com/azago) and [Mark Jaquith](http://markjaquith.com/)
- Fixed Session Storage Issue - Reported by a whole bunch of different people; [one](https://github.com/balupton/History.js/issues#issue/36), [two](https://github.com/balupton/History.js/issues#issue/37), [three](http://getsatisfaction.com/balupton/topics/history_js_1_6_losing_state_after_manual_page_reload)
- Fixed URL Encoding Issue - [Reported](https://github.com/balupton/history.js/issues/#issue/33) by [Rob Madole](http://robmadole.com/)
- Disabled support for IE6,7,8 when using the Prototype Adapter (there is nothing we can do about this, it is due to a bug in the prototype library) - [Reported](https://github.com/balupton/history.js/issues#issue/39) by [Sindre Wimberger](http://sindre.at/)
- URLs in the State Hashes for HTML4 Browsers are now even shorter - [Discussion](https://github.com/balupton/history.js/issues#issue/28)
- Fixed a issue with the MooTools Adapter and JSON with IE7 and IE8
- v1.6.0 - March 22 2011
- Added Zepto adapter thanks to [Matt Garrett](http://twitter.com/#!/matthewgarrett)
- The readme now references the supported versions of the libraries we use
- Updated vendors to the most recent versions. jQuery 1.5.1 and Mootools 1.3.1
- Reverted versions of Safari iOS prior to version 4.3 to be HTML4 browsers, Safari iOS 4.3 is a HTML5 browser
- Refined code in History.js and its adapters
- Fixed issue with extra state being inserted on Safari 5 requiring an extra click on the back button to go home - [Reported](https://github.com/balupton/history.js/issues#issue/17) by [Rob Madole](http://robmadole.com/)
- Fixed issue with Safari 5 and Safari iOS 4 sometimes failing to apply the state change under busy conditions - Solution conceived with [Matt Garrett](http://twitter.com/matthewgarrett)
- Fixed issue with HTML4 browsers requiring a query-string in the urls of states - [Reported](https://github.com/balupton/history.js/issues#issue/26) by [azago](https://github.com/azago)
- Fixed issue with HTML4 browsers requiring title in the states in order to use state data - [Reported](https://github.com/balupton/history.js/issues#issue/25) by [Jonathan McLaughlin](http://system-werks.com/)
- Fixed issue with HTML4 browsers failing is a state is pushed/replaced twice in a row - [Reported](https://github.com/balupton/history.js/issues#issue/17) by [Joey Baker](http://byjoeybaker.com/)
- **B/C BREAK:** The `statechange` event now only fires if the state has changed; it no longer fires on page initialisation. This is following the [Firefox 4 History API Changes](http://hacks.mozilla.org/2011/03/history-api-changes-in-firefox-4/) which we agree with - this breaks standard, but makes more sense.
- v1.5.0 - February 12 2011
- Moved to UglifyJS instead of Google Closure
- Split HTML4 functionality from HTML5 functionality
- Installation details have changed (the filenames are different)
- v1.4.1 - February 10 2011
- Added HTML History API Support for Safari 5 and Safari iOS 4.2.1
- Cleaned code a bit (mostly with unit tests)
- v1.4.0 - February 10 2011
- Unit Testing now uses [QUnit](http://docs.jquery.com/Qunit)
- Corrected Safari 5 Support
- Now uses queues instead of timeouts
- This means the API works exactly as expected, no more need to wrap calls in timeouts
- Included a Subscribe Form in the Demo for Version Updates via Email
- Small updates to Documentation
- v1.3.1 - February 04 2011
- Improved Documentation
- v1.3.0 - January 31 2011
- Support for cleaner HTML4 States
- v1.2.1 - January 30 2011
- Fixed History.log always being called - [reported by dlee](https://github.com/balupton/History.js/issues/#issue/2)
- Re-Added `History.go(index)` support
- v1.2.0 - January 25 2011
- Support for HTML4 States in HTML5 Browsers (added test)
- Updates of Documentation
- v1.1.0 - January 24 2011
- Developed a series of automated test cases
- Fixed issue with traditional anchors
- Fixed issue with differing replaceState functionality in HTML4 Browsers
- Fixed issue with Google Chrome artefacts being carried over to the initial state
- Provided `onstatechange` and `onanchorchange` events
- v1.0.0 - January 22 2011
- Supported `History.pushState` and `History.replaceState` degradation
- Supported jQuery, MooTools and Prototype Frameworks
## Todo for Upcoming Releases
- Allow for url to be optional in `pushState` and `replaceState` calls
- Add an Ajax extension to succeed the [jQuery Ajaxy](http://balupton.com/projects/jquery-ajaxy) project
- Add a compilation test to ensure `.debug = false` and no `History.log` or `console.xxx` calls exist.
It's likely these features and/or others have been included in the latest [dev branch](https://github.com/balupton/History.js/tree/dev). If you are wanting to fork and help out, then be sure to work on the dev branch and not master.

10
admin/thirdparty/history-js/license.txt vendored Normal file
View File

@ -0,0 +1,10 @@
Copyright (c) 2011, Benjamin Arthur Lupton
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 Benjamin Arthur Lupton 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 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 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.

View File

@ -0,0 +1,74 @@
{
"name": "history.js",
"version": "1.6.0",
"description": "History.js gracefully supports the HTML5 History/State APIs (pushState, replaceState, onPopState) in all browsers. Including continued support for data, titles, replaceState. Supports jQuery, MooTools and Prototype. For HTML5 browsers this means that you can modify the URL directly, without needing to use hashes anymore. For HTML4 browsers it will revert back to using the old onhashchange functionality.",
"homepage": "https://github.com/balupton/history.js",
"keywords": [
"javascript",
"html5 history api",
"hashchange",
"popstate",
"pushstate",
"replacestate",
"hashes",
"hashbang"
],
"author": {
"name": "Benjamin Lupton",
"email": "b@lupton.cc",
"web": "http://balupton.com"
},
"maintainers": [
{
"name": "Benjamin Lupton",
"email": "b@lupton.cc",
"web": "http://balupton.com"
}
],
"contributors": [
{
"name": "Benjamin Lupton",
"email": "b@lupton.cc",
"web": "http://balupton.com"
}
],
"bugs": {
"web": "https://github.com/balupton/history.js/issues"
},
"licenses": [
{
"type": "New-BSD",
"url": "http://creativecommons.org/licenses/BSD/"
}
],
"repository" : {
"type" : "git",
"url" : "http://github.com/balupton/history.js.git"
},
"dependencies": {
},
"engines" : {
},
"directories": {
"out": "./scripts/compressed",
"src": "./scripts/uncompressed"
},
"buildr": {
"compress": {
"js": true,
"css": false,
"img": false,
"html": false
},
"bundle": false,
"directories": {
"out": "./scripts/compressed",
"src": "./scripts/uncompressed"
},
"files": {
"js": true,
"css": false,
"img": false
}
}
}

View File

@ -0,0 +1 @@
(function(a,b){function d(a,d){var e=d.__amplify__?JSON.parse(d.__amplify__):{};c.addType(a,function(f,g,h){var i=g,j=(new Date).getTime(),k,l;if(!f){i={};for(f in e)k=d[f],l=k?JSON.parse(k):{expires:-1},l.expires&&l.expires<=j?(delete d[f],delete e[f]):i[f.replace(/^__amplify__/,"")]=l.data;d.__amplify__=JSON.stringify(e);return i}f="__amplify__"+f;if(g===b){if(e[f]){k=d[f],l=k?JSON.parse(k):{expires:-1};if(l.expires&&l.expires<=j)delete d[f],delete e[f];else return l.data}}else if(g===null)delete d[f],delete e[f];else{l=JSON.stringify({data:g,expires:h.expires?j+h.expires:null});try{d[f]=l,e[f]=!0}catch(m){c[a]();try{d[f]=l,e[f]=!0}catch(m){throw c.error()}}}d.__amplify__=JSON.stringify(e);return i})}JSON.stringify=JSON.stringify||JSON.encode,JSON.parse=JSON.parse||JSON.decode;var c=a.store=function(a,b,d,e){var e=c.type;d&&d.type&&d.type in c.types&&(e=d.type);return c.types[e](a,b,d||{})};c.types={},c.type=null,c.addType=function(a,b){c.type||(c.type=a),c.types[a]=b,c[a]=function(b,d,e){e=e||{},e.type=a;return c(b,d,e)}},c.error=function(){return"amplify.store quota exceeded"};for(var e in{localStorage:1,sessionStorage:1})try{window[e].getItem&&d(e,window[e])}catch(f){}window.globalStorage&&(d("globalStorage",window.globalStorage[window.location.hostname]),c.type==="sessionStorage"&&(c.type="globalStorage")),function(){var a=document.createElement("div"),d="amplify",e;a.style.display="none",document.getElementsByTagName("head")[0].appendChild(a),a.addBehavior&&(a.addBehavior("#default#userdata"),a.load(d),e=a.getAttribute(d)?JSON.parse(a.getAttribute(d)):{},c.addType("userData",function(f,g,h){var i=g,j=(new Date).getTime(),k,l,m;if(!f){i={};for(f in e)k=a.getAttribute(f),l=k?JSON.parse(k):{expires:-1},l.expires&&l.expires<=j?(a.removeAttribute(f),delete e[f]):i[f]=l.data;a.setAttribute(d,JSON.stringify(e)),a.save(d);return i}f=f.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,"-");if(g===b){if(f in e){k=a.getAttribute(f),l=k?JSON.parse(k):{expires:-1};if(l.expires&&l.expires<=j)a.removeAttribute(f),delete e[f];else return l.data}}else g===null?(a.removeAttribute(f),delete e[f]):(m=a.getAttribute(f),l=JSON.stringify({data:g,expires:h.expires?j+h.expires:null}),a.setAttribute(f,l),e[f]=!0);a.setAttribute(d,JSON.stringify(e));try{a.save(d)}catch(n){m===null?(a.removeAttribute(f),delete e[f]):a.setAttribute(f,m),c.userData();try{a.setAttribute(f,l),e[f]=!0,a.save(d)}catch(n){m===null?(a.removeAttribute(f),delete e[f]):a.setAttribute(f,m);throw c.error()}}return i}))}(),d("memory",{})})(this.amplify=this.amplify||{})

View File

@ -0,0 +1 @@
(function(a,b){var c=a.History=a.History||{},d=a.jQuery;if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");c.Adapter={bind:function(a,b,c){d(a).bind(b,c)},trigger:function(a,b){d(a).trigger(b)},onDomLoad:function(a){d(a)}},typeof c.init!="undefined"&&c.init()})(window)

View File

@ -0,0 +1 @@
(function(a,b){var c=a.History=a.History||{},d=a.MooTools;if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");Object.append(Element.NativeEvents,{popstate:2,hashchange:2}),c.Adapter={bind:function(a,b,c){var d=typeof a=="string"?document.id(a):a;d.addEvent(b,c)},trigger:function(a,b){var c=typeof a=="string"?document.id(a):a;c.fireEvent(b)},onDomLoad:function(b){a.addEvent("domready",b)}},typeof c.init!="undefined"&&c.init()})(window)

View File

@ -0,0 +1 @@
(function(a,b){var c=a.History=a.History||{},d=a.Prototype,e=a.Element,f=a.Event,g=a.$;if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");typeof a.fireEvent=="undefined"&&typeof a.dispatchEvent=="undefined"?c.enable=!1:(function(){var a={HTMLEvents:/^(?:load|unload|abort|error|select|hashchange|popstate|change|submit|reset|focus|blur|resize|scroll)$/,MouseEvents:/^(?:click|mouse(?:down|up|over|move|out))$/},b={pointerX:0,pointerY:0,button:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,bubbles:!0,cancelable:!0};f.hasNativeEvent=function(b,c){var d=null,e;b=g(b);for(var f in a)if(a[f].test(c)){d=f;break}e=d?!0:!1;return e},f.bind=function(a,b,c){a=g(a);return e.hasNativeEvent(a,b)?e.observe(a,b,c):e.observe(a,"custom:"+b,c)},f.trigger=function(c,d){var f=Object.extend(b,arguments[2]||{}),h,i=null;c=g(c);var j;for(j in a)if(a[j].test(d)){i=j;break}if(!i)return e.fire(c,"custom:"+d);document.createEvent?(h=document.createEvent(i),i==="HTMLEvents"?h.initEvent(d,f.bubbles,f.cancelable):i&&h.initMouseEvent(d,f.bubbles,f.cancelable,document.defaultView,f.button,f.pointerX,f.pointerY,f.pointerX,f.pointerY,f.ctrlKey,f.altKey,f.shiftKey,f.metaKey,f.button,c)):document.createEventObject&&(f.clientX=f.pointerX,f.clientY=f.pointerY,h=Object.extend(document.createEventObject(),f));if(c.fireEvent)c.fireEvent("on"+d,h);else if(c.dispatchEvent)c.dispatchEvent(h);else throw new Error("Cannot dispatch the event");return c},e.addMethods({simulate:f.trigger,trigger:f.trigger,bind:f.bind,hasNativeEvent:f.hasNativeEvent})}(),c.Adapter={bind:function(a,b,c){e.bind(a,b,c)},trigger:function(a,b){e.trigger(a,b)},onDomLoad:function(b){f.observe(a.document,"dom:loaded",b)}},typeof c.init!="undefined"&&c.init())})(window)

View File

@ -0,0 +1 @@
(function(a,b){var c=a.History=a.History||{},d=a.YUI;if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");c.Adapter={bind:function(a,b,c){d().use("node-base",function(d){d.one(a).on(b,c)})},trigger:function(a,b){d().use("node-event-simulate",function(c){c.one(a).simulate(b)})},onDomLoad:function(a){d().use("event",function(b){b.on("domready",a)})}},typeof c.init!="undefined"&&c.init()})(window)

View File

@ -0,0 +1 @@
(function(a,b){var c=a.History=a.History||{},d=a.Zepto;if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");c.Adapter={bind:function(a,b,c){d(a).bind(b,c)},trigger:function(a,b){d(a).trigger(b)},onDomLoad:function(a){d(a)}},typeof c.init!="undefined"&&c.init()})(window)

View File

@ -0,0 +1 @@
(function(a,b){"use strict";var c=a.document,d=a.setTimeout||d,e=a.clearTimeout||e,f=a.setInterval||f,g=a.History=a.History||{};if(typeof g.initHtml4!="undefined")throw new Error("History.js HTML4 Support has already been loaded...");g.initHtml4=function(){if(typeof g.initHtml4.initialized!="undefined")return!1;g.initHtml4.initialized=!0,g.enabled=!0,g.savedHashes=[],g.isLastHash=function(a){var b=g.getHashByIndex(),c=a===b;return c},g.saveHash=function(a){if(g.isLastHash(a))return!1;g.savedHashes.push(a);return!0},g.getHashByIndex=function(a){var b=null;typeof a=="undefined"?b=g.savedHashes[g.savedHashes.length-1]:a<0?b=g.savedHashes[g.savedHashes.length+a]:b=g.savedHashes[a];return b},g.discardedHashes={},g.discardedStates={},g.discardState=function(a,b,c){var d=g.getHashByState(a),e={discardedState:a,backState:c,forwardState:b};g.discardedStates[d]=e;return!0},g.discardHash=function(a,b,c){var d={discardedHash:a,backState:c,forwardState:b};g.discardedHashes[a]=d;return!0},g.discardedState=function(a){var b=g.getHashByState(a),c=g.discardedStates[b]||!1;return c},g.discardedHash=function(a){var b=g.discardedHashes[a]||!1;return b},g.recycleState=function(a){var b=g.getHashByState(a);g.discardedState(a)&&delete g.discardedStates[b];return!0},g.emulated.hashChange&&(g.hashChangeInit=function(){g.checkerFunction=null;var b="";if(g.isInternetExplorer()){var d="historyjs-iframe",e=c.createElement("iframe");e.setAttribute("id",d),e.style.display="none",c.body.appendChild(e),e.contentWindow.document.open(),e.contentWindow.document.close();var h="",i=!1;g.checkerFunction=function(){if(i)return!1;i=!0;var c=g.getHash()||"",d=g.unescapeHash(e.contentWindow.document.location.hash)||"";c!==b?(b=c,d!==c&&(h=d=c,e.contentWindow.document.open(),e.contentWindow.document.close(),e.contentWindow.document.location.hash=g.escapeHash(c)),g.Adapter.trigger(a,"hashchange")):d!==h&&(h=d,g.setHash(d,!1)),i=!1;return!0}}else g.checkerFunction=function(){var c=g.getHash();c!==b&&(b=c,g.Adapter.trigger(a,"hashchange"));return!0};f(g.checkerFunction,g.options.hashChangeInterval);return!0},g.Adapter.onDomLoad(g.hashChangeInit)),g.emulated.pushState&&(g.onHashChange=function(b){var d=b&&b.newURL||c.location.href,e=g.getHashByUrl(d),f=null,h=null,i=null;if(g.isLastHash(e)){g.busy(!1);return!1}g.doubleCheckComplete(),g.saveHash(e);if(e&&g.isTraditionalAnchor(e)){g.Adapter.trigger(a,"anchorchange"),g.busy(!1);return!1}f=g.extractState(g.getFullUrl(e||c.location.href,!1),!0);if(g.isLastSavedState(f)){g.busy(!1);return!1}h=g.getHashByState(f);var j=g.discardedState(f);if(j){g.getHashByIndex(-2)===g.getHashByState(j.forwardState)?g.back(!1):g.forward(!1);return!1}g.pushState(f.data,f.title,f.url,!1);return!0},g.Adapter.bind(a,"hashchange",g.onHashChange),g.pushState=function(b,d,e,f){if(g.getHashByUrl(e))throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==!1&&g.busy()){g.pushQueue({scope:g,callback:g.pushState,args:arguments,queue:f});return!1}g.busy(!0);var h=g.createStateObject(b,d,e),i=g.getHashByState(h),j=g.getState(!1),k=g.getHashByState(j),l=g.getHash();g.storeState(h),g.expectedStateId=h.id,g.recycleState(h),g.setTitle(h);if(i===k){g.busy(!1);return!1}if(i!==l&&i!==g.getShortUrl(c.location.href)){g.setHash(i,!1);return!1}g.saveState(h),g.Adapter.trigger(a,"statechange"),g.busy(!1);return!0},g.replaceState=function(a,b,c,d){if(g.getHashByUrl(c))throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(d!==!1&&g.busy()){g.pushQueue({scope:g,callback:g.replaceState,args:arguments,queue:d});return!1}g.busy(!0);var e=g.createStateObject(a,b,c),f=g.getState(!1),h=g.getStateByIndex(-2);g.discardState(f,e,h),g.pushState(e.data,e.title,e.url,!1);return!0},g.getHash()&&!g.emulated.hashChange&&g.Adapter.onDomLoad(function(){g.Adapter.trigger(a,"hashchange")}))},g.init()})(window)

View File

@ -0,0 +1 @@
(function(a,b){"use strict";var c=a.console||b,d=a.document,e=a.navigator,f=a.amplify||!1,g=a.setTimeout,h=a.clearTimeout,i=a.setInterval,j=a.JSON,k=a.History=a.History||{},l=a.history;j.stringify=j.stringify||j.encode,j.parse=j.parse||j.decode;if(typeof k.init!="undefined")throw new Error("History.js Core has already been loaded...");k.init=function(){if(typeof k.Adapter=="undefined")return!1;typeof k.initCore!="undefined"&&k.initCore(),typeof k.initHtml4!="undefined"&&k.initHtml4();return!0},k.initCore=function(){if(typeof k.initCore.initialized!="undefined")return!1;k.initCore.initialized=!0,k.options=k.options||{},k.options.hashChangeInterval=k.options.hashChangeInterval||100,k.options.safariPollInterval=k.options.safariPollInterval||500,k.options.doubleCheckInterval=k.options.doubleCheckInterval||500,k.options.storeInterval=k.options.storeInterval||1e3,k.options.busyDelay=k.options.busyDelay||250,k.options.debug=k.options.debug||!1,k.options.initialTitle=k.options.initialTitle||d.title,k.debug=function(){(k.options.debug||!1)&&k.log.apply(k,arguments)},k.log=function(){var a=typeof c!="undefined"&&typeof c.log!="undefined"&&typeof c.log.apply!="undefined",b=d.getElementById("log"),e,f,g;if(a){var h=Array.prototype.slice.call(arguments);e=h.shift(),typeof c.debug!="undefined"?c.debug.apply(c,[e,h]):c.log.apply(c,[e,h])}else e="\n"+arguments[0]+"\n";for(f=1,g=arguments.length;f<g;++f){var i=arguments[f];if(typeof i=="object"&&typeof j!="undefined")try{i=j.stringify(i)}catch(k){}e+="\n"+i+"\n"}b?(b.value+=e+"\n-----\n",b.scrollTop=b.scrollHeight-b.clientHeight):a||alert(e);return!0},k.getInternetExplorerMajorVersion=function(){var a=k.getInternetExplorerMajorVersion.cached=typeof k.getInternetExplorerMajorVersion.cached!="undefined"?k.getInternetExplorerMajorVersion.cached:function(){var a=3,b=d.createElement("div"),c=b.getElementsByTagName("i");while((b.innerHTML="<!--[if gt IE "+ ++a+"]><i></i><![endif]-->")&&c[0]);return a>4?a:!1}();return a},k.isInternetExplorer=function(){var a=k.isInternetExplorer.cached=typeof k.isInternetExplorer.cached!="undefined"?k.isInternetExplorer.cached:Boolean(k.getInternetExplorerMajorVersion());return a},k.emulated={pushState:!Boolean(a.history&&a.history.pushState&&a.history.replaceState&&!/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(e.userAgent)&&!/AppleWebKit\/5([0-2]|3[0-2])/i.test(e.userAgent)),hashChange:Boolean(!("onhashchange"in a||"onhashchange"in d)||k.isInternetExplorer()&&k.getInternetExplorerMajorVersion()<8)},k.enabled=!k.emulated.pushState,k.bugs={setHash:Boolean(!k.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),safariPoll:Boolean(!k.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),ieDoubleCheck:Boolean(k.isInternetExplorer()&&k.getInternetExplorerMajorVersion()<8),hashEscape:Boolean(k.isInternetExplorer()&&k.getInternetExplorerMajorVersion()<7)},k.isEmptyObject=function(a){for(var b in a)return!1;return!0},k.cloneObject=function(a){var b,c;a?(b=j.stringify(a),c=j.parse(b)):c={};return c},k.getRootUrl=function(){var a=d.location.protocol+"//"+(d.location.hostname||d.location.host);if(d.location.port||!1)a+=":"+d.location.port;a+="/";return a},k.getBaseHref=function(){var a=d.getElementsByTagName("base"),b=null,c="";a.length===1&&(b=a[0],c=b.href.replace(/[^\/]+$/,"")),c=c.replace(/\/+$/,""),c&&(c+="/");return c},k.getBaseUrl=function(){var a=k.getBaseHref()||k.getBasePageUrl()||k.getRootUrl();return a},k.getPageUrl=function(){var a=k.getState(!1,!1),b=(a||{}).url||d.location.href,c=b.replace(/\/+$/,"").replace(/[^\/]+$/,function(a,b,c){return/\./.test(a)?a:a+"/"});return c},k.getBasePageUrl=function(){var a=d.location.href.replace(/[#\?].*/,"").replace(/[^\/]+$/,function(a,b,c){return/[^\/]$/.test(a)?"":a}).replace(/\/+$/,"")+"/";return a},k.getFullUrl=function(a,b){var c=a,d=a.substring(0,1);b=typeof b=="undefined"?!0:b,/[a-z]+\:\/\//.test(a)||(d==="/"?c=k.getRootUrl()+a.replace(/^\/+/,""):d==="#"?c=k.getPageUrl().replace(/#.*/,"")+a:d==="?"?c=k.getPageUrl().replace(/[\?#].*/,"")+a:b?c=k.getBaseUrl()+a.replace(/^(\.\/)+/,""):c=k.getBasePageUrl()+a.replace(/^(\.\/)+/,""));return c.replace(/\#$/,"")},k.getShortUrl=function(a){var b=a,c=k.getBaseUrl(),d=k.getRootUrl();k.emulated.pushState&&(b=b.replace(c,"")),b=b.replace(d,"/"),k.isTraditionalAnchor(b)&&(b="./"+b),b=b.replace(/^(\.\/)+/g,"./").replace(/\#$/,"");return b},k.store=f?f.store("History.store")||{}:{},k.store.idToState=k.store.idToState||{},k.store.urlToId=k.store.urlToId||{},k.store.stateToId=k.store.stateToId||{},k.idToState=k.idToState||{},k.stateToId=k.stateToId||{},k.urlToId=k.urlToId||{},k.storedStates=k.storedStates||[],k.savedStates=k.savedStates||[],k.getState=function(a,b){typeof a=="undefined"&&(a=!0),typeof b=="undefined"&&(b=!0);var c=k.getLastSavedState();!c&&b&&(c=k.createStateObject()),a&&(c=k.cloneObject(c),c.url=c.cleanUrl||c.url);return c},k.getIdByState=function(a){var b=k.extractId(a.url);if(!b){var c=k.getStateString(a);if(typeof k.stateToId[c]!="undefined")b=k.stateToId[c];else if(typeof k.store.stateToId[c]!="undefined")b=k.store.stateToId[c];else{for(;;){b=String(Math.floor(Math.random()*1e3));if(typeof k.idToState[b]=="undefined"&&typeof k.store.idToState[b]=="undefined")break}k.stateToId[c]=b,k.idToState[b]=a}}return b},k.normalizeState=function(a){if(!a||typeof a!="object")a={};if(typeof a.normalized!="undefined")return a;if(!a.data||typeof a.data!="object")a.data={};var b={};b.normalized=!0,b.title=a.title||"",b.url=k.getFullUrl(k.unescapeString(a.url||d.location.href)),b.hash=k.getShortUrl(b.url),b.data=k.cloneObject(a.data),b.id=k.getIdByState(b),b.cleanUrl=b.url.replace(/\??\&_suid.*/,""),b.url=b.cleanUrl;var c=!k.isEmptyObject(b.data);if(b.title||c)b.hash=k.getShortUrl(b.url).replace(/\??\&_suid.*/,""),/\?/.test(b.hash)||(b.hash+="?"),b.hash+="&_suid="+b.id;b.hashedUrl=k.getFullUrl(b.hash),(k.emulated.pushState||k.bugs.safariPoll)&&k.hasUrlDuplicate(b)&&(b.url=b.hashedUrl);return b},k.createStateObject=function(a,b,c){var d={data:a,title:b,url:c};d=k.normalizeState(d);return d},k.getStateById=function(a){a=String(a);var c=k.idToState[a]||k.store.idToState[a]||b;return c},k.getStateString=function(a){var b=k.normalizeState(a),c={data:b.data,title:a.title,url:a.url},d=j.stringify(c);return d},k.getStateId=function(a){var b=k.normalizeState(a),c=b.id;return c},k.getHashByState=function(a){var b,c=k.normalizeState(a);b=c.hash;return b},k.extractId=function(a){var b,c,d;c=/(.*)\&_suid=([0-9]+)$/.exec(a),d=c?c[1]||a:a,b=c?String(c[2]||""):"";return b||!1},k.isTraditionalAnchor=function(a){var b=!/[\/\?\.]/.test(a);return b},k.extractState=function(a,b){var c=null;b=b||!1;var d=k.extractId(a);d&&(c=k.getStateById(d));if(!c){var e=k.getFullUrl(a);d=k.getIdByUrl(e)||!1,d&&(c=k.getStateById(d)),!c&&b&&!k.isTraditionalAnchor(a)&&(c=k.createStateObject(null,null,e))}return c},k.getIdByUrl=function(a){var c=k.urlToId[a]||k.store.urlToId[a]||b;return c},k.getLastSavedState=function(){return k.savedStates[k.savedStates.length-1]||b},k.getLastStoredState=function(){return k.storedStates[k.storedStates.length-1]||b},k.hasUrlDuplicate=function(a){var b=!1,c=k.extractState(a.url);b=c&&c.id!==a.id;return b},k.storeState=function(a){k.urlToId[a.url]=a.id,k.storedStates.push(k.cloneObject(a));return a},k.isLastSavedState=function(a){var b=!1;if(k.savedStates.length){var c=a.id,d=k.getLastSavedState(),e=d.id;b=c===e}return b},k.saveState=function(a){if(k.isLastSavedState(a))return!1;k.savedStates.push(k.cloneObject(a));return!0},k.getStateByIndex=function(a){var b=null;typeof a=="undefined"?b=k.savedStates[k.savedStates.length-1]:a<0?b=k.savedStates[k.savedStates.length+a]:b=k.savedStates[a];return b},k.getHash=function(){var a=k.unescapeHash(d.location.hash);return a},k.unescapeString=function(b){var c=b,d;for(;;){d=a.unescape(c);if(d===c)break;c=d}return c},k.unescapeHash=function(a){var b=k.normalizeHash(a);b=k.unescapeString(b);return b},k.normalizeHash=function(a){var b=a.replace(/[^#]*#/,"").replace(/#.*/,"");return b},k.setHash=function(a,b){if(b!==!1&&k.busy()){k.pushQueue({scope:k,callback:k.setHash,args:arguments,queue:b});return!1}var c=k.escapeHash(a);k.busy(!0);var e=k.extractState(a,!0);if(e&&!k.emulated.pushState)k.pushState(e.data,e.title,e.url,!1);else if(d.location.hash!==c)if(k.bugs.setHash){var f=k.getPageUrl();k.pushState(null,null,f+"#"+c,!1)}else d.location.hash=c;return k},k.escapeHash=function(b){var c=k.normalizeHash(b);c=a.escape(c),k.bugs.hashEscape||(c=c.replace(/\%21/g,"!").replace(/\%26/g,"&").replace(/\%3D/g,"=").replace(/\%3F/g,"?"));return c},k.getHashByUrl=function(a){var b=String(a).replace(/([^#]*)#?([^#]*)#?(.*)/,"$2");b=k.unescapeHash(b);return b},k.setTitle=function(a){var b=a.title;if(!b){var c=k.getStateByIndex(0);c&&c.url===a.url&&(b=c.title||k.options.initialTitle)}try{d.getElementsByTagName("title")[0].innerHTML=b.replace("<","&lt;").replace(">","&gt;").replace(" & "," &amp; ")}catch(e){}d.title=b;return k},k.queues=[],k.busy=function(a){typeof a!="undefined"?k.busy.flag=a:typeof k.busy.flag=="undefined"&&(k.busy.flag=!1);if(!k.busy.flag){h(k.busy.timeout);var b=function(){if(!k.busy.flag)for(var a=k.queues.length-1;a>=0;--a){var c=k.queues[a];if(c.length===0)continue;var d=c.shift();k.fireQueueItem(d),k.busy.timeout=g(b,k.options.busyDelay)}};k.busy.timeout=g(b,k.options.busyDelay)}return k.busy.flag},k.fireQueueItem=function(a){return a.callback.apply(a.scope||k,a.args||[])},k.pushQueue=function(a){k.queues[a.queue||0]=k.queues[a.queue||0]||[],k.queues[a.queue||0].push(a);return k},k.queue=function(a,b){typeof a=="function"&&(a={callback:a}),typeof b!="undefined"&&(a.queue=b),k.busy()?k.pushQueue(a):k.fireQueueItem(a);return k},k.clearQueue=function(){k.busy.flag=!1,k.queues=[];return k},k.stateChanged=!1,k.doubleChecker=!1,k.doubleCheckComplete=function(){k.stateChanged=!0,k.doubleCheckClear();return k},k.doubleCheckClear=function(){k.doubleChecker&&(h(k.doubleChecker),k.doubleChecker=!1);return k},k.doubleCheck=function(a){k.stateChanged=!1,k.doubleCheckClear(),k.bugs.ieDoubleCheck&&(k.doubleChecker=g(function(){k.doubleCheckClear(),k.stateChanged||a();return!0},k.options.doubleCheckInterval));return k},k.safariStatePoll=function(){var b=k.extractState(d.location.href),c;if(!k.isLastSavedState(b))c=b;else return;c||(c=k.createStateObject()),k.Adapter.trigger(a,"popstate");return k},k.back=function(a){if(a!==!1&&k.busy()){k.pushQueue({scope:k,callback:k.back,args:arguments,queue:a});return!1}k.busy(!0),k.doubleCheck(function(){k.back(!1)}),l.go(-1);return!0},k.forward=function(a){if(a!==!1&&k.busy()){k.pushQueue({scope:k,callback:k.forward,args:arguments,queue:a});return!1}k.busy(!0),k.doubleCheck(function(){k.forward(!1)}),l.go(1);return!0},k.go=function(a,b){var c;if(a>0)for(c=1;c<=a;++c)k.forward(b);else{if(!(a<0))throw new Error("History.go: History.go requires a positive or negative integer passed.");for(c=-1;c>=a;--c)k.back(b)}return k},k.saveState(k.storeState(k.extractState(d.location.href,!0))),f&&(k.onUnload=function(){var a=f.store("History.store")||{},b;a.idToState=a.idToState||{},a.urlToId=a.urlToId||{},a.stateToId=a.stateToId||{};for(b in k.idToState){if(!k.idToState.hasOwnProperty(b))continue;a.idToState[b]=k.idToState[b]}for(b in k.urlToId){if(!k.urlToId.hasOwnProperty(b))continue;a.urlToId[b]=k.urlToId[b]}for(b in k.stateToId){if(!k.stateToId.hasOwnProperty(b))continue;a.stateToId[b]=k.stateToId[b]}k.store=a,f.store("History.store",a)},i(k.onUnload,k.options.storeInterval),k.Adapter.bind(a,"beforeunload",k.onUnload),k.Adapter.bind(a,"unload",k.onUnload));if(k.emulated.pushState){var m=function(){};k.pushState=k.pushState||m,k.replaceState=k.replaceState||m}else{k.onPopState=function(b){k.doubleCheckComplete();var c=k.getHash();if(c){var e=k.extractState(c||d.location.href,!0);e?k.replaceState(e.data,e.title,e.url,!1):(k.Adapter.trigger(a,"anchorchange"),k.busy(!1)),k.expectedStateId=!1;return!1}var f=!1;b=b||{},typeof b.state=="undefined"&&(typeof b.originalEvent!="undefined"&&typeof b.originalEvent.state!="undefined"?b.state=b.originalEvent.state||!1:typeof b.event!="undefined"&&typeof b.event.state!="undefined"&&(b.state=b.event.state||!1)),b.state=b.state||!1,b.state?f=k.getStateById(b.state):k.expectedStateId?f=k.getStateById(k.expectedStateId):f=k.extractState(d.location.href),f||(f=k.createStateObject(null,null,d.location.href)),k.expectedStateId=!1;if(k.isLastSavedState(f)){k.busy(!1);return!1}k.storeState(f),k.saveState(f),k.setTitle(f),k.Adapter.trigger(a,"statechange"),k.busy(!1);return!0},k.Adapter.bind(a,"popstate",k.onPopState),k.pushState=function(b,c,d,e){if(k.getHashByUrl(d)&&k.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&k.busy()){k.pushQueue({scope:k,callback:k.pushState,args:arguments,queue:e});return!1}k.busy(!0);var f=k.createStateObject(b,c,d);k.isLastSavedState(f)?k.busy(!1):(k.storeState(f),k.expectedStateId=f.id,l.pushState(f.id,f.title,f.url),k.Adapter.trigger(a,"popstate"));return!0},k.replaceState=function(b,c,d,e){if(k.getHashByUrl(d)&&k.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&k.busy()){k.pushQueue({scope:k,callback:k.replaceState,args:arguments,queue:e});return!1}k.busy(!0);var f=k.createStateObject(b,c,d);k.isLastSavedState(f)?k.busy(!1):(k.storeState(f),k.expectedStateId=f.id,l.replaceState(f.id,f.title,f.url),k.Adapter.trigger(a,"popstate"));return!0},k.bugs.safariPoll&&i(k.safariStatePoll,k.options.safariPollInterval);if(e.vendor==="Apple Computer, Inc."||(e.appCodeName||"")==="Mozilla")k.Adapter.bind(a,"hashchange",function(){k.Adapter.trigger(a,"popstate")}),k.getHash()&&k.Adapter.onDomLoad(function(){k.Adapter.trigger(a,"hashchange")})}},k.init()})(window)

View File

@ -0,0 +1 @@
var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)d=rep[c],typeof d=="string"&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function f(a){return a<10?"0"+a:a}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(b&&typeof b!="function"&&(typeof b!="object"||typeof b.length!="number"))throw new Error("JSON.stringify");return str("",{"":a})}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")})}()

View File

@ -0,0 +1,247 @@
/*!
* Amplify Store - Persistent Client-Side Storage @VERSION
*
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
* Dual licensed under the MIT or GPL licenses.
* http://appendto.com/open-source-licenses
*
* http://amplifyjs.com
*/
(function( amplify, undefined ) {
// MooTools Compatibility
JSON.stringify = JSON.stringify||JSON.encode;
JSON.parse = JSON.parse||JSON.decode;
var store = amplify.store = function( key, value, options, type ) {
var type = store.type;
if ( options && options.type && options.type in store.types ) {
type = options.type;
}
return store.types[ type ]( key, value, options || {} );
};
store.types = {};
store.type = null;
store.addType = function( type, storage ) {
if ( !store.type ) {
store.type = type;
}
store.types[ type ] = storage;
store[ type ] = function( key, value, options ) {
options = options || {};
options.type = type;
return store( key, value, options );
};
}
store.error = function() {
return "amplify.store quota exceeded";
};
function createSimpleStorage( storageType, storage ) {
var values = storage.__amplify__ ? JSON.parse( storage.__amplify__ ) : {};
store.addType( storageType, function( key, value, options ) {
var ret = value,
now = (new Date()).getTime(),
storedValue,
parsed;
if ( !key ) {
ret = {};
for ( key in values ) {
storedValue = storage[ key ];
parsed = storedValue ? JSON.parse( storedValue ) : { expires: -1 };
if ( parsed.expires && parsed.expires <= now ) {
delete storage[ key ];
delete values[ key ];
} else {
ret[ key.replace( /^__amplify__/, "" ) ] = parsed.data;
}
}
storage.__amplify__ = JSON.stringify( values );
return ret;
}
// protect against overwriting built-in properties
key = "__amplify__" + key;
if ( value === undefined ) {
if ( values[ key ] ) {
storedValue = storage[ key ];
parsed = storedValue ? JSON.parse( storedValue ) : { expires: -1 };
if ( parsed.expires && parsed.expires <= now ) {
delete storage[ key ];
delete values[ key ];
} else {
return parsed.data;
}
}
} else {
if ( value === null ) {
delete storage[ key ];
delete values[ key ];
} else {
parsed = JSON.stringify({
data: value,
expires: options.expires ? now + options.expires : null
});
try {
storage[ key ] = parsed;
values[ key ] = true;
// quota exceeded
} catch( error ) {
// expire old data and try again
store[ storageType ]();
try {
storage[ key ] = parsed;
values[ key ] = true;
} catch( error ) {
throw store.error();
}
}
}
}
storage.__amplify__ = JSON.stringify( values );
return ret;
});
}
// localStorage + sessionStorage
// IE 8+, Firefox 3.5+, Safari 4+, Chrome 4+, Opera 10.5+, iPhone 2+, Android 2+
for ( var webStorageType in { localStorage: 1, sessionStorage: 1 } ) {
// try/catch for file protocol in Firefox
try {
if ( window[ webStorageType ].getItem ) {
createSimpleStorage( webStorageType, window[ webStorageType ] );
}
} catch( e ) {}
}
// globalStorage
// non-standard: Firefox 2+
// https://developer.mozilla.org/en/dom/storage#globalStorage
if ( window.globalStorage ) {
createSimpleStorage( "globalStorage",
window.globalStorage[ window.location.hostname ] );
// Firefox 2.0 and 3.0 have sessionStorage and globalStorage
// make sure we defualt to globalStorage
// but don't default to globalStorage in 3.5+ which also has localStorage
if ( store.type === "sessionStorage" ) {
store.type = "globalStorage";
}
}
// userData
// non-standard: IE 5+
// http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx
(function() {
// append to html instead of body so we can do this from the head
var div = document.createElement( "div" ),
attrKey = "amplify",
attrs;
div.style.display = "none";
document.getElementsByTagName( "head" )[ 0 ].appendChild( div );
if ( div.addBehavior ) {
div.addBehavior( "#default#userdata" );
div.load( attrKey );
attrs = div.getAttribute( attrKey ) ? JSON.parse( div.getAttribute( attrKey ) ) : {};
store.addType( "userData", function( key, value, options ) {
var ret = value,
now = (new Date()).getTime(),
attr,
parsed,
prevValue;
if ( !key ) {
ret = {};
for ( key in attrs ) {
attr = div.getAttribute( key );
parsed = attr ? JSON.parse( attr ) : { expires: -1 };
if ( parsed.expires && parsed.expires <= now ) {
div.removeAttribute( key );
delete attrs[ key ];
} else {
ret[ key ] = parsed.data;
}
}
div.setAttribute( attrKey, JSON.stringify( attrs ) );
div.save( attrKey );
return ret;
}
// convert invalid characters to dashes
// http://www.w3.org/TR/REC-xml/#NT-Name
// simplified to assume the starting character is valid
// also removed colon as it is invalid in HTML attribute names
key = key.replace( /[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g, "-" );
if ( value === undefined ) {
if ( key in attrs ) {
attr = div.getAttribute( key );
parsed = attr ? JSON.parse( attr ) : { expires: -1 };
if ( parsed.expires && parsed.expires <= now ) {
div.removeAttribute( key );
delete attrs[ key ];
} else {
return parsed.data;
}
}
} else {
if ( value === null ) {
div.removeAttribute( key );
delete attrs[ key ];
} else {
// we need to get the previous value in case we need to rollback
prevValue = div.getAttribute( key );
parsed = JSON.stringify({
data: value,
expires: (options.expires ? (now + options.expires) : null)
});
div.setAttribute( key, parsed );
attrs[ key ] = true;
}
}
div.setAttribute( attrKey, JSON.stringify( attrs ) );
try {
div.save( attrKey );
// quota exceeded
} catch ( error ) {
// roll the value back to the previous value
if ( prevValue === null ) {
div.removeAttribute( key );
delete attrs[ key ];
} else {
div.setAttribute( key, prevValue );
}
// expire old data and try again
store.userData();
try {
div.setAttribute( key, parsed );
attrs[ key ] = true;
div.save( attrKey );
} catch ( error ) {
// roll the value back to the previous value
if ( prevValue === null ) {
div.removeAttribute( key );
delete attrs[ key ];
} else {
div.setAttribute( key, prevValue );
}
throw store.error();
}
}
return ret;
});
}
}() );
// in-memory storage
// fallback for all browsers to enable the API even if we can't persist data
createSimpleStorage( "memory", {} );
}( this.amplify = this.amplify || {} ) );

View File

@ -0,0 +1 @@
// If you know dojo - then this is your canvas

View File

@ -0,0 +1,58 @@
/**
* History.js jQuery Adapter
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
*/
// Closure
(function(window,undefined){
// Localise Globals
var
History = window.History = window.History||{},
jQuery = window.jQuery;
// Check Existence
if ( typeof History.Adapter !== 'undefined' ) {
throw new Error('History.js Adapter has already been loaded...');
}
// Add the Adapter
History.Adapter = {
/**
* History.Adapter.bind(el,event,callback)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @param {Function} callback
* @return
*/
bind: function(el,event,callback){
jQuery(el).bind(event,callback);
},
/**
* History.Adapter.trigger(el,event)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @return
*/
trigger: function(el,event){
jQuery(el).trigger(event);
},
/**
* History.Adapter.trigger(el,event,data)
* @param {Function} callback
* @return
*/
onDomLoad: function(callback) {
jQuery(callback);
}
};
// Try and Initialise History
if ( typeof History.init !== 'undefined' ) {
History.init();
}
})(window);

View File

@ -0,0 +1,66 @@
/**
* History.js jQuery Adapter
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
*/
// Closure
(function(window,undefined){
// Localise Globals
var
History = window.History = window.History||{},
MooTools = window.MooTools;
// Check Existence
if ( typeof History.Adapter !== 'undefined' ) {
throw new Error('History.js Adapter has already been loaded...');
}
// Make MooTools aware of History.js Events
Object.append(Element.NativeEvents,{
'popstate':2,
'hashchange':2
});
// Add the Adapter
History.Adapter = {
/**
* History.Adapter.bind(el,event,callback)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @param {Function} callback
* @return
*/
bind: function(el,event,callback){
var El = typeof el === 'string' ? document.id(el) : el;
El.addEvent(event,callback);
},
/**
* History.Adapter.trigger(el,event)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @return
*/
trigger: function(el,event){
var El = typeof el === 'string' ? document.id(el) : el;
El.fireEvent(event);
},
/**
* History.Adapter.trigger(el,event)
* @param {Function} callback
* @return
*/
onDomLoad: function(callback) {
window.addEvent('domready',callback);
}
};
// Try and Initialise History
if ( typeof History.init !== 'undefined' ) {
History.init();
}
})(window);

View File

@ -0,0 +1,197 @@
/**
* History.js Prototype Adapter
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
*/
// Closure
(function(window,undefined){
// Localise Globals
var
History = window.History = window.History||{},
Prototype = window.Prototype,
Element = window.Element,
Event = window.Event,
$ = window.$;
// Check Existence
if ( typeof History.Adapter !== 'undefined' ) {
throw new Error('History.js Adapter has already been loaded...');
}
// Prototype does not support event binding to the window element in IE6-8
if ( typeof window.fireEvent === 'undefined' && typeof window.dispatchEvent === 'undefined' ) {
History.enable = false;
return;
}
/**
* Bind and Trigger custom and native events in Prototype
* @author Juriy Zaytsev (kangax)
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright MIT license <http://creativecommons.org/licenses/MIT/>
*/
(function(){
// Prepare
var
eventMatchers = {
'HTMLEvents': /^(?:load|unload|abort|error|select|hashchange|popstate|change|submit|reset|focus|blur|resize|scroll)$/,
'MouseEvents': /^(?:click|mouse(?:down|up|over|move|out))$/
},
defaultOptions = {
pointerX: 0,
pointerY: 0,
button: 0,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
bubbles: true,
cancelable: true
};
// Check for Native Event
Event.hasNativeEvent = function(element, eventName) {
// Prepare
var eventType = null, result;
element = $(element);
// Cycle
for (var name in eventMatchers) {
if ( eventMatchers[name].test(eventName) ) {
eventType = name;
break;
}
}
// Evaluate
result = eventType ? true : false;
// Return result
return result;
};
// Bind a Native or Custom Event
Event.bind = function(element, eventName, eventHandler) {
// Prepare
element = $(element);
// Native Event?
if ( Element.hasNativeEvent(element,eventName) ) {
return Element.observe(element,eventName,eventHandler);
}
// Custom Event?
else {
return Element.observe(element,'custom:'+eventName,eventHandler);
}
// Return element
return element;
};
// Trigger
Event.trigger = function(element, eventName) {
// Prepare
var options = Object.extend(defaultOptions, arguments[2] || { });
var oEvent, eventType = null;
element = $(element);
// Check for Native Event
var name; for (name in eventMatchers) {
if (eventMatchers[name].test(eventName)) { eventType = name; break; }
}
// Custom Event?
if ( !eventType ) {
return Element.fire(element,'custom:'+eventName);
}
// Create Event
if ( document.createEvent ) {
// Firefox + Others
oEvent = document.createEvent(eventType);
// Normal Event?
if ( eventType === 'HTMLEvents' ) {
oEvent.initEvent(eventName, options.bubbles, options.cancelable);
}
// Mouse Event?
else if ( eventType ) {
oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
}
}
else if ( document.createEventObject ) {
// Internet Explorer
options.clientX = options.pointerX;
options.clientY = options.pointerY;
oEvent = Object.extend(document.createEventObject(), options);
}
// Fire Event
if ( element.fireEvent ) {
element.fireEvent('on'+eventName,oEvent);
}
else if ( element.dispatchEvent ) {
element.dispatchEvent(oEvent);
}
else {
throw new Error('Cannot dispatch the event');
}
// Return
return element;
};
// Amend Element Prototype
Element.addMethods({
simulate: Event.trigger,
trigger: Event.trigger,
bind: Event.bind,
hasNativeEvent: Event.hasNativeEvent
});
})();
// Add the Adapter
History.Adapter = {
/**
* History.Adapter.bind(el,event,callback)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @param {Function} callback
* @return
*/
bind: function(el,event,callback){
Element.bind(el,event,callback);
},
/**
* History.Adapter.trigger(el,event)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @return
*/
trigger: function(el,event){
Element.trigger(el,event);
},
/**
* History.Adapter.trigger(el,event,data)
* @param {Function} callback
* @return
*/
onDomLoad: function(callback) {
Event.observe(window.document, 'dom:loaded', callback);
}
};
// Try and Initialise History
if ( typeof History.init !== 'undefined' ) {
History.init();
}
})(window);

View File

@ -0,0 +1,64 @@
/**
* History.js YUI Adapter [NOT WORKING]
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
*/
// Closure
(function(window,undefined){
// Localise Globals
var
History = window.History = window.History||{},
YUI = window.YUI;
// Check Existence
if ( typeof History.Adapter !== 'undefined' ) {
throw new Error('History.js Adapter has already been loaded...');
}
// Add the Adapter
History.Adapter = {
/**
* History.Adapter.bind(el,event,callback)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @param {Function} callback
* @return {element}
*/
bind: function(el,event,callback){
YUI().use('node-base', function(Y){
Y.one(el).on(event,callback);
});
},
/**
* History.Adapter.trigger(el,event)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @return {element}
*/
trigger: function(el,event){
YUI().use('node-event-simulate', function(Y){
Y.one(el).simulate(event);
});
},
/**
* History.Adapter.trigger(el,event,data)
* @param {Function} callback
* @return {true}
*/
onDomLoad: function(callback) {
YUI().use('event', function(Y){
Y.on('domready', callback);
});
}
};
// Try and Initialise History
if ( typeof History.init !== 'undefined' ) {
History.init();
}
})(window);

View File

@ -0,0 +1,58 @@
/**
* History.js Zepto Adapter
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
*/
// Closure
(function(window,undefined){
// Localise Globals
var
History = window.History = window.History||{},
Zepto = window.Zepto;
// Check Existence
if ( typeof History.Adapter !== 'undefined' ) {
throw new Error('History.js Adapter has already been loaded...');
}
// Add the Adapter
History.Adapter = {
/**
* History.Adapter.bind(el,event,callback)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @param {Function} callback
* @return
*/
bind: function(el,event,callback){
Zepto(el).bind(event,callback);
},
/**
* History.Adapter.trigger(el,event)
* @param {Element|Selector} el
* @param {String} event - custom and standard events
* @return
*/
trigger: function(el,event){
Zepto(el).trigger(event);
},
/**
* History.Adapter.trigger(el,event,data)
* @param {Function} callback
* @return
*/
onDomLoad: function(callback) {
Zepto(callback);
}
};
// Try and Initialise History
if ( typeof History.init !== 'undefined' ) {
History.init();
}
})(window);

View File

@ -0,0 +1,606 @@
/**
* History.js HTML4 Support
* Depends on the HTML5 Support
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
*/
(function(window,undefined){
"use strict";
// --------------------------------------------------------------------------
// Initialise
// Localise Globals
var
document = window.document, // Make sure we are using the correct document
setTimeout = window.setTimeout||setTimeout,
clearTimeout = window.clearTimeout||clearTimeout,
setInterval = window.setInterval||setInterval,
History = window.History = window.History||{}; // Public History Object
// Check Existence
if ( typeof History.initHtml4 !== 'undefined' ) {
throw new Error('History.js HTML4 Support has already been loaded...');
}
// --------------------------------------------------------------------------
// Initialise HTML4 Support
// Initialise HTML4 Support
History.initHtml4 = function(){
// Initialise
if ( typeof History.initHtml4.initialized !== 'undefined' ) {
// Already Loaded
return false;
}
else {
History.initHtml4.initialized = true;
}
// ----------------------------------------------------------------------
// Properties
/**
* History.enabled
* Is History enabled?
*/
History.enabled = true;
// ----------------------------------------------------------------------
// Hash Storage
/**
* History.savedHashes
* Store the hashes in an array
*/
History.savedHashes = [];
/**
* History.isLastHash(newHash)
* Checks if the hash is the last hash
* @param {string} newHash
* @return {boolean} true
*/
History.isLastHash = function(newHash){
// Prepare
var oldHash = History.getHashByIndex();
// Check
var isLast = newHash === oldHash;
// Return isLast
return isLast;
};
/**
* History.saveHash(newHash)
* Push a Hash
* @param {string} newHash
* @return {boolean} true
*/
History.saveHash = function(newHash){
// Check Hash
if ( History.isLastHash(newHash) ) {
return false;
}
// Push the Hash
History.savedHashes.push(newHash);
// Return true
return true;
};
/**
* History.getHashByIndex()
* Gets a hash by the index
* @param {integer} index
* @return {string}
*/
History.getHashByIndex = function(index){
// Prepare
var hash = null;
// Handle
if ( typeof index === 'undefined' ) {
// Get the last inserted
hash = History.savedHashes[History.savedHashes.length-1];
}
else if ( index < 0 ) {
// Get from the end
hash = History.savedHashes[History.savedHashes.length+index];
}
else {
// Get from the beginning
hash = History.savedHashes[index];
}
// Return hash
return hash;
};
// ----------------------------------------------------------------------
// Discarded States
/**
* History.discardedHashes
* A hashed array of discarded hashes
*/
History.discardedHashes = {};
/**
* History.discardedStates
* A hashed array of discarded states
*/
History.discardedStates = {};
/**
* History.discardState(State)
* Discards the state by ignoring it through History
* @param {object} State
* @return {true}
*/
History.discardState = function(discardedState,forwardState,backState){
//History.debug('History.discardState', arguments);
// Prepare
var discardedStateHash = History.getHashByState(discardedState);
// Create Discard Object
var discardObject = {
'discardedState': discardedState,
'backState': backState,
'forwardState': forwardState
};
// Add to DiscardedStates
History.discardedStates[discardedStateHash] = discardObject;
// Return true
return true;
};
/**
* History.discardHash(hash)
* Discards the hash by ignoring it through History
* @param {string} hash
* @return {true}
*/
History.discardHash = function(discardedHash,forwardState,backState){
//History.debug('History.discardState', arguments);
// Create Discard Object
var discardObject = {
'discardedHash': discardedHash,
'backState': backState,
'forwardState': forwardState
};
// Add to discardedHash
History.discardedHashes[discardedHash] = discardObject;
// Return true
return true;
};
/**
* History.discardState(State)
* Checks to see if the state is discarded
* @param {object} State
* @return {bool}
*/
History.discardedState = function(State){
// Prepare
var StateHash = History.getHashByState(State);
// Check
var discarded = History.discardedStates[StateHash]||false;
// Return true
return discarded;
};
/**
* History.discardedHash(hash)
* Checks to see if the state is discarded
* @param {string} State
* @return {bool}
*/
History.discardedHash = function(hash){
// Check
var discarded = History.discardedHashes[hash]||false;
// Return true
return discarded;
};
/**
* History.recycleState(State)
* Allows a discarded state to be used again
* @param {object} data
* @param {string} title
* @param {string} url
* @return {true}
*/
History.recycleState = function(State){
//History.debug('History.recycleState', arguments);
// Prepare
var StateHash = History.getHashByState(State);
// Remove from DiscardedStates
if ( History.discardedState(State) ) {
delete History.discardedStates[StateHash];
}
// Return true
return true;
};
// ----------------------------------------------------------------------
// HTML4 HashChange Support
if ( History.emulated.hashChange ) {
/*
* We must emulate the HTML4 HashChange Support by manually checking for hash changes
*/
/**
* History.hashChangeInit()
* Init the HashChange Emulation
*/
History.hashChangeInit = function(){
// Define our Checker Function
History.checkerFunction = null;
// Define some variables that will help in our checker function
var
lastDocumentHash = '';
// Handle depending on the browser
if ( History.isInternetExplorer() ) {
// IE6 and IE7
// We need to use an iframe to emulate the back and forward buttons
// Create iFrame
var
iframeId = 'historyjs-iframe',
iframe = document.createElement('iframe');
// Adjust iFarme
iframe.setAttribute('id', iframeId);
iframe.style.display = 'none';
// Append iFrame
document.body.appendChild(iframe);
// Create initial history entry
iframe.contentWindow.document.open();
iframe.contentWindow.document.close();
// Define some variables that will help in our checker function
var
lastIframeHash = '',
checkerRunning = false;
// Define the checker function
History.checkerFunction = function(){
// Check Running
if ( checkerRunning ) {
return false;
}
// Update Running
checkerRunning = true;
// Fetch
var
documentHash = History.getHash()||'',
iframeHash = History.unescapeHash(iframe.contentWindow.document.location.hash)||'';
// The Document Hash has changed (application caused)
if ( documentHash !== lastDocumentHash ) {
// Equalise
lastDocumentHash = documentHash;
// Create a history entry in the iframe
if ( iframeHash !== documentHash ) {
//History.debug('hashchange.checker: iframe hash change', 'documentHash (new):', documentHash, 'iframeHash (old):', iframeHash);
// Equalise
lastIframeHash = iframeHash = documentHash;
// Create History Entry
iframe.contentWindow.document.open();
iframe.contentWindow.document.close();
// Update the iframe's hash
iframe.contentWindow.document.location.hash = History.escapeHash(documentHash);
}
// Trigger Hashchange Event
History.Adapter.trigger(window,'hashchange');
}
// The iFrame Hash has changed (back button caused)
else if ( iframeHash !== lastIframeHash ) {
//History.debug('hashchange.checker: iframe hash out of sync', 'iframeHash (new):', iframeHash, 'documentHash (old):', documentHash);
// Equalise
lastIframeHash = iframeHash;
// Update the Hash
History.setHash(iframeHash,false);
}
// Reset Running
checkerRunning = false;
// Return true
return true;
};
}
else {
// We are not IE
// Firefox 1 or 2, Opera
// Define the checker function
History.checkerFunction = function(){
// Prepare
var documentHash = History.getHash();
// The Document Hash has changed (application caused)
if ( documentHash !== lastDocumentHash ) {
// Equalise
lastDocumentHash = documentHash;
// Trigger Hashchange Event
History.Adapter.trigger(window,'hashchange');
}
// Return true
return true;
};
}
// Apply the checker function
History.intervalList.push(setInterval(History.checkerFunction, History.options.hashChangeInterval));
// Done
return true;
}; // History.hashChangeInit
// Bind hashChangeInit
History.Adapter.onDomLoad(History.hashChangeInit);
} // History.emulated.hashChange
// ----------------------------------------------------------------------
// HTML5 State Support
if ( History.emulated.pushState ) {
/*
* We must emulate the HTML5 State Management by using HTML4 HashChange
*/
/**
* History.onHashChange(event)
* Trigger HTML5's window.onpopstate via HTML4 HashChange Support
*/
History.onHashChange = function(event){
//History.debug('History.onHashChange', arguments);
// Prepare
var
currentUrl = ((event && event.newURL) || document.location.href),
currentHash = History.getHashByUrl(currentUrl),
currentState = null,
currentStateHash = null,
currentStateHashExits = null;
// Check if we are the same state
if ( History.isLastHash(currentHash) ) {
// There has been no change (just the page's hash has finally propagated)
//History.debug('History.onHashChange: no change');
History.busy(false);
return false;
}
// Reset the double check
History.doubleCheckComplete();
// Store our location for use in detecting back/forward direction
History.saveHash(currentHash);
// Expand Hash
if ( currentHash && History.isTraditionalAnchor(currentHash) ) {
//History.debug('History.onHashChange: traditional anchor', currentHash);
// Traditional Anchor Hash
History.Adapter.trigger(window,'anchorchange');
History.busy(false);
return false;
}
// Create State
currentState = History.extractState(History.getFullUrl(currentHash||document.location.href,false),true);
// Check if we are the same state
if ( History.isLastSavedState(currentState) ) {
//History.debug('History.onHashChange: no change');
// There has been no change (just the page's hash has finally propagated)
History.busy(false);
return false;
}
// Create the state Hash
currentStateHash = History.getHashByState(currentState);
// Check if we are DiscardedState
var discardObject = History.discardedState(currentState);
if ( discardObject ) {
// Ignore this state as it has been discarded and go back to the state before it
if ( History.getHashByIndex(-2) === History.getHashByState(discardObject.forwardState) ) {
// We are going backwards
//History.debug('History.onHashChange: go backwards');
History.back(false);
} else {
// We are going forwards
//History.debug('History.onHashChange: go forwards');
History.forward(false);
}
return false;
}
// Push the new HTML5 State
//History.debug('History.onHashChange: success hashchange');
History.pushState(currentState.data,currentState.title,currentState.url,false);
// End onHashChange closure
return true;
};
History.Adapter.bind(window,'hashchange',History.onHashChange);
/**
* History.pushState(data,title,url)
* Add a new State to the history object, become it, and trigger onpopstate
* We have to trigger for HTML4 compatibility
* @param {object} data
* @param {string} title
* @param {string} url
* @return {true}
*/
History.pushState = function(data,title,url,queue){
//History.debug('History.pushState: called', arguments);
// Check the State
if ( History.getHashByUrl(url) ) {
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
}
// Handle Queueing
if ( queue !== false && History.busy() ) {
// Wait + Push to Queue
//History.debug('History.pushState: we must wait', arguments);
History.pushQueue({
scope: History,
callback: History.pushState,
args: arguments,
queue: queue
});
return false;
}
// Make Busy
History.busy(true);
// Fetch the State Object
var
newState = History.createStateObject(data,title,url),
newStateHash = History.getHashByState(newState),
oldState = History.getState(false),
oldStateHash = History.getHashByState(oldState),
html4Hash = History.getHash();
// Store the newState
History.storeState(newState);
History.expectedStateId = newState.id;
// Recycle the State
History.recycleState(newState);
// Force update of the title
History.setTitle(newState);
// Check if we are the same State
if ( newStateHash === oldStateHash ) {
//History.debug('History.pushState: no change', newStateHash);
History.busy(false);
return false;
}
// Update HTML4 Hash
if ( newStateHash !== html4Hash && newStateHash !== History.getShortUrl(document.location.href) ) {
//History.debug('History.pushState: update hash', newStateHash, html4Hash);
History.setHash(newStateHash,false);
return false;
}
// Update HTML5 State
History.saveState(newState);
// Fire HTML5 Event
//History.debug('History.pushState: trigger popstate');
History.Adapter.trigger(window,'statechange');
History.busy(false);
// End pushState closure
return true;
};
/**
* History.replaceState(data,title,url)
* Replace the State and trigger onpopstate
* We have to trigger for HTML4 compatibility
* @param {object} data
* @param {string} title
* @param {string} url
* @return {true}
*/
History.replaceState = function(data,title,url,queue){
//History.debug('History.replaceState: called', arguments);
// Check the State
if ( History.getHashByUrl(url) ) {
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
}
// Handle Queueing
if ( queue !== false && History.busy() ) {
// Wait + Push to Queue
//History.debug('History.replaceState: we must wait', arguments);
History.pushQueue({
scope: History,
callback: History.replaceState,
args: arguments,
queue: queue
});
return false;
}
// Make Busy
History.busy(true);
// Fetch the State Objects
var
newState = History.createStateObject(data,title,url),
oldState = History.getState(false),
previousState = History.getStateByIndex(-2);
// Discard Old State
History.discardState(oldState,newState,previousState);
// Alias to PushState
History.pushState(newState.data,newState.title,newState.url,false);
// End replaceState closure
return true;
};
/**
* Ensure initial state is handled correctly
*/
if ( History.getHash() && !History.emulated.hashChange ) {
History.Adapter.onDomLoad(function(){
History.Adapter.trigger(window,'hashchange');
});
}
} // History.emulated.pushState
}; // History.initHtml4
// Try and Initialise History
History.init();
})(window);

View File

@ -0,0 +1,1867 @@
/**
* History.js Core
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
*/
(function(window,undefined){
"use strict";
// --------------------------------------------------------------------------
// Initialise
// Localise Globals
var
console = window.console||undefined, // Prevent a JSLint complain
document = window.document, // Make sure we are using the correct document
navigator = window.navigator, // Make sure we are using the correct navigator
amplify = window.amplify||false, // Amplify.js
setTimeout = window.setTimeout,
clearTimeout = window.clearTimeout,
setInterval = window.setInterval,
clearInterval = window.clearInterval,
JSON = window.JSON,
History = window.History = window.History||{}, // Public History Object
history = window.history; // Old History Object
// MooTools Compatibility
JSON.stringify = JSON.stringify||JSON.encode;
JSON.parse = JSON.parse||JSON.decode;
// Check Existence
if ( typeof History.init !== 'undefined' ) {
throw new Error('History.js Core has already been loaded...');
}
// Initialise History
History.init = function(){
// Check Load Status of Adapter
if ( typeof History.Adapter === 'undefined' ) {
return false;
}
// Check Load Status of Core
if ( typeof History.initCore !== 'undefined' ) {
History.initCore();
}
// Check Load Status of HTML4 Support
if ( typeof History.initHtml4 !== 'undefined' ) {
History.initHtml4();
}
// Return true
return true;
};
// --------------------------------------------------------------------------
// Initialise Core
// Initialise Core
History.initCore = function(){
// Initialise
if ( typeof History.initCore.initialized !== 'undefined' ) {
// Already Loaded
return false;
}
else {
History.initCore.initialized = true;
}
// ----------------------------------------------------------------------
// Options
/**
* History.options
* Configurable options
*/
History.options = History.options||{};
/**
* History.options.hashChangeInterval
* How long should the interval be before hashchange checks
*/
History.options.hashChangeInterval = History.options.hashChangeInterval || 100;
/**
* History.options.safariPollInterval
* How long should the interval be before safari poll checks
*/
History.options.safariPollInterval = History.options.safariPollInterval || 500;
/**
* History.options.doubleCheckInterval
* How long should the interval be before we perform a double check
*/
History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500;
/**
* History.options.storeInterval
* How long should we wait between store calls
*/
History.options.storeInterval = History.options.storeInterval || 1000;
/**
* History.options.busyDelay
* How long should we wait between busy events
*/
History.options.busyDelay = History.options.busyDelay || 250;
/**
* History.options.debug
* If true will enable debug messages to be logged
*/
History.options.debug = History.options.debug || false;
/**
* History.options.initialTitle
* What is the title of the initial state
*/
History.options.initialTitle = History.options.initialTitle || document.title;
// ----------------------------------------------------------------------
// Interval record
/**
* History.intervalList
* List of intervals set, to be cleared when document is unloaded.
*/
History.intervalList = [];
/**
* History.clearAllIntervals
* Clears all setInterval instances.
*/
History.clearAllIntervals = function(){
var i, il = History.intervalList;
if (typeof il !== "undefined" && il !== null) {
for (i = 0; i < il.length; i++) {
clearInterval(il[i]);
}
History.intervalList = null;
}
};
History.Adapter.bind(window,"beforeunload",History.clearAllIntervals);
History.Adapter.bind(window,"unload",History.clearAllIntervals);
// ----------------------------------------------------------------------
// Debug
/**
* History.debug(message,...)
* Logs the passed arguments if debug enabled
*/
History.debug = function(){
if ( (History.options.debug||false) ) {
History.log.apply(History,arguments);
}
};
/**
* History.log(message,...)
* Logs the passed arguments
*/
History.log = function(){
// Prepare
var
consoleExists = !(typeof console === 'undefined' || typeof console.log === 'undefined' || typeof console.log.apply === 'undefined'),
textarea = document.getElementById('log'),
message,
i,n
;
// Write to Console
if ( consoleExists ) {
var args = Array.prototype.slice.call(arguments);
message = args.shift();
if ( typeof console.debug !== 'undefined' ) {
console.debug.apply(console,[message,args]);
}
else {
console.log.apply(console,[message,args]);
}
}
else {
message = ("\n"+arguments[0]+"\n");
}
// Write to log
for ( i=1,n=arguments.length; i<n; ++i ) {
var arg = arguments[i];
if ( typeof arg === 'object' && typeof JSON !== 'undefined' ) {
try {
arg = JSON.stringify(arg);
}
catch ( Exception ) {
// Recursive Object
}
}
message += "\n"+arg+"\n";
}
// Textarea
if ( textarea ) {
textarea.value += message+"\n-----\n";
textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight;
}
// No Textarea, No Console
else if ( !consoleExists ) {
alert(message);
}
// Return true
return true;
};
// ----------------------------------------------------------------------
// Emulated Status
/**
* History.getInternetExplorerMajorVersion()
* Get's the major version of Internet Explorer
* @return {integer}
* @license Public Domain
* @author Benjamin Arthur Lupton <contact@balupton.com>
* @author James Padolsey <https://gist.github.com/527683>
*/
History.getInternetExplorerMajorVersion = function(){
var result = History.getInternetExplorerMajorVersion.cached =
(typeof History.getInternetExplorerMajorVersion.cached !== 'undefined')
? History.getInternetExplorerMajorVersion.cached
: (function(){
var v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while ( (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0] ) {}
return (v > 4) ? v : false;
})()
;
return result;
};
/**
* History.isInternetExplorer()
* Are we using Internet Explorer?
* @return {boolean}
* @license Public Domain
* @author Benjamin Arthur Lupton <contact@balupton.com>
*/
History.isInternetExplorer = function(){
var result =
History.isInternetExplorer.cached =
(typeof History.isInternetExplorer.cached !== 'undefined')
? History.isInternetExplorer.cached
: Boolean(History.getInternetExplorerMajorVersion())
;
return result;
};
/**
* History.emulated
* Which features require emulating?
*/
History.emulated = {
pushState: !Boolean(
window.history && window.history.pushState && window.history.replaceState
&& !(
(/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */
|| (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
)
),
hashChange: Boolean(
!(('onhashchange' in window) || ('onhashchange' in document))
||
(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)
)
};
/**
* History.enabled
* Is History enabled?
*/
History.enabled = !History.emulated.pushState;
/**
* History.bugs
* Which bugs are present
*/
History.bugs = {
/**
* Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call
* https://bugs.webkit.org/show_bug.cgi?id=56249
*/
setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
/**
* Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions
* https://bugs.webkit.org/show_bug.cgi?id=42940
*/
safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
/**
* MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
*/
ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8),
/**
* MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event
*/
hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7)
};
/**
* History.isEmptyObject(obj)
* Checks to see if the Object is Empty
* @param {Object} obj
* @return {boolean}
*/
History.isEmptyObject = function(obj) {
for ( var name in obj ) {
return false;
}
return true;
};
/**
* History.cloneObject(obj)
* Clones a object
* @param {Object} obj
* @return {Object}
*/
History.cloneObject = function(obj) {
var hash,newObj;
if ( obj ) {
hash = JSON.stringify(obj);
newObj = JSON.parse(hash);
}
else {
newObj = {};
}
return newObj;
};
// ----------------------------------------------------------------------
// URL Helpers
/**
* History.getRootUrl()
* Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com"
* @return {String} rootUrl
*/
History.getRootUrl = function(){
// Create
var rootUrl = document.location.protocol+'//'+(document.location.hostname||document.location.host);
if ( document.location.port||false ) {
rootUrl += ':'+document.location.port;
}
rootUrl += '/';
// Return
return rootUrl;
};
/**
* History.getBaseHref()
* Fetches the `href` attribute of the `<base href="...">` element if it exists
* @return {String} baseHref
*/
History.getBaseHref = function(){
// Create
var
baseElements = document.getElementsByTagName('base'),
baseElement = null,
baseHref = '';
// Test for Base Element
if ( baseElements.length === 1 ) {
// Prepare for Base Element
baseElement = baseElements[0];
baseHref = baseElement.href.replace(/[^\/]+$/,'');
}
// Adjust trailing slash
baseHref = baseHref.replace(/\/+$/,'');
if ( baseHref ) baseHref += '/';
// Return
return baseHref;
};
/**
* History.getBaseUrl()
* Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first)
* @return {String} baseUrl
*/
History.getBaseUrl = function(){
// Create
var baseUrl = History.getBaseHref()||History.getBasePageUrl()||History.getRootUrl();
// Return
return baseUrl;
};
/**
* History.getPageUrl()
* Fetches the URL of the current page
* @return {String} pageUrl
*/
History.getPageUrl = function(){
// Fetch
var
State = History.getState(false,false),
stateUrl = (State||{}).url||document.location.href;
// Create
var pageUrl = stateUrl.replace(/\/+$/,'').replace(/[^\/]+$/,function(part,index,string){
return (/\./).test(part) ? part : part+'/';
});
// Return
return pageUrl;
};
/**
* History.getBasePageUrl()
* Fetches the Url of the directory of the current page
* @return {String} basePageUrl
*/
History.getBasePageUrl = function(){
// Create
var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
return (/[^\/]$/).test(part) ? '' : part;
}).replace(/\/+$/,'')+'/';
// Return
return basePageUrl;
};
/**
* History.getFullUrl(url)
* Ensures that we have an absolute URL and not a relative URL
* @param {string} url
* @param {Boolean} allowBaseHref
* @return {string} fullUrl
*/
History.getFullUrl = function(url,allowBaseHref){
// Prepare
var fullUrl = url, firstChar = url.substring(0,1);
allowBaseHref = (typeof allowBaseHref === 'undefined') ? true : allowBaseHref;
// Check
if ( /[a-z]+\:\/\//.test(url) ) {
// Full URL
}
else if ( firstChar === '/' ) {
// Root URL
fullUrl = History.getRootUrl()+url.replace(/^\/+/,'');
}
else if ( firstChar === '#' ) {
// Anchor URL
fullUrl = History.getPageUrl().replace(/#.*/,'')+url;
}
else if ( firstChar === '?' ) {
// Query URL
fullUrl = History.getPageUrl().replace(/[\?#].*/,'')+url;
}
else {
// Relative URL
if ( allowBaseHref ) {
fullUrl = History.getBaseUrl()+url.replace(/^(\.\/)+/,'');
} else {
fullUrl = History.getBasePageUrl()+url.replace(/^(\.\/)+/,'');
}
// We have an if condition above as we do not want hashes
// which are relative to the baseHref in our URLs
// as if the baseHref changes, then all our bookmarks
// would now point to different locations
// whereas the basePageUrl will always stay the same
}
// Return
return fullUrl.replace(/\#$/,'');
};
/**
* History.getShortUrl(url)
* Ensures that we have a relative URL and not a absolute URL
* @param {string} url
* @return {string} url
*/
History.getShortUrl = function(url){
// Prepare
var shortUrl = url, baseUrl = History.getBaseUrl(), rootUrl = History.getRootUrl();
// Trim baseUrl
if ( History.emulated.pushState ) {
// We are in a if statement as when pushState is not emulated
// The actual url these short urls are relative to can change
// So within the same session, we the url may end up somewhere different
shortUrl = shortUrl.replace(baseUrl,'');
}
// Trim rootUrl
shortUrl = shortUrl.replace(rootUrl,'/');
// Ensure we can still detect it as a state
if ( History.isTraditionalAnchor(shortUrl) ) {
shortUrl = './'+shortUrl;
}
// Clean It
shortUrl = shortUrl.replace(/^(\.\/)+/g,'./').replace(/\#$/,'');
// Return
return shortUrl;
};
// ----------------------------------------------------------------------
// State Storage
/**
* History.store
* The store for all session specific data
*/
History.store = amplify ? (amplify.store('History.store')||{}) : {};
History.store.idToState = History.store.idToState||{};
History.store.urlToId = History.store.urlToId||{};
History.store.stateToId = History.store.stateToId||{};
/**
* History.idToState
* 1-1: State ID to State Object
*/
History.idToState = History.idToState||{};
/**
* History.stateToId
* 1-1: State String to State ID
*/
History.stateToId = History.stateToId||{};
/**
* History.urlToId
* 1-1: State URL to State ID
*/
History.urlToId = History.urlToId||{};
/**
* History.storedStates
* Store the states in an array
*/
History.storedStates = History.storedStates||[];
/**
* History.savedStates
* Saved the states in an array
*/
History.savedStates = History.savedStates||[];
/**
* History.getState()
* Get an object containing the data, title and url of the current state
* @param {Boolean} friendly
* @param {Boolean} create
* @return {Object} State
*/
History.getState = function(friendly,create){
// Prepare
if ( typeof friendly === 'undefined' ) { friendly = true; }
if ( typeof create === 'undefined' ) { create = true; }
// Fetch
var State = History.getLastSavedState();
// Create
if ( !State && create ) {
State = History.createStateObject();
}
// Adjust
if ( friendly ) {
State = History.cloneObject(State);
State.url = State.cleanUrl||State.url;
}
// Return
return State;
};
/**
* History.getIdByState(State)
* Gets a ID for a State
* @param {State} newState
* @return {String} id
*/
History.getIdByState = function(newState){
// Fetch ID
var id = History.extractId(newState.url);
if ( !id ) {
// Find ID via State String
var str = History.getStateString(newState);
if ( typeof History.stateToId[str] !== 'undefined' ) {
id = History.stateToId[str];
}
else if ( typeof History.store.stateToId[str] !== 'undefined' ) {
id = History.store.stateToId[str];
}
else {
// Generate a new ID
while ( true ) {
id = String(Math.floor(Math.random()*1000));
if ( typeof History.idToState[id] === 'undefined' && typeof History.store.idToState[id] === 'undefined' ) {
break;
}
}
// Apply the new State to the ID
History.stateToId[str] = id;
History.idToState[id] = newState;
}
}
// Return ID
return id;
};
/**
* History.normalizeState(State)
* Expands a State Object
* @param {object} State
* @return {object}
*/
History.normalizeState = function(oldState){
// Prepare
if ( !oldState || (typeof oldState !== 'object') ) {
oldState = {};
}
// Check
if ( typeof oldState.normalized !== 'undefined' ) {
return oldState;
}
// Adjust
if ( !oldState.data || (typeof oldState.data !== 'object') ) {
oldState.data = {};
}
// ----------------------------------------------------------------------
// Create
var newState = {};
newState.normalized = true;
newState.title = oldState.title||'';
newState.url = History.getFullUrl(History.unescapeString(oldState.url||document.location.href));
newState.hash = History.getShortUrl(newState.url);
newState.data = History.cloneObject(oldState.data);
// Fetch ID
newState.id = History.getIdByState(newState);
// ----------------------------------------------------------------------
// Clean the URL
newState.cleanUrl = newState.url.replace(/\??\&_suid.*/,'');
newState.url = newState.cleanUrl;
// Check to see if we have more than just a url
var dataNotEmpty = !History.isEmptyObject(newState.data);
// Apply
if ( newState.title || dataNotEmpty ) {
// Add ID to Hash
newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/,'');
if ( !/\?/.test(newState.hash) ) {
newState.hash += '?';
}
newState.hash += '&_suid='+newState.id;
}
// Create the Hashed URL
newState.hashedUrl = History.getFullUrl(newState.hash);
// ----------------------------------------------------------------------
// Update the URL if we have a duplicate
if ( (History.emulated.pushState || History.bugs.safariPoll) && History.hasUrlDuplicate(newState) ) {
newState.url = newState.hashedUrl;
}
// ----------------------------------------------------------------------
// Return
return newState;
};
/**
* History.createStateObject(data,title,url)
* Creates a object based on the data, title and url state params
* @param {object} data
* @param {string} title
* @param {string} url
* @return {object}
*/
History.createStateObject = function(data,title,url){
// Hashify
var State = {
'data': data,
'title': title,
'url': url
};
// Expand the State
State = History.normalizeState(State);
// Return object
return State;
};
/**
* History.getStateById(id)
* Get a state by it's UID
* @param {String} id
*/
History.getStateById = function(id){
// Prepare
id = String(id);
// Retrieve
var State = History.idToState[id] || History.store.idToState[id] || undefined;
// Return State
return State;
};
/**
* Get a State's String
* @param {State} passedState
*/
History.getStateString = function(passedState){
// Prepare
var State = History.normalizeState(passedState);
// Clean
var cleanedState = {
data: State.data,
title: passedState.title,
url: passedState.url
};
// Fetch
var str = JSON.stringify(cleanedState);
// Return
return str;
};
/**
* Get a State's ID
* @param {State} passedState
* @return {String} id
*/
History.getStateId = function(passedState){
// Prepare
var State = History.normalizeState(passedState);
// Fetch
var id = State.id;
// Return
return id;
};
/**
* History.getHashByState(State)
* Creates a Hash for the State Object
* @param {State} passedState
* @return {String} hash
*/
History.getHashByState = function(passedState){
// Prepare
var hash, State = History.normalizeState(passedState);
// Fetch
hash = State.hash;
// Return
return hash;
};
/**
* History.extractId(url_or_hash)
* Get a State ID by it's URL or Hash
* @param {string} url_or_hash
* @return {string} id
*/
History.extractId = function ( url_or_hash ) {
// Prepare
var id;
// Extract
var parts,url;
parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash);
url = parts ? (parts[1]||url_or_hash) : url_or_hash;
id = parts ? String(parts[2]||'') : '';
// Return
return id||false;
};
/**
* History.isTraditionalAnchor
* Checks to see if the url is a traditional anchor or not
* @param {String} url_or_hash
* @return {Boolean}
*/
History.isTraditionalAnchor = function(url_or_hash){
// Check
var isTraditional = !(/[\/\?\.]/.test(url_or_hash));
// Return
return isTraditional;
};
/**
* History.extractState
* Get a State by it's URL or Hash
* @param {String} url_or_hash
* @return {State|null}
*/
History.extractState = function(url_or_hash,create){
// Prepare
var State = null;
create = create||false;
// Fetch SUID
var id = History.extractId(url_or_hash);
if ( id ) {
State = History.getStateById(id);
}
// Fetch SUID returned no State
if ( !State ) {
// Fetch URL
var url = History.getFullUrl(url_or_hash);
// Check URL
id = History.getIdByUrl(url)||false;
if ( id ) {
State = History.getStateById(id);
}
// Create State
if ( !State && create && !History.isTraditionalAnchor(url_or_hash) ) {
State = History.createStateObject(null,null,url);
}
}
// Return
return State;
};
/**
* History.getIdByUrl()
* Get a State ID by a State URL
*/
History.getIdByUrl = function(url){
// Fetch
var id = History.urlToId[url] || History.store.urlToId[url] || undefined;
// Return
return id;
};
/**
* History.getLastSavedState()
* Get an object containing the data, title and url of the current state
* @return {Object} State
*/
History.getLastSavedState = function(){
return History.savedStates[History.savedStates.length-1]||undefined;
};
/**
* History.getLastStoredState()
* Get an object containing the data, title and url of the current state
* @return {Object} State
*/
History.getLastStoredState = function(){
return History.storedStates[History.storedStates.length-1]||undefined;
};
/**
* History.hasUrlDuplicate
* Checks if a Url will have a url conflict
* @param {Object} newState
* @return {Boolean} hasDuplicate
*/
History.hasUrlDuplicate = function(newState) {
// Prepare
var hasDuplicate = false;
// Fetch
var oldState = History.extractState(newState.url);
// Check
hasDuplicate = oldState && oldState.id !== newState.id;
// Return
return hasDuplicate;
};
/**
* History.storeState
* Store a State
* @param {Object} newState
* @return {Object} newState
*/
History.storeState = function(newState){
// Store the State
History.urlToId[newState.url] = newState.id;
// Push the State
History.storedStates.push(History.cloneObject(newState));
// Return newState
return newState;
};
/**
* History.isLastSavedState(newState)
* Tests to see if the state is the last state
* @param {Object} newState
* @return {boolean} isLast
*/
History.isLastSavedState = function(newState){
// Prepare
var isLast = false;
// Check
if ( History.savedStates.length ) {
var
newId = newState.id,
oldState = History.getLastSavedState(),
oldId = oldState.id;
// Check
isLast = (newId === oldId);
}
// Return
return isLast;
};
/**
* History.saveState
* Push a State
* @param {Object} newState
* @return {boolean} changed
*/
History.saveState = function(newState){
// Check Hash
if ( History.isLastSavedState(newState) ) {
return false;
}
// Push the State
History.savedStates.push(History.cloneObject(newState));
// Return true
return true;
};
/**
* History.getStateByIndex()
* Gets a state by the index
* @param {integer} index
* @return {Object}
*/
History.getStateByIndex = function(index){
// Prepare
var State = null;
// Handle
if ( typeof index === 'undefined' ) {
// Get the last inserted
State = History.savedStates[History.savedStates.length-1];
}
else if ( index < 0 ) {
// Get from the end
State = History.savedStates[History.savedStates.length+index];
}
else {
// Get from the beginning
State = History.savedStates[index];
}
// Return State
return State;
};
// ----------------------------------------------------------------------
// Hash Helpers
/**
* History.getHash()
* Gets the current document hash
* @return {string}
*/
History.getHash = function(){
var hash = History.unescapeHash(document.location.hash);
return hash;
};
/**
* History.unescapeString()
* Unescape a string
* @param {String} str
* @return {string}
*/
History.unescapeString = function(str){
// Prepare
var result = str;
// Unescape hash
var tmp;
while ( true ) {
tmp = window.unescape(result);
if ( tmp === result ) {
break;
}
result = tmp;
}
// Return result
return result;
};
/**
* History.unescapeHash()
* normalize and Unescape a Hash
* @param {String} hash
* @return {string}
*/
History.unescapeHash = function(hash){
// Prepare
var result = History.normalizeHash(hash);
// Unescape hash
result = History.unescapeString(result);
// Return result
return result;
};
/**
* History.normalizeHash()
* normalize a hash across browsers
* @return {string}
*/
History.normalizeHash = function(hash){
var result = hash.replace(/[^#]*#/,'').replace(/#.*/, '');
// Return result
return result;
};
/**
* History.setHash(hash)
* Sets the document hash
* @param {string} hash
* @return {History}
*/
History.setHash = function(hash,queue){
// Handle Queueing
if ( queue !== false && History.busy() ) {
// Wait + Push to Queue
//History.debug('History.setHash: we must wait', arguments);
History.pushQueue({
scope: History,
callback: History.setHash,
args: arguments,
queue: queue
});
return false;
}
// Log
//History.debug('History.setHash: called',hash);
// Prepare
var adjustedHash = History.escapeHash(hash);
// Make Busy + Continue
History.busy(true);
// Check if hash is a state
var State = History.extractState(hash,true);
if ( State && !History.emulated.pushState ) {
// Hash is a state so skip the setHash
//History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments);
// PushState
History.pushState(State.data,State.title,State.url,false);
}
else if ( document.location.hash !== adjustedHash ) {
// Hash is a proper hash, so apply it
// Handle browser bugs
if ( History.bugs.setHash ) {
// Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249
// Fetch the base page
var pageUrl = History.getPageUrl();
// Safari hash apply
History.pushState(null,null,pageUrl+'#'+adjustedHash,false);
}
else {
// Normal hash apply
document.location.hash = adjustedHash;
}
}
// Chain
return History;
};
/**
* History.escape()
* normalize and Escape a Hash
* @return {string}
*/
History.escapeHash = function(hash){
var result = History.normalizeHash(hash);
// Escape hash
result = window.escape(result);
// IE6 Escape Bug
if ( !History.bugs.hashEscape ) {
// Restore common parts
result = result
.replace(/\%21/g,'!')
.replace(/\%26/g,'&')
.replace(/\%3D/g,'=')
.replace(/\%3F/g,'?');
}
// Return result
return result;
};
/**
* History.getHashByUrl(url)
* Extracts the Hash from a URL
* @param {string} url
* @return {string} url
*/
History.getHashByUrl = function(url){
// Extract the hash
var hash = String(url)
.replace(/([^#]*)#?([^#]*)#?(.*)/, '$2')
;
// Unescape hash
hash = History.unescapeHash(hash);
// Return hash
return hash;
};
/**
* History.setTitle(title)
* Applies the title to the document
* @param {State} newState
* @return {Boolean}
*/
History.setTitle = function(newState){
// Prepare
var title = newState.title;
// Initial
if ( !title ) {
var firstState = History.getStateByIndex(0);
if ( firstState && firstState.url === newState.url ) {
title = firstState.title||History.options.initialTitle;
}
}
// Apply
try {
document.getElementsByTagName('title')[0].innerHTML = title.replace('<','&lt;').replace('>','&gt;').replace(' & ',' &amp; ');
}
catch ( Exception ) { }
document.title = title;
// Chain
return History;
};
// ----------------------------------------------------------------------
// Queueing
/**
* History.queues
* The list of queues to use
* First In, First Out
*/
History.queues = [];
/**
* History.busy(value)
* @param {boolean} value [optional]
* @return {boolean} busy
*/
History.busy = function(value){
// Apply
if ( typeof value !== 'undefined' ) {
//History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length);
History.busy.flag = value;
}
// Default
else if ( typeof History.busy.flag === 'undefined' ) {
History.busy.flag = false;
}
// Queue
if ( !History.busy.flag ) {
// Execute the next item in the queue
clearTimeout(History.busy.timeout);
var fireNext = function(){
if ( History.busy.flag ) return;
for ( var i=History.queues.length-1; i >= 0; --i ) {
var queue = History.queues[i];
if ( queue.length === 0 ) continue;
var item = queue.shift();
History.fireQueueItem(item);
History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
}
};
History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
}
// Return
return History.busy.flag;
};
/**
* History.fireQueueItem(item)
* Fire a Queue Item
* @param {Object} item
* @return {Mixed} result
*/
History.fireQueueItem = function(item){
return item.callback.apply(item.scope||History,item.args||[]);
};
/**
* History.pushQueue(callback,args)
* Add an item to the queue
* @param {Object} item [scope,callback,args,queue]
*/
History.pushQueue = function(item){
// Prepare the queue
History.queues[item.queue||0] = History.queues[item.queue||0]||[];
// Add to the queue
History.queues[item.queue||0].push(item);
// Chain
return History;
};
/**
* History.queue (item,queue), (func,queue), (func), (item)
* Either firs the item now if not busy, or adds it to the queue
*/
History.queue = function(item,queue){
// Prepare
if ( typeof item === 'function' ) {
item = {
callback: item
};
}
if ( typeof queue !== 'undefined' ) {
item.queue = queue;
}
// Handle
if ( History.busy() ) {
History.pushQueue(item);
} else {
History.fireQueueItem(item);
}
// Chain
return History;
};
/**
* History.clearQueue()
* Clears the Queue
*/
History.clearQueue = function(){
History.busy.flag = false;
History.queues = [];
return History;
};
// ----------------------------------------------------------------------
// IE Bug Fix
/**
* History.stateChanged
* States whether or not the state has changed since the last double check was initialised
*/
History.stateChanged = false;
/**
* History.doubleChecker
* Contains the timeout used for the double checks
*/
History.doubleChecker = false;
/**
* History.doubleCheckComplete()
* Complete a double check
* @return {History}
*/
History.doubleCheckComplete = function(){
// Update
History.stateChanged = true;
// Clear
History.doubleCheckClear();
// Chain
return History;
};
/**
* History.doubleCheckClear()
* Clear a double check
* @return {History}
*/
History.doubleCheckClear = function(){
// Clear
if ( History.doubleChecker ) {
clearTimeout(History.doubleChecker);
History.doubleChecker = false;
}
// Chain
return History;
};
/**
* History.doubleCheck()
* Create a double check
* @return {History}
*/
History.doubleCheck = function(tryAgain){
// Reset
History.stateChanged = false;
History.doubleCheckClear();
// Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does)
// Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940
if ( History.bugs.ieDoubleCheck ) {
// Apply Check
History.doubleChecker = setTimeout(
function(){
History.doubleCheckClear();
if ( !History.stateChanged ) {
//History.debug('History.doubleCheck: State has not yet changed, trying again', arguments);
// Re-Attempt
tryAgain();
}
return true;
},
History.options.doubleCheckInterval
);
}
// Chain
return History;
};
// ----------------------------------------------------------------------
// Safari Bug Fix
/**
* History.safariStatePoll()
* Poll the current state
* @return {History}
*/
History.safariStatePoll = function(){
// Poll the URL
// Get the Last State which has the new URL
var
urlState = History.extractState(document.location.href),
newState;
// Check for a difference
if ( !History.isLastSavedState(urlState) ) {
newState = urlState;
}
else {
return;
}
// Check if we have a state with that url
// If not create it
if ( !newState ) {
//History.debug('History.safariStatePoll: new');
newState = History.createStateObject();
}
// Apply the New State
//History.debug('History.safariStatePoll: trigger');
History.Adapter.trigger(window,'popstate');
// Chain
return History;
};
// ----------------------------------------------------------------------
// State Aliases
/**
* History.back(queue)
* Send the browser history back one item
* @param {Integer} queue [optional]
*/
History.back = function(queue){
//History.debug('History.back: called', arguments);
// Handle Queueing
if ( queue !== false && History.busy() ) {
// Wait + Push to Queue
//History.debug('History.back: we must wait', arguments);
History.pushQueue({
scope: History,
callback: History.back,
args: arguments,
queue: queue
});
return false;
}
// Make Busy + Continue
History.busy(true);
// Fix certain browser bugs that prevent the state from changing
History.doubleCheck(function(){
History.back(false);
});
// Go back
history.go(-1);
// End back closure
return true;
};
/**
* History.forward(queue)
* Send the browser history forward one item
* @param {Integer} queue [optional]
*/
History.forward = function(queue){
//History.debug('History.forward: called', arguments);
// Handle Queueing
if ( queue !== false && History.busy() ) {
// Wait + Push to Queue
//History.debug('History.forward: we must wait', arguments);
History.pushQueue({
scope: History,
callback: History.forward,
args: arguments,
queue: queue
});
return false;
}
// Make Busy + Continue
History.busy(true);
// Fix certain browser bugs that prevent the state from changing
History.doubleCheck(function(){
History.forward(false);
});
// Go forward
history.go(1);
// End forward closure
return true;
};
/**
* History.go(index,queue)
* Send the browser history back or forward index times
* @param {Integer} queue [optional]
*/
History.go = function(index,queue){
//History.debug('History.go: called', arguments);
// Prepare
var i;
// Handle
if ( index > 0 ) {
// Forward
for ( i=1; i<=index; ++i ) {
History.forward(queue);
}
}
else if ( index < 0 ) {
// Backward
for ( i=-1; i>=index; --i ) {
History.back(queue);
}
}
else {
throw new Error('History.go: History.go requires a positive or negative integer passed.');
}
// Chain
return History;
};
// ----------------------------------------------------------------------
// Initialise
/**
* Create the initial State
*/
History.saveState(History.storeState(History.extractState(document.location.href,true)));
/**
* Bind for Saving Store
*/
if ( amplify ) {
History.onUnload = function(){
// Prepare
var
currentStore = amplify.store('History.store')||{},
item;
// Ensure
currentStore.idToState = currentStore.idToState || {};
currentStore.urlToId = currentStore.urlToId || {};
currentStore.stateToId = currentStore.stateToId || {};
// Sync
for ( item in History.idToState ) {
if ( !History.idToState.hasOwnProperty(item) ) {
continue;
}
currentStore.idToState[item] = History.idToState[item];
}
for ( item in History.urlToId ) {
if ( !History.urlToId.hasOwnProperty(item) ) {
continue;
}
currentStore.urlToId[item] = History.urlToId[item];
}
for ( item in History.stateToId ) {
if ( !History.stateToId.hasOwnProperty(item) ) {
continue;
}
currentStore.stateToId[item] = History.stateToId[item];
}
// Update
History.store = currentStore;
// Store
amplify.store('History.store',currentStore);
};
// For Internet Explorer
History.intervalList.push(setInterval(History.onUnload,History.options.storeInterval));
// For Other Browsers
History.Adapter.bind(window,'beforeunload',History.onUnload);
History.Adapter.bind(window,'unload',History.onUnload);
// Both are enabled for consistency
}
// ----------------------------------------------------------------------
// HTML5 State Support
if ( History.emulated.pushState ) {
/*
* Provide Skeleton for HTML4 Browsers
*/
// Prepare
var emptyFunction = function(){};
History.pushState = History.pushState||emptyFunction;
History.replaceState = History.replaceState||emptyFunction;
}
else {
/*
* Use native HTML5 History API Implementation
*/
/**
* History.onPopState(event,extra)
* Refresh the Current State
*/
History.onPopState = function(event){
// Reset the double check
History.doubleCheckComplete();
// Check for a Hash, and handle apporiatly
var currentHash = History.getHash();
if ( currentHash ) {
// Expand Hash
var currentState = History.extractState(currentHash||document.location.href,true);
if ( currentState ) {
// We were able to parse it, it must be a State!
// Let's forward to replaceState
//History.debug('History.onPopState: state anchor', currentHash, currentState);
History.replaceState(currentState.data, currentState.title, currentState.url, false);
}
else {
// Traditional Anchor
//History.debug('History.onPopState: traditional anchor', currentHash);
History.Adapter.trigger(window,'anchorchange');
History.busy(false);
}
// We don't care for hashes
History.expectedStateId = false;
return false;
}
// Prepare
var newState = false;
// Prepare
event = event||{};
if ( typeof event.state === 'undefined' ) {
// jQuery
if ( typeof event.originalEvent !== 'undefined' && typeof event.originalEvent.state !== 'undefined' ) {
event.state = event.originalEvent.state||false;
}
// MooTools
else if ( typeof event.event !== 'undefined' && typeof event.event.state !== 'undefined' ) {
event.state = event.event.state||false;
}
}
// Ensure
event.state = (event.state||false);
// Fetch State
if ( event.state ) {
// Vanilla: Back/forward button was used
newState = History.getStateById(event.state);
}
else if ( History.expectedStateId ) {
// Vanilla: A new state was pushed, and popstate was called manually
newState = History.getStateById(History.expectedStateId);
}
else {
// Initial State
newState = History.extractState(document.location.href);
}
// The State did not exist in our store
if ( !newState ) {
// Regenerate the State
newState = History.createStateObject(null,null,document.location.href);
}
// Clean
History.expectedStateId = false;
// Check if we are the same state
if ( History.isLastSavedState(newState) ) {
// There has been no change (just the page's hash has finally propagated)
//History.debug('History.onPopState: no change', newState, History.savedStates);
History.busy(false);
return false;
}
// Store the State
History.storeState(newState);
History.saveState(newState);
// Force update of the title
History.setTitle(newState);
// Fire Our Event
History.Adapter.trigger(window,'statechange');
History.busy(false);
// Return true
return true;
};
History.Adapter.bind(window,'popstate',History.onPopState);
/**
* History.pushState(data,title,url)
* Add a new State to the history object, become it, and trigger onpopstate
* We have to trigger for HTML4 compatibility
* @param {object} data
* @param {string} title
* @param {string} url
* @return {true}
*/
History.pushState = function(data,title,url,queue){
//History.debug('History.pushState: called', arguments);
// Check the State
if ( History.getHashByUrl(url) && History.emulated.pushState ) {
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
}
// Handle Queueing
if ( queue !== false && History.busy() ) {
// Wait + Push to Queue
//History.debug('History.pushState: we must wait', arguments);
History.pushQueue({
scope: History,
callback: History.pushState,
args: arguments,
queue: queue
});
return false;
}
// Make Busy + Continue
History.busy(true);
// Create the newState
var newState = History.createStateObject(data,title,url);
// Check it
if ( History.isLastSavedState(newState) ) {
// Won't be a change
History.busy(false);
}
else {
// Store the newState
History.storeState(newState);
History.expectedStateId = newState.id;
// Push the newState
history.pushState(newState.id,newState.title,newState.url);
// Fire HTML5 Event
History.Adapter.trigger(window,'popstate');
}
// End pushState closure
return true;
};
/**
* History.replaceState(data,title,url)
* Replace the State and trigger onpopstate
* We have to trigger for HTML4 compatibility
* @param {object} data
* @param {string} title
* @param {string} url
* @return {true}
*/
History.replaceState = function(data,title,url,queue){
//History.debug('History.replaceState: called', arguments);
// Check the State
if ( History.getHashByUrl(url) && History.emulated.pushState ) {
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
}
// Handle Queueing
if ( queue !== false && History.busy() ) {
// Wait + Push to Queue
//History.debug('History.replaceState: we must wait', arguments);
History.pushQueue({
scope: History,
callback: History.replaceState,
args: arguments,
queue: queue
});
return false;
}
// Make Busy + Continue
History.busy(true);
// Create the newState
var newState = History.createStateObject(data,title,url);
// Check it
if ( History.isLastSavedState(newState) ) {
// Won't be a change
History.busy(false);
}
else {
// Store the newState
History.storeState(newState);
History.expectedStateId = newState.id;
// Push the newState
history.replaceState(newState.id,newState.title,newState.url);
// Fire HTML5 Event
History.Adapter.trigger(window,'popstate');
}
// End replaceState closure
return true;
};
// Be aware, the following is only for native pushState implementations
// If you are wanting to include something for all browsers
// Then include it above this if block
/**
* Setup Safari Fix
*/
if ( History.bugs.safariPoll ) {
History.intervalList.push(setInterval(History.safariStatePoll, History.options.safariPollInterval));
}
/**
* Ensure Cross Browser Compatibility
*/
if ( navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName||'') === 'Mozilla' ) {
/**
* Fix Safari HashChange Issue
*/
// Setup Alias
History.Adapter.bind(window,'hashchange',function(){
History.Adapter.trigger(window,'popstate');
});
// Initialise Alias
if ( History.getHash() ) {
History.Adapter.onDomLoad(function(){
History.Adapter.trigger(window,'hashchange');
});
}
}
} // !History.emulated.pushState
}; // History.initCore
// Try and Initialise History
History.init();
})(window);

View File

@ -0,0 +1,480 @@
/*
http://www.JSON.org/json2.js
2011-01-18
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
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';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false, regexp: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON;
if (!JSON) {
JSON = {};
}
(function () {
"use strict";
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' : gap ?
'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' : gap ?
'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
'{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());