mirror of
https://github.com/placeholder-soft/prodigyapi.git
synced 2026-01-12 22:44:57 +08:00
Static table of contents (#701)
* Add showing/hiding submenus, fix sidebar styling, fix bug where includes wouldn't appear in ToC * Update ToC to highlight last header if page is scrolled to very bottom, fixes #280 * Set HTML title to current h1 section text, see #133 * Fix menu not opening on mobile * Add back increase toc item height on mobile * Fix padding bug * Add back in ToC sliding animation
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -7,3 +7,4 @@ gem 'middleman-autoprefixer', '~> 2.7.0'
|
||||
gem "middleman-sprockets", "~> 4.1.0"
|
||||
gem 'rouge', '~> 2.0.5'
|
||||
gem 'redcarpet', '~> 3.4.0'
|
||||
gem 'nokogiri', '~> 1.6.8'
|
||||
|
||||
@@ -79,7 +79,10 @@ GEM
|
||||
middleman-syntax (3.0.0)
|
||||
middleman-core (>= 3.2)
|
||||
rouge (~> 2.0)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.10.1)
|
||||
nokogiri (1.6.8.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
padrino-helpers (0.13.3.3)
|
||||
i18n (~> 0.6, >= 0.6.7)
|
||||
padrino-support (= 0.13.3.3)
|
||||
@@ -115,8 +118,9 @@ DEPENDENCIES
|
||||
middleman-autoprefixer (~> 2.7.0)
|
||||
middleman-sprockets (~> 4.1.0)
|
||||
middleman-syntax (~> 3.0.0)
|
||||
nokogiri (~> 1.6.8)
|
||||
redcarpet (~> 3.4.0)
|
||||
rouge (~> 2.0.5)
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.3
|
||||
1.14.5
|
||||
|
||||
@@ -47,3 +47,7 @@ end
|
||||
# Deploy Configuration
|
||||
# If you want Middleman to listen on a different port, you can set that below
|
||||
set :port, 4567
|
||||
|
||||
helpers do
|
||||
require './lib/toc_data.rb'
|
||||
end
|
||||
|
||||
30
lib/toc_data.rb
Normal file
30
lib/toc_data.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
require 'nokogiri'
|
||||
|
||||
def toc_data(page_content)
|
||||
html_doc = Nokogiri::HTML::DocumentFragment.parse(page_content)
|
||||
|
||||
# get a flat list of headers
|
||||
headers = []
|
||||
html_doc.css('h1, h2, h3').each do |header|
|
||||
headers.push({
|
||||
id: header.attribute('id').to_s,
|
||||
content: header.content,
|
||||
level: header.name[1].to_i,
|
||||
children: []
|
||||
})
|
||||
end
|
||||
|
||||
[3,2].each do |header_level|
|
||||
header_to_nest = nil
|
||||
headers = headers.reject do |header|
|
||||
if header[:level] == header_level
|
||||
header_to_nest[:children].push header if header_to_nest
|
||||
true
|
||||
else
|
||||
header_to_nest = header if header[:level] == (header_level - 1)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
headers
|
||||
end
|
||||
@@ -1,4 +1,2 @@
|
||||
//= require ./lib/_energize
|
||||
//= require ./app/_lang
|
||||
//= require ./all_nosearch
|
||||
//= require ./app/_search
|
||||
//= require ./app/_toc
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
//= require ./lib/_energize
|
||||
//= require ./app/_lang
|
||||
//= require ./app/_toc
|
||||
//= require ./app/_lang
|
||||
|
||||
$(function() {
|
||||
loadToc($('#toc'), '.toc-link', '.toc-list-h2', 10);
|
||||
setupLanguages($('body').data('languages'));
|
||||
$('.content').imagesLoaded( function() {
|
||||
window.recacheHeights();
|
||||
window.refreshToc();
|
||||
});
|
||||
});
|
||||
|
||||
window.onpopstate = function() {
|
||||
activateLanguage(getLanguageFromQueryString());
|
||||
};
|
||||
|
||||
@@ -15,13 +15,14 @@ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
(function (global) {
|
||||
;(function () {
|
||||
'use strict';
|
||||
|
||||
var languages = [];
|
||||
|
||||
global.setupLanguages = setupLanguages;
|
||||
global.activateLanguage = activateLanguage;
|
||||
window.setupLanguages = setupLanguages;
|
||||
window.activateLanguage = activateLanguage;
|
||||
window.getLanguageFromQueryString = getLanguageFromQueryString;
|
||||
|
||||
function activateLanguage(language) {
|
||||
if (!language) return;
|
||||
@@ -36,7 +37,7 @@ under the License.
|
||||
$(".highlight.tab-" + language).show();
|
||||
$(".lang-specific." + language).show();
|
||||
|
||||
global.toc.calculateHeights();
|
||||
window.recacheHeights();
|
||||
|
||||
// scroll to the new location of the position
|
||||
if ($(window.location.hash).get(0)) {
|
||||
@@ -159,8 +160,5 @@ under the License.
|
||||
activateLanguage(language);
|
||||
return false;
|
||||
});
|
||||
window.onpopstate = function() {
|
||||
activateLanguage(getLanguageFromQueryString());
|
||||
};
|
||||
});
|
||||
})(window);
|
||||
})();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//= require ../lib/_lunr
|
||||
//= require ../lib/_jquery
|
||||
//= require ../lib/_jquery.highlight
|
||||
(function () {
|
||||
;(function () {
|
||||
'use strict';
|
||||
|
||||
var content, searchResults;
|
||||
|
||||
@@ -1,57 +1,106 @@
|
||||
//= require ../lib/_jquery
|
||||
//= require ../lib/_jquery_ui
|
||||
//= require ../lib/_jquery.tocify
|
||||
//= require ../lib/_imagesloaded.min
|
||||
(function (global) {
|
||||
;(function () {
|
||||
'use strict';
|
||||
|
||||
var debounce = function(func, waitTime) {
|
||||
var timeout = false;
|
||||
return function() {
|
||||
if (timeout === false) {
|
||||
setTimeout(function() {
|
||||
func();
|
||||
timeout = false;
|
||||
}, waitTime);
|
||||
timeout = true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var closeToc = function() {
|
||||
$(".tocify-wrapper").removeClass('open');
|
||||
$("#nav-button").removeClass('open');
|
||||
};
|
||||
|
||||
var makeToc = function() {
|
||||
global.toc = $("#toc").tocify({
|
||||
selectors: 'h1, h2',
|
||||
extendPage: false,
|
||||
theme: 'none',
|
||||
smoothScroll: false,
|
||||
showEffectSpeed: 0,
|
||||
hideEffectSpeed: 180,
|
||||
ignoreSelector: '.toc-ignore',
|
||||
highlightOffset: 60,
|
||||
scrollTo: -1,
|
||||
scrollHistory: true,
|
||||
hashGenerator: function (text, element) {
|
||||
return element.prop('id');
|
||||
function loadToc($toc, tocLinkSelector, tocListSelector, scrollOffset) {
|
||||
var headerHeights = {};
|
||||
var pageHeight = 0;
|
||||
var windowHeight = 0;
|
||||
var originalTitle = document.title;
|
||||
|
||||
var recacheHeights = function() {
|
||||
headerHeights = {};
|
||||
pageHeight = $(document).height();
|
||||
windowHeight = $(window).height();
|
||||
|
||||
$toc.find(tocLinkSelector).each(function() {
|
||||
var targetId = $(this).attr('href');
|
||||
if (targetId[0] === "#") {
|
||||
headerHeights[targetId] = $(targetId).offset().top;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var refreshToc = function() {
|
||||
var currentTop = $(document).scrollTop() + scrollOffset;
|
||||
|
||||
if (currentTop + windowHeight >= pageHeight) {
|
||||
// at bottom of page, so just select last header by making currentTop very large
|
||||
// this fixes the problem where the last header won't ever show as active if its content
|
||||
// is shorter than the window height
|
||||
currentTop = pageHeight + 1000;
|
||||
}
|
||||
}).data('toc-tocify');
|
||||
|
||||
$("#nav-button").click(function() {
|
||||
$(".tocify-wrapper").toggleClass('open');
|
||||
$("#nav-button").toggleClass('open');
|
||||
return false;
|
||||
});
|
||||
var best = null;
|
||||
for (var name in headerHeights) {
|
||||
if ((headerHeights[name] < currentTop && headerHeights[name] > headerHeights[best]) || best === null) {
|
||||
best = name;
|
||||
}
|
||||
}
|
||||
|
||||
$(".page-wrapper").click(closeToc);
|
||||
$(".tocify-item").click(closeToc);
|
||||
};
|
||||
var $best = $toc.find("[href='" + best + "']").first();
|
||||
if (!$best.hasClass("active")) {
|
||||
$toc.find(".active").removeClass("active");
|
||||
$best.addClass("active");
|
||||
$best.parents(tocListSelector).addClass("active");
|
||||
$best.siblings(tocListSelector).addClass("active");
|
||||
$toc.find(tocListSelector).filter(":not(.active)").slideUp(150);
|
||||
$toc.find(tocListSelector).filter(".active").slideDown(150);
|
||||
if (window.history.pushState) {
|
||||
window.history.pushState(null, "", best);
|
||||
}
|
||||
// TODO remove classnames
|
||||
document.title = $best.data("title") + " – " + originalTitle;
|
||||
}
|
||||
};
|
||||
|
||||
// Hack to make already open sections to start opened,
|
||||
// instead of displaying an ugly animation
|
||||
function animate() {
|
||||
setTimeout(function() {
|
||||
toc.setOption('showEffectSpeed', 180);
|
||||
}, 50);
|
||||
var makeToc = function() {
|
||||
recacheHeights();
|
||||
refreshToc();
|
||||
|
||||
$("#nav-button").click(function() {
|
||||
$(".toc-wrapper").toggleClass('open');
|
||||
$("#nav-button").toggleClass('open');
|
||||
return false;
|
||||
});
|
||||
$(".page-wrapper").click(closeToc);
|
||||
$(".tocify-item").click(closeToc);
|
||||
|
||||
// reload immediately after scrolling on toc click
|
||||
$toc.find(tocLinkSelector).click(function() {
|
||||
setTimeout(function() {
|
||||
refreshToc();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$(window).scroll(debounce(refreshToc, 200));
|
||||
$(window).resize(debounce(recacheHeights, 200));
|
||||
};
|
||||
|
||||
makeToc();
|
||||
|
||||
window.recacheHeights = recacheHeights;
|
||||
window.refreshToc = refreshToc;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
makeToc();
|
||||
animate();
|
||||
setupLanguages($('body').data('languages'));
|
||||
$('.content').imagesLoaded( function() {
|
||||
global.toc.calculateHeights();
|
||||
});
|
||||
});
|
||||
})(window);
|
||||
|
||||
window.loadToc = loadToc;
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,566 +0,0 @@
|
||||
/*! jQuery UI - v1.11.3 - 2015-02-12
|
||||
* http://jqueryui.com
|
||||
* Includes: widget.js
|
||||
* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
|
||||
|
||||
(function( factory ) {
|
||||
if ( typeof define === "function" && define.amd ) {
|
||||
|
||||
// AMD. Register as an anonymous module.
|
||||
define([ "jquery" ], factory );
|
||||
} else {
|
||||
|
||||
// Browser globals
|
||||
factory( jQuery );
|
||||
}
|
||||
}(function( $ ) {
|
||||
/*!
|
||||
* jQuery UI Widget 1.11.3
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://api.jqueryui.com/jQuery.widget/
|
||||
*/
|
||||
|
||||
|
||||
var widget_uuid = 0,
|
||||
widget_slice = Array.prototype.slice;
|
||||
|
||||
$.cleanData = (function( orig ) {
|
||||
return function( elems ) {
|
||||
var events, elem, i;
|
||||
for ( i = 0; (elem = elems[i]) != null; i++ ) {
|
||||
try {
|
||||
|
||||
// Only trigger remove when necessary to save time
|
||||
events = $._data( elem, "events" );
|
||||
if ( events && events.remove ) {
|
||||
$( elem ).triggerHandler( "remove" );
|
||||
}
|
||||
|
||||
// http://bugs.jquery.com/ticket/8235
|
||||
} catch ( e ) {}
|
||||
}
|
||||
orig( elems );
|
||||
};
|
||||
})( $.cleanData );
|
||||
|
||||
$.widget = function( name, base, prototype ) {
|
||||
var fullName, existingConstructor, constructor, basePrototype,
|
||||
// proxiedPrototype allows the provided prototype to remain unmodified
|
||||
// so that it can be used as a mixin for multiple widgets (#8876)
|
||||
proxiedPrototype = {},
|
||||
namespace = name.split( "." )[ 0 ];
|
||||
|
||||
name = name.split( "." )[ 1 ];
|
||||
fullName = namespace + "-" + name;
|
||||
|
||||
if ( !prototype ) {
|
||||
prototype = base;
|
||||
base = $.Widget;
|
||||
}
|
||||
|
||||
// create selector for plugin
|
||||
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
|
||||
return !!$.data( elem, fullName );
|
||||
};
|
||||
|
||||
$[ namespace ] = $[ namespace ] || {};
|
||||
existingConstructor = $[ namespace ][ name ];
|
||||
constructor = $[ namespace ][ name ] = function( options, element ) {
|
||||
// allow instantiation without "new" keyword
|
||||
if ( !this._createWidget ) {
|
||||
return new constructor( options, element );
|
||||
}
|
||||
|
||||
// allow instantiation without initializing for simple inheritance
|
||||
// must use "new" keyword (the code above always passes args)
|
||||
if ( arguments.length ) {
|
||||
this._createWidget( options, element );
|
||||
}
|
||||
};
|
||||
// extend with the existing constructor to carry over any static properties
|
||||
$.extend( constructor, existingConstructor, {
|
||||
version: prototype.version,
|
||||
// copy the object used to create the prototype in case we need to
|
||||
// redefine the widget later
|
||||
_proto: $.extend( {}, prototype ),
|
||||
// track widgets that inherit from this widget in case this widget is
|
||||
// redefined after a widget inherits from it
|
||||
_childConstructors: []
|
||||
});
|
||||
|
||||
basePrototype = new base();
|
||||
// we need to make the options hash a property directly on the new instance
|
||||
// otherwise we'll modify the options hash on the prototype that we're
|
||||
// inheriting from
|
||||
basePrototype.options = $.widget.extend( {}, basePrototype.options );
|
||||
$.each( prototype, function( prop, value ) {
|
||||
if ( !$.isFunction( value ) ) {
|
||||
proxiedPrototype[ prop ] = value;
|
||||
return;
|
||||
}
|
||||
proxiedPrototype[ prop ] = (function() {
|
||||
var _super = function() {
|
||||
return base.prototype[ prop ].apply( this, arguments );
|
||||
},
|
||||
_superApply = function( args ) {
|
||||
return base.prototype[ prop ].apply( this, args );
|
||||
};
|
||||
return function() {
|
||||
var __super = this._super,
|
||||
__superApply = this._superApply,
|
||||
returnValue;
|
||||
|
||||
this._super = _super;
|
||||
this._superApply = _superApply;
|
||||
|
||||
returnValue = value.apply( this, arguments );
|
||||
|
||||
this._super = __super;
|
||||
this._superApply = __superApply;
|
||||
|
||||
return returnValue;
|
||||
};
|
||||
})();
|
||||
});
|
||||
constructor.prototype = $.widget.extend( basePrototype, {
|
||||
// TODO: remove support for widgetEventPrefix
|
||||
// always use the name + a colon as the prefix, e.g., draggable:start
|
||||
// don't prefix for widgets that aren't DOM-based
|
||||
widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
|
||||
}, proxiedPrototype, {
|
||||
constructor: constructor,
|
||||
namespace: namespace,
|
||||
widgetName: name,
|
||||
widgetFullName: fullName
|
||||
});
|
||||
|
||||
// If this widget is being redefined then we need to find all widgets that
|
||||
// are inheriting from it and redefine all of them so that they inherit from
|
||||
// the new version of this widget. We're essentially trying to replace one
|
||||
// level in the prototype chain.
|
||||
if ( existingConstructor ) {
|
||||
$.each( existingConstructor._childConstructors, function( i, child ) {
|
||||
var childPrototype = child.prototype;
|
||||
|
||||
// redefine the child widget using the same prototype that was
|
||||
// originally used, but inherit from the new version of the base
|
||||
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
|
||||
});
|
||||
// remove the list of existing child constructors from the old constructor
|
||||
// so the old child constructors can be garbage collected
|
||||
delete existingConstructor._childConstructors;
|
||||
} else {
|
||||
base._childConstructors.push( constructor );
|
||||
}
|
||||
|
||||
$.widget.bridge( name, constructor );
|
||||
|
||||
return constructor;
|
||||
};
|
||||
|
||||
$.widget.extend = function( target ) {
|
||||
var input = widget_slice.call( arguments, 1 ),
|
||||
inputIndex = 0,
|
||||
inputLength = input.length,
|
||||
key,
|
||||
value;
|
||||
for ( ; inputIndex < inputLength; inputIndex++ ) {
|
||||
for ( key in input[ inputIndex ] ) {
|
||||
value = input[ inputIndex ][ key ];
|
||||
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
|
||||
// Clone objects
|
||||
if ( $.isPlainObject( value ) ) {
|
||||
target[ key ] = $.isPlainObject( target[ key ] ) ?
|
||||
$.widget.extend( {}, target[ key ], value ) :
|
||||
// Don't extend strings, arrays, etc. with objects
|
||||
$.widget.extend( {}, value );
|
||||
// Copy everything else by reference
|
||||
} else {
|
||||
target[ key ] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
$.widget.bridge = function( name, object ) {
|
||||
var fullName = object.prototype.widgetFullName || name;
|
||||
$.fn[ name ] = function( options ) {
|
||||
var isMethodCall = typeof options === "string",
|
||||
args = widget_slice.call( arguments, 1 ),
|
||||
returnValue = this;
|
||||
|
||||
if ( isMethodCall ) {
|
||||
this.each(function() {
|
||||
var methodValue,
|
||||
instance = $.data( this, fullName );
|
||||
if ( options === "instance" ) {
|
||||
returnValue = instance;
|
||||
return false;
|
||||
}
|
||||
if ( !instance ) {
|
||||
return $.error( "cannot call methods on " + name + " prior to initialization; " +
|
||||
"attempted to call method '" + options + "'" );
|
||||
}
|
||||
if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
|
||||
return $.error( "no such method '" + options + "' for " + name + " widget instance" );
|
||||
}
|
||||
methodValue = instance[ options ].apply( instance, args );
|
||||
if ( methodValue !== instance && methodValue !== undefined ) {
|
||||
returnValue = methodValue && methodValue.jquery ?
|
||||
returnValue.pushStack( methodValue.get() ) :
|
||||
methodValue;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
// Allow multiple hashes to be passed on init
|
||||
if ( args.length ) {
|
||||
options = $.widget.extend.apply( null, [ options ].concat(args) );
|
||||
}
|
||||
|
||||
this.each(function() {
|
||||
var instance = $.data( this, fullName );
|
||||
if ( instance ) {
|
||||
instance.option( options || {} );
|
||||
if ( instance._init ) {
|
||||
instance._init();
|
||||
}
|
||||
} else {
|
||||
$.data( this, fullName, new object( options, this ) );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
};
|
||||
};
|
||||
|
||||
$.Widget = function( /* options, element */ ) {};
|
||||
$.Widget._childConstructors = [];
|
||||
|
||||
$.Widget.prototype = {
|
||||
widgetName: "widget",
|
||||
widgetEventPrefix: "",
|
||||
defaultElement: "<div>",
|
||||
options: {
|
||||
disabled: false,
|
||||
|
||||
// callbacks
|
||||
create: null
|
||||
},
|
||||
_createWidget: function( options, element ) {
|
||||
element = $( element || this.defaultElement || this )[ 0 ];
|
||||
this.element = $( element );
|
||||
this.uuid = widget_uuid++;
|
||||
this.eventNamespace = "." + this.widgetName + this.uuid;
|
||||
|
||||
this.bindings = $();
|
||||
this.hoverable = $();
|
||||
this.focusable = $();
|
||||
|
||||
if ( element !== this ) {
|
||||
$.data( element, this.widgetFullName, this );
|
||||
this._on( true, this.element, {
|
||||
remove: function( event ) {
|
||||
if ( event.target === element ) {
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.document = $( element.style ?
|
||||
// element within the document
|
||||
element.ownerDocument :
|
||||
// element is window or document
|
||||
element.document || element );
|
||||
this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
|
||||
}
|
||||
|
||||
this.options = $.widget.extend( {},
|
||||
this.options,
|
||||
this._getCreateOptions(),
|
||||
options );
|
||||
|
||||
this._create();
|
||||
this._trigger( "create", null, this._getCreateEventData() );
|
||||
this._init();
|
||||
},
|
||||
_getCreateOptions: $.noop,
|
||||
_getCreateEventData: $.noop,
|
||||
_create: $.noop,
|
||||
_init: $.noop,
|
||||
|
||||
destroy: function() {
|
||||
this._destroy();
|
||||
// we can probably remove the unbind calls in 2.0
|
||||
// all event bindings should go through this._on()
|
||||
this.element
|
||||
.unbind( this.eventNamespace )
|
||||
.removeData( this.widgetFullName )
|
||||
// support: jquery <1.6.3
|
||||
// http://bugs.jquery.com/ticket/9413
|
||||
.removeData( $.camelCase( this.widgetFullName ) );
|
||||
this.widget()
|
||||
.unbind( this.eventNamespace )
|
||||
.removeAttr( "aria-disabled" )
|
||||
.removeClass(
|
||||
this.widgetFullName + "-disabled " +
|
||||
"ui-state-disabled" );
|
||||
|
||||
// clean up events and states
|
||||
this.bindings.unbind( this.eventNamespace );
|
||||
this.hoverable.removeClass( "ui-state-hover" );
|
||||
this.focusable.removeClass( "ui-state-focus" );
|
||||
},
|
||||
_destroy: $.noop,
|
||||
|
||||
widget: function() {
|
||||
return this.element;
|
||||
},
|
||||
|
||||
option: function( key, value ) {
|
||||
var options = key,
|
||||
parts,
|
||||
curOption,
|
||||
i;
|
||||
|
||||
if ( arguments.length === 0 ) {
|
||||
// don't return a reference to the internal hash
|
||||
return $.widget.extend( {}, this.options );
|
||||
}
|
||||
|
||||
if ( typeof key === "string" ) {
|
||||
// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
|
||||
options = {};
|
||||
parts = key.split( "." );
|
||||
key = parts.shift();
|
||||
if ( parts.length ) {
|
||||
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
|
||||
for ( i = 0; i < parts.length - 1; i++ ) {
|
||||
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
|
||||
curOption = curOption[ parts[ i ] ];
|
||||
}
|
||||
key = parts.pop();
|
||||
if ( arguments.length === 1 ) {
|
||||
return curOption[ key ] === undefined ? null : curOption[ key ];
|
||||
}
|
||||
curOption[ key ] = value;
|
||||
} else {
|
||||
if ( arguments.length === 1 ) {
|
||||
return this.options[ key ] === undefined ? null : this.options[ key ];
|
||||
}
|
||||
options[ key ] = value;
|
||||
}
|
||||
}
|
||||
|
||||
this._setOptions( options );
|
||||
|
||||
return this;
|
||||
},
|
||||
_setOptions: function( options ) {
|
||||
var key;
|
||||
|
||||
for ( key in options ) {
|
||||
this._setOption( key, options[ key ] );
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
_setOption: function( key, value ) {
|
||||
this.options[ key ] = value;
|
||||
|
||||
if ( key === "disabled" ) {
|
||||
this.widget()
|
||||
.toggleClass( this.widgetFullName + "-disabled", !!value );
|
||||
|
||||
// If the widget is becoming disabled, then nothing is interactive
|
||||
if ( value ) {
|
||||
this.hoverable.removeClass( "ui-state-hover" );
|
||||
this.focusable.removeClass( "ui-state-focus" );
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
return this._setOptions({ disabled: false });
|
||||
},
|
||||
disable: function() {
|
||||
return this._setOptions({ disabled: true });
|
||||
},
|
||||
|
||||
_on: function( suppressDisabledCheck, element, handlers ) {
|
||||
var delegateElement,
|
||||
instance = this;
|
||||
|
||||
// no suppressDisabledCheck flag, shuffle arguments
|
||||
if ( typeof suppressDisabledCheck !== "boolean" ) {
|
||||
handlers = element;
|
||||
element = suppressDisabledCheck;
|
||||
suppressDisabledCheck = false;
|
||||
}
|
||||
|
||||
// no element argument, shuffle and use this.element
|
||||
if ( !handlers ) {
|
||||
handlers = element;
|
||||
element = this.element;
|
||||
delegateElement = this.widget();
|
||||
} else {
|
||||
element = delegateElement = $( element );
|
||||
this.bindings = this.bindings.add( element );
|
||||
}
|
||||
|
||||
$.each( handlers, function( event, handler ) {
|
||||
function handlerProxy() {
|
||||
// allow widgets to customize the disabled handling
|
||||
// - disabled as an array instead of boolean
|
||||
// - disabled class as method for disabling individual parts
|
||||
if ( !suppressDisabledCheck &&
|
||||
( instance.options.disabled === true ||
|
||||
$( this ).hasClass( "ui-state-disabled" ) ) ) {
|
||||
return;
|
||||
}
|
||||
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
||||
.apply( instance, arguments );
|
||||
}
|
||||
|
||||
// copy the guid so direct unbinding works
|
||||
if ( typeof handler !== "string" ) {
|
||||
handlerProxy.guid = handler.guid =
|
||||
handler.guid || handlerProxy.guid || $.guid++;
|
||||
}
|
||||
|
||||
var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
|
||||
eventName = match[1] + instance.eventNamespace,
|
||||
selector = match[2];
|
||||
if ( selector ) {
|
||||
delegateElement.delegate( selector, eventName, handlerProxy );
|
||||
} else {
|
||||
element.bind( eventName, handlerProxy );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_off: function( element, eventName ) {
|
||||
eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
|
||||
this.eventNamespace;
|
||||
element.unbind( eventName ).undelegate( eventName );
|
||||
|
||||
// Clear the stack to avoid memory leaks (#10056)
|
||||
this.bindings = $( this.bindings.not( element ).get() );
|
||||
this.focusable = $( this.focusable.not( element ).get() );
|
||||
this.hoverable = $( this.hoverable.not( element ).get() );
|
||||
},
|
||||
|
||||
_delay: function( handler, delay ) {
|
||||
function handlerProxy() {
|
||||
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
||||
.apply( instance, arguments );
|
||||
}
|
||||
var instance = this;
|
||||
return setTimeout( handlerProxy, delay || 0 );
|
||||
},
|
||||
|
||||
_hoverable: function( element ) {
|
||||
this.hoverable = this.hoverable.add( element );
|
||||
this._on( element, {
|
||||
mouseenter: function( event ) {
|
||||
$( event.currentTarget ).addClass( "ui-state-hover" );
|
||||
},
|
||||
mouseleave: function( event ) {
|
||||
$( event.currentTarget ).removeClass( "ui-state-hover" );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_focusable: function( element ) {
|
||||
this.focusable = this.focusable.add( element );
|
||||
this._on( element, {
|
||||
focusin: function( event ) {
|
||||
$( event.currentTarget ).addClass( "ui-state-focus" );
|
||||
},
|
||||
focusout: function( event ) {
|
||||
$( event.currentTarget ).removeClass( "ui-state-focus" );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_trigger: function( type, event, data ) {
|
||||
var prop, orig,
|
||||
callback = this.options[ type ];
|
||||
|
||||
data = data || {};
|
||||
event = $.Event( event );
|
||||
event.type = ( type === this.widgetEventPrefix ?
|
||||
type :
|
||||
this.widgetEventPrefix + type ).toLowerCase();
|
||||
// the original event may come from any element
|
||||
// so we need to reset the target on the new event
|
||||
event.target = this.element[ 0 ];
|
||||
|
||||
// copy original event properties over to the new event
|
||||
orig = event.originalEvent;
|
||||
if ( orig ) {
|
||||
for ( prop in orig ) {
|
||||
if ( !( prop in event ) ) {
|
||||
event[ prop ] = orig[ prop ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.element.trigger( event, data );
|
||||
return !( $.isFunction( callback ) &&
|
||||
callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
|
||||
event.isDefaultPrevented() );
|
||||
}
|
||||
};
|
||||
|
||||
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
|
||||
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
|
||||
if ( typeof options === "string" ) {
|
||||
options = { effect: options };
|
||||
}
|
||||
var hasOptions,
|
||||
effectName = !options ?
|
||||
method :
|
||||
options === true || typeof options === "number" ?
|
||||
defaultEffect :
|
||||
options.effect || defaultEffect;
|
||||
options = options || {};
|
||||
if ( typeof options === "number" ) {
|
||||
options = { duration: options };
|
||||
}
|
||||
hasOptions = !$.isEmptyObject( options );
|
||||
options.complete = callback;
|
||||
if ( options.delay ) {
|
||||
element.delay( options.delay );
|
||||
}
|
||||
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
|
||||
element[ method ]( options );
|
||||
} else if ( effectName !== method && element[ effectName ] ) {
|
||||
element[ effectName ]( options.duration, options.easing, callback );
|
||||
} else {
|
||||
element.queue(function( next ) {
|
||||
$( this )[ method ]();
|
||||
if ( callback ) {
|
||||
callback.call( element[ 0 ] );
|
||||
}
|
||||
next();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var widget = $.widget;
|
||||
|
||||
|
||||
|
||||
}));
|
||||
@@ -14,6 +14,15 @@ License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
%>
|
||||
<% language_tabs = current_page.data.language_tabs || [] %>
|
||||
<% page_content = yield %>
|
||||
<%
|
||||
if current_page.data.includes
|
||||
current_page.data.includes.each do |include|
|
||||
page_content += partial("includes/#{include}")
|
||||
end
|
||||
end
|
||||
%>
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -41,7 +50,7 @@ under the License.
|
||||
<%= image_tag('navbar.png') %>
|
||||
</span>
|
||||
</a>
|
||||
<div class="tocify-wrapper">
|
||||
<div class="toc-wrapper">
|
||||
<%= image_tag "logo.png", class: 'logo' %>
|
||||
<% if language_tabs.any? %>
|
||||
<div class="lang-selector">
|
||||
@@ -60,7 +69,21 @@ under the License.
|
||||
</div>
|
||||
<ul class="search-results"></ul>
|
||||
<% end %>
|
||||
<div id="toc">
|
||||
<div id="toc" class="toc-list-h1">
|
||||
<% toc_data(page_content).each do |h1| %>
|
||||
<li>
|
||||
<a href="#<%= h1[:id] %>" class="toc-h1 toc-link" data-title="<%= h1[:content] %>"><%= h1[:content] %></a>
|
||||
<% if h1[:children].length > 0 %>
|
||||
<ul class="toc-list-h2">
|
||||
<% h1[:children].each do |h2| %>
|
||||
<li>
|
||||
<a href="#<%= h2[:id] %>" class="toc-h2 toc-link" data-title="<%= h1[:content] %>"><%= h2[:content] %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if current_page.data.toc_footers %>
|
||||
<ul class="toc-footer">
|
||||
@@ -73,10 +96,7 @@ under the License.
|
||||
<div class="page-wrapper">
|
||||
<div class="dark-box"></div>
|
||||
<div class="content">
|
||||
<%= yield %>
|
||||
<% current_page.data.includes && current_page.data.includes.each do |include| %>
|
||||
<%= partial "includes/#{include}" %>
|
||||
<% end %>
|
||||
<%= page_content %>
|
||||
</div>
|
||||
<div class="dark-box">
|
||||
<% if language_tabs.any? %>
|
||||
|
||||
@@ -55,7 +55,7 @@ html, body {
|
||||
$nav-subitem-bg;
|
||||
}
|
||||
|
||||
.tocify-wrapper {
|
||||
.toc-wrapper {
|
||||
transition: left 0.3s ease-in-out;
|
||||
|
||||
overflow-y: auto;
|
||||
@@ -146,14 +146,6 @@ html, body {
|
||||
}
|
||||
|
||||
|
||||
.tocify-item>a, .toc-footer li {
|
||||
padding: 0 $nav-padding 0 $nav-padding;
|
||||
display: block;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
// The Table of Contents is composed of multiple nested
|
||||
// unordered lists. These styles remove the default
|
||||
// styling of an unordered list because it is ugly.
|
||||
@@ -164,30 +156,17 @@ html, body {
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
li {
|
||||
color: $nav-text;
|
||||
transition-property: background;
|
||||
transition-timing-function: linear;
|
||||
transition-duration: 230ms;
|
||||
}
|
||||
|
||||
// This is the currently selected ToC entry
|
||||
.tocify-focus {
|
||||
.toc-link.active {
|
||||
box-shadow: 0px 1px 0px $nav-active-shadow;
|
||||
background-color: $nav-active-bg;
|
||||
color: $nav-active-text;
|
||||
}
|
||||
|
||||
// Subheaders are the submenus that slide open
|
||||
// in the table of contents.
|
||||
.tocify-subheader {
|
||||
display: none; // tocify will override this when needed
|
||||
.toc-list-h2 {
|
||||
display: none;
|
||||
background-color: $nav-subitem-bg;
|
||||
font-weight: 500;
|
||||
.tocify-item>a {
|
||||
padding-left: $nav-padding + $nav-indent;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
// for embossed look:
|
||||
@include embossed-bg;
|
||||
@@ -196,6 +175,11 @@ html, body {
|
||||
}
|
||||
}
|
||||
|
||||
.toc-h2 {
|
||||
padding-left: $nav-padding + $nav-indent;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.toc-footer {
|
||||
padding: 1em 0;
|
||||
margin-top: 1em;
|
||||
@@ -216,7 +200,19 @@ html, body {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toc-link, .toc-footer li {
|
||||
padding: 0 $nav-padding 0 $nav-padding;
|
||||
display: block;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
transition-property: background;
|
||||
transition-timing-function: linear;
|
||||
transition-duration: 130ms;
|
||||
}
|
||||
|
||||
// button to show navigation on mobile devices
|
||||
@@ -571,7 +567,7 @@ html, body {
|
||||
// There are also a couple styles disperesed
|
||||
|
||||
@media (max-width: $tablet-width) {
|
||||
.tocify-wrapper {
|
||||
.toc-wrapper {
|
||||
left: -$nav-width;
|
||||
|
||||
&.open {
|
||||
@@ -587,7 +583,7 @@ html, body {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tocify-wrapper .tocify-item > a {
|
||||
.toc-link {
|
||||
padding-top: 0.3em;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
@@ -602,7 +598,7 @@ html, body {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.tocify-wrapper .lang-selector {
|
||||
.toc-wrapper .lang-selector {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user