Add basic support for rendering dynamic content on pages.
Change-Id: If3ba4f71771a01043ec6d544e3b4a9222ba35daf
This commit is contained in:
@@ -167,10 +167,12 @@ $(document).ready(function() {
|
||||
// highlight Design tab
|
||||
if ($("body").hasClass("design")) {
|
||||
$("#header li.design a").addClass("selected");
|
||||
$("#sticky-header").addClass("design");
|
||||
|
||||
// highlight Develop tab
|
||||
} else if ($("body").hasClass("develop") || $("body").hasClass("google")) {
|
||||
$("#header li.develop a").addClass("selected");
|
||||
$("#sticky-header").addClass("develop");
|
||||
// In Develop docs, also highlight appropriate sub-tab
|
||||
var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
|
||||
if (rootDir == "training") {
|
||||
@@ -195,8 +197,26 @@ $(document).ready(function() {
|
||||
// highlight Distribute tab
|
||||
} else if ($("body").hasClass("distribute")) {
|
||||
$("#header li.distribute a").addClass("selected");
|
||||
}
|
||||
$("#sticky-header").addClass("distribute");
|
||||
|
||||
var baseFrag = pagePathOriginal.indexOf('/', 1) + 1;
|
||||
var secondFrag = pagePathOriginal.substring(baseFrag, pagePathOriginal.indexOf('/', baseFrag));
|
||||
if (secondFrag == "users") {
|
||||
$("#nav-x li.users a").addClass("selected");
|
||||
} else if (secondFrag == "engage") {
|
||||
$("#nav-x li.engage a").addClass("selected");
|
||||
} else if (secondFrag == "monetize") {
|
||||
$("#nav-x li.monetize a").addClass("selected");
|
||||
} else if (secondFrag == "tools") {
|
||||
$("#nav-x li.disttools a").addClass("selected");
|
||||
} else if (secondFrag == "stories") {
|
||||
$("#nav-x li.stories a").addClass("selected");
|
||||
} else if (secondFrag == "essentials") {
|
||||
$("#nav-x li.essentials a").addClass("selected");
|
||||
} else if (secondFrag == "googleplay") {
|
||||
$("#nav-x li.googleplay a").addClass("selected");
|
||||
}
|
||||
}
|
||||
// set global variable so we can highlight the sidenav a bit later (such as for google reference)
|
||||
// and highlight the sidenav
|
||||
mPagePath = pagePath;
|
||||
@@ -906,6 +926,86 @@ function writeCookie(cookie, val, section, expiration) {
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Displays sticky nav bar on pages when dac header scrolls out of view
|
||||
*/
|
||||
|
||||
(function() {
|
||||
$(document).ready(function() {
|
||||
|
||||
// Sticky nav position
|
||||
var stickyTop = $('#header-wrapper').outerHeight();
|
||||
var sticky = false;
|
||||
var hiding = false;
|
||||
var $stickyEl = $('#sticky-header');
|
||||
var $menuEl = $('.menu-container');
|
||||
//var scrollThrottle = -1;
|
||||
var lastScroll = 0;
|
||||
var autoScrolling = false;
|
||||
|
||||
$(window).scroll(function() {
|
||||
var top = $(window).scrollTop();
|
||||
|
||||
if (sticky && top < stickyTop) {
|
||||
sticky = false;
|
||||
hiding = true;
|
||||
$stickyEl.css({'opacity': 0});
|
||||
setTimeout(function() {
|
||||
$menuEl.removeClass('sticky-menu');
|
||||
$stickyEl.hide();
|
||||
hiding = false;
|
||||
}, 250);
|
||||
} else if (!sticky && top >= stickyTop) {
|
||||
sticky = true;
|
||||
$stickyEl.show();
|
||||
$menuEl.addClass('sticky-menu');
|
||||
|
||||
setTimeout(function() {
|
||||
$stickyEl.css({'opacity': 1});
|
||||
}, 10);
|
||||
|
||||
// If its a jump then make sure to modify the scroll because of the
|
||||
// sticky nav
|
||||
if (!autoScrolling && Math.abs(top - lastScroll > 100)) {
|
||||
autoScrolling = true;
|
||||
$('body,html').animate({scrollTop:(top = top - 60)}, '250', 'swing', function() { autoScrolling = false; });
|
||||
}
|
||||
} else if (hiding && top < 15) {
|
||||
$menuEl.removeClass('sticky-menu');
|
||||
$stickyEl.hide();
|
||||
hiding = false;
|
||||
}
|
||||
|
||||
lastScroll = top;
|
||||
});
|
||||
|
||||
// Stack hover states
|
||||
$('.section-card-menu').each(function(index, el) {
|
||||
var height = $(el).height();
|
||||
$(el).css({height:height+'px', position:'relative'});
|
||||
var $cardInfo = $(el).find('.card-info');
|
||||
|
||||
$cardInfo.css({position: 'absolute', bottom:'0px', left:'0px', right:'0px', overflow:'visible'});
|
||||
});
|
||||
|
||||
// Auto scroll anchors and account for sticky nav
|
||||
$('a[href^=#]').click(function(e){
|
||||
e.preventDefault();
|
||||
var tmp = $.attr(this, 'href').substr(1);
|
||||
var el = document.getElementById(tmp) ||
|
||||
((tmp = document.getElementsByName(tmp)).length ?
|
||||
tmp[0] : null);
|
||||
|
||||
if (el) {
|
||||
var top = $(el).offset().top - 60;
|
||||
autoScrolling = true;
|
||||
$('body,html').animate({scrollTop:top}, '500', 'swing', function() { autoScrolling = false; });
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
@@ -1724,6 +1824,7 @@ function search_changed(e, kd, toroot)
|
||||
$('.suggest-card').hide();
|
||||
if ($("#searchResults").is(":hidden") && (search.value != "")) {
|
||||
// if results aren't showing (and text not empty), return true to allow search to execute
|
||||
$('body,html').animate({scrollTop:0}, '500', 'swing', function() { autoScrolling = false; });
|
||||
return true;
|
||||
} else {
|
||||
// otherwise, results are already showing, so allow ajax to auto refresh the results
|
||||
@@ -3233,3 +3334,603 @@ function showSamples() {
|
||||
$("#samples").append($ul);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ########################################################## */
|
||||
/* ################### RESOURCE CARDS ##################### */
|
||||
/* ########################################################## */
|
||||
|
||||
/** Handle resource queries, collections, and grids (sections). Requires
|
||||
jd_tag_helpers.js and the *_unified_data.js to be loaded. */
|
||||
|
||||
(function() {
|
||||
// Prevent the same resource from being loaded more than once per page.
|
||||
var addedPageResources = {};
|
||||
|
||||
$(document).ready(function() {
|
||||
$('.resource-widget').each(function() {
|
||||
initResourceWidget(this);
|
||||
});
|
||||
|
||||
// Might remove this, but adds ellipsis to card descriptions rather
|
||||
// than just cutting them off, not sure if it performs well
|
||||
$('.card-info .text').ellipsis();
|
||||
});
|
||||
|
||||
/*
|
||||
Three types of resource layouts:
|
||||
Flow - Uses a fixed row-height flow using float left style.
|
||||
Carousel - Single card slideshow all same dimension absoute.
|
||||
Stack - Uses fixed columns and flexible element height.
|
||||
*/
|
||||
function initResourceWidget(widget) {
|
||||
var $widget = $(widget);
|
||||
var isFlow = $widget.hasClass('resource-flow-layout'),
|
||||
isCarousel = $widget.hasClass('resource-carousel-layout'),
|
||||
isStack = $widget.hasClass('resource-stack-layout');
|
||||
|
||||
// find size of widget by pulling out its class name
|
||||
var sizeCols = 1;
|
||||
var m = $widget.get(0).className.match(/\bcol-(\d+)\b/);
|
||||
if (m) {
|
||||
sizeCols = parseInt(m[1], 10);
|
||||
}
|
||||
|
||||
var opts = {
|
||||
cardSizes: ($widget.data('cardsizes') || '').split(','),
|
||||
maxResults: parseInt($widget.data('maxresults') || '100', 10),
|
||||
itemsPerPage: $widget.data('itemsperpage'),
|
||||
sortOrder: $widget.data('sortorder'),
|
||||
query: $widget.data('query'),
|
||||
section: $widget.data('section'),
|
||||
sizeCols: sizeCols
|
||||
};
|
||||
|
||||
// run the search for the set of resources to show
|
||||
|
||||
var resources = buildResourceList(opts);
|
||||
|
||||
if (isFlow) {
|
||||
drawResourcesFlowWidget($widget, opts, resources);
|
||||
} else if (isCarousel) {
|
||||
drawResourcesCarouselWidget($widget, opts, resources);
|
||||
} else if (isStack) {
|
||||
var sections = buildSectionList(opts);
|
||||
opts['numStacks'] = $widget.data('numstacks');
|
||||
drawResourcesStackWidget($widget, opts, resources, sections);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initializes a Resource Carousel Widget */
|
||||
function drawResourcesCarouselWidget($widget, opts, resources) {
|
||||
$widget.empty();
|
||||
|
||||
$widget.addClass('resource-card slideshow-container')
|
||||
.append($('<a>').addClass('slideshow-prev').text('Prev'))
|
||||
.append($('<a>').addClass('slideshow-next').text('Next'));
|
||||
|
||||
var css = { 'width': $widget.width() + 'px',
|
||||
'height': $widget.height() + 'px' };
|
||||
|
||||
var $ul = $('<ul>');
|
||||
|
||||
for (var i = 0; i < resources.length; ++i) {
|
||||
//keep url clean for matching and offline mode handling
|
||||
var urlPrefix = resources[i].url.indexOf("//") > -1 ? "" : toRoot;
|
||||
var $card = $('<a>')
|
||||
.attr('href', urlPrefix + resources[i].url)
|
||||
.decorateResourceCard(resources[i]);
|
||||
|
||||
$('<li>').css(css)
|
||||
.append($card)
|
||||
.appendTo($ul);
|
||||
}
|
||||
|
||||
$('<div>').addClass('frame')
|
||||
.append($ul)
|
||||
.appendTo($widget);
|
||||
|
||||
$widget.dacSlideshow({
|
||||
auto: true,
|
||||
btnPrev: '.slideshow-prev',
|
||||
btnNext: '.slideshow-next'
|
||||
});
|
||||
};
|
||||
|
||||
/* Initializes a Resource Card Stack Widget (column-based layout) */
|
||||
function drawResourcesStackWidget($widget, opts, resources, sections) {
|
||||
// Don't empty widget, grab all items inside since they will be the first
|
||||
// items stacked, followed by the resource query
|
||||
|
||||
var cards = $widget.find('.resource-card').detach().toArray();
|
||||
var numStacks = opts.numStacks || 1;
|
||||
var $stacks = [];
|
||||
var urlString;
|
||||
|
||||
for (var i = 0; i < numStacks; ++i) {
|
||||
$stacks[i] = $('<div>').addClass('resource-card-stack')
|
||||
.appendTo($widget);
|
||||
}
|
||||
|
||||
var sectionResources = [];
|
||||
|
||||
// Extract any subsections that are actually resource cards
|
||||
for (var i = 0; i < sections.length; ++i) {
|
||||
if (!sections[i].sections || !sections[i].sections.length) {
|
||||
//keep url clean for matching and offline mode handling
|
||||
urlPrefix = sections[i].url.indexOf("//") > -1 ? "" : toRoot;
|
||||
// Render it as a resource card
|
||||
|
||||
sectionResources.push(
|
||||
$('<a>')
|
||||
.addClass('resource-card section-card')
|
||||
.attr('href', urlPrefix + sections[i].resource.url)
|
||||
.decorateResourceCard(sections[i].resource)[0]
|
||||
);
|
||||
|
||||
} else {
|
||||
cards.push(
|
||||
$('<div>')
|
||||
.addClass('resource-card section-card-menu')
|
||||
.decorateResourceSection(sections[i])[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cards = cards.concat(sectionResources);
|
||||
|
||||
for (var i = 0; i < resources.length; ++i) {
|
||||
//keep url clean for matching and offline mode handling
|
||||
urlPrefix = resources[i].url.indexOf("//") > -1 ? "" : toRoot;
|
||||
var $card = $('<a>')
|
||||
.addClass('resource-card related-card')
|
||||
.attr('href', urlPrefix + resources[i].url)
|
||||
.decorateResourceCard(resources[i]);
|
||||
|
||||
cards.push($card[0]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < cards.length; ++i) {
|
||||
// Find the stack with the shortest height, but give preference to
|
||||
// left to right order.
|
||||
var minHeight = $stacks[0].height();
|
||||
var minIndex = 0;
|
||||
|
||||
for (var j = 1; j < numStacks; ++j) {
|
||||
var height = $stacks[j].height();
|
||||
if (height < minHeight - 45) {
|
||||
minHeight = height;
|
||||
minIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
$stacks[minIndex].append($(cards[i]));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Initializes a flow widget, see distribute.scss for generating accompanying css */
|
||||
function drawResourcesFlowWidget($widget, opts, resources) {
|
||||
$widget.empty();
|
||||
var cardSizes = opts.cardSizes || ['6x6'];
|
||||
var i = 0, j = 0;
|
||||
|
||||
while (i < resources.length) {
|
||||
var cardSize = cardSizes[j++ % cardSizes.length];
|
||||
cardSize = cardSize.replace(/^\s+|\s+$/,'');
|
||||
|
||||
// A stack has a third dimension which is the number of stacked items
|
||||
var isStack = cardSize.match(/(\d+)x(\d+)x(\d+)/);
|
||||
var stackCount = 0;
|
||||
var $stackDiv = null;
|
||||
|
||||
if (isStack) {
|
||||
// Create a stack container which should have the dimensions defined
|
||||
// by the product of the items inside.
|
||||
$stackDiv = $('<div>').addClass('resource-card-stack resource-card-' + isStack[1]
|
||||
+ 'x' + isStack[2] * isStack[3]) .appendTo($widget);
|
||||
}
|
||||
|
||||
// Build each stack item or just a single item
|
||||
do {
|
||||
var resource = resources[i];
|
||||
//keep url clean for matching and offline mode handling
|
||||
urlPrefix = resource.url.indexOf("//") > -1 ? "" : toRoot;
|
||||
var $card = $('<a>')
|
||||
.addClass('resource-card resource-card-' + cardSize + ' resource-card-' + resource.type)
|
||||
.attr('href', urlPrefix + resource.url);
|
||||
|
||||
if (isStack) {
|
||||
$card.addClass('resource-card-' + isStack[1] + 'x' + isStack[2]);
|
||||
if (++stackCount == parseInt(isStack[3])) {
|
||||
$card.addClass('resource-card-row-stack-last');
|
||||
stackCount = 0;
|
||||
}
|
||||
} else {
|
||||
stackCount = 0;
|
||||
}
|
||||
|
||||
$card.decorateResourceCard(resource)
|
||||
.appendTo($stackDiv || $widget);
|
||||
|
||||
} while (++i < resources.length && stackCount > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a site map of resources using a section as a root. */
|
||||
function buildSectionList(opts) {
|
||||
if (opts.section && SECTION_BY_ID[opts.section]) {
|
||||
return SECTION_BY_ID[opts.section].sections || [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function buildResourceList(opts) {
|
||||
var maxResults = opts.maxResults || 100;
|
||||
|
||||
var query = opts.query || '';
|
||||
var expressions = parseResourceQuery(query);
|
||||
var addedResourceIndices = {};
|
||||
var results = [];
|
||||
|
||||
for (var i = 0; i < expressions.length; i++) {
|
||||
var clauses = expressions[i];
|
||||
|
||||
// build initial set of resources from first clause
|
||||
var firstClause = clauses[0];
|
||||
var resources = [];
|
||||
switch (firstClause.attr) {
|
||||
case 'type':
|
||||
resources = ALL_RESOURCES_BY_TYPE[firstClause.value];
|
||||
break;
|
||||
case 'lang':
|
||||
resources = ALL_RESOURCES_BY_LANG[firstClause.value];
|
||||
break;
|
||||
case 'tag':
|
||||
resources = ALL_RESOURCES_BY_TAG[firstClause.value];
|
||||
break;
|
||||
case 'collection':
|
||||
var urls = RESOURCE_COLLECTIONS[firstClause.value].resources || [];
|
||||
resources = urls.map(function(url){ return ALL_RESOURCES_BY_URL[url]; });
|
||||
break;
|
||||
case 'section':
|
||||
var urls = SITE_MAP[firstClause.value].sections || [];
|
||||
resources = urls.map(function(url){ return ALL_RESOURCES_BY_URL[url]; });
|
||||
break;
|
||||
}
|
||||
//console.log(firstClause.attr + ':' + firstClause.value);
|
||||
resources = resources || [];
|
||||
|
||||
// use additional clauses to filter corpus
|
||||
if (clauses.length > 1) {
|
||||
var otherClauses = clauses.slice(1);
|
||||
resources = resources.filter(getResourceMatchesClausesFilter(otherClauses));
|
||||
}
|
||||
|
||||
// filter out resources already added
|
||||
if (i > 1) {
|
||||
resources = resources.filter(getResourceNotAlreadyAddedFilter(addedResourceIndices));
|
||||
}
|
||||
|
||||
// add to list of already added indices
|
||||
for (var j = 0; j < resources.length; j++) {
|
||||
console.log(resources[j].title);
|
||||
addedResourceIndices[resources[j].index] = 1;
|
||||
}
|
||||
|
||||
// concat to final results list
|
||||
results = results.concat(resources);
|
||||
}
|
||||
|
||||
if (opts.sortOrder && results.length) {
|
||||
var attr = opts.sortOrder;
|
||||
|
||||
if (opts.sortOrder == 'random') {
|
||||
var i = results.length, j, temp;
|
||||
while (--i) {
|
||||
j = Math.floor(Math.random() * (i + 1));
|
||||
temp = results[i];
|
||||
results[i] = results[j];
|
||||
results[j] = temp;
|
||||
}
|
||||
} else {
|
||||
var desc = attr.charAt(0) == '-';
|
||||
if (desc) {
|
||||
attr = attr.substring(1);
|
||||
}
|
||||
results = results.sort(function(x,y) {
|
||||
return (desc ? -1 : 1) * (parseInt(x[attr], 10) - parseInt(y[attr], 10));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
results = results.filter(getResourceNotAlreadyAddedFilter(addedPageResources));
|
||||
results = results.slice(0, maxResults);
|
||||
|
||||
for (var j = 0; j < results.length; ++j) {
|
||||
addedPageResources[results[j].index] = 1;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
function getResourceNotAlreadyAddedFilter(addedResourceIndices) {
|
||||
return function(resource) {
|
||||
return !addedResourceIndices[resource.index];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function getResourceMatchesClausesFilter(clauses) {
|
||||
return function(resource) {
|
||||
return doesResourceMatchClauses(resource, clauses);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function doesResourceMatchClauses(resource, clauses) {
|
||||
for (var i = 0; i < clauses.length; i++) {
|
||||
var map;
|
||||
switch (clauses[i].attr) {
|
||||
case 'type':
|
||||
map = IS_RESOURCE_OF_TYPE[clauses[i].value];
|
||||
break;
|
||||
case 'lang':
|
||||
map = IS_RESOURCE_IN_LANG[clauses[i].value];
|
||||
break;
|
||||
case 'tag':
|
||||
map = IS_RESOURCE_TAGGED[clauses[i].value];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!map || (!!clauses[i].negative ? map[resource.index] : !map[resource.index])) {
|
||||
return clauses[i].negative;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function parseResourceQuery(query) {
|
||||
// Parse query into array of expressions (expression e.g. 'tag:foo + type:video')
|
||||
var expressions = [];
|
||||
var expressionStrs = query.split(',') || [];
|
||||
for (var i = 0; i < expressionStrs.length; i++) {
|
||||
var expr = expressionStrs[i] || '';
|
||||
|
||||
// Break expression into clauses (clause e.g. 'tag:foo')
|
||||
var clauses = [];
|
||||
var clauseStrs = expr.split(/(?=[\+\-])/);
|
||||
for (var j = 0; j < clauseStrs.length; j++) {
|
||||
var clauseStr = clauseStrs[j] || '';
|
||||
|
||||
// Get attribute and value from clause (e.g. attribute='tag', value='foo')
|
||||
var parts = clauseStr.split(':');
|
||||
var clause = {};
|
||||
|
||||
clause.attr = parts[0].replace(/^\s+|\s+$/g,'');
|
||||
if (clause.attr) {
|
||||
if (clause.attr.charAt(0) == '+') {
|
||||
clause.attr = clause.attr.substring(1);
|
||||
} else if (clause.attr.charAt(0) == '-') {
|
||||
clause.negative = true;
|
||||
clause.attr = clause.attr.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (parts.length > 1) {
|
||||
clause.value = parts[1].replace(/^\s+|\s+$/g,'');
|
||||
}
|
||||
|
||||
clauses.push(clause);
|
||||
}
|
||||
|
||||
if (!clauses.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
expressions.push(clauses);
|
||||
}
|
||||
|
||||
return expressions;
|
||||
}
|
||||
})();
|
||||
|
||||
(function($) {
|
||||
/* Simple jquery function to create dom for a standard resource card */
|
||||
$.fn.decorateResourceCard = function(resource) {
|
||||
var section = resource.group || resource.type;
|
||||
var imgUrl;
|
||||
if (resource.image) {
|
||||
//keep url clean for matching and offline mode handling
|
||||
var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot;
|
||||
imgUrl = urlPrefix + resource.image;
|
||||
}
|
||||
|
||||
$('<div>')
|
||||
.addClass('card-bg')
|
||||
.css('background-image', 'url(' + (imgUrl || toRoot + 'assets/images/resource-card-default-android.jpg') + ')')
|
||||
.appendTo(this);
|
||||
|
||||
$('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : ''))
|
||||
.append($('<div>').addClass('section').text(section))
|
||||
.append($('<div>').addClass('title').html(resource.title))
|
||||
.append($('<div>').addClass('description')
|
||||
.append($('<div>').addClass('text').html(resource.summary))
|
||||
.append($('<div>').addClass('util')
|
||||
.append($('<div>').addClass('g-plusone')
|
||||
.attr('data-size', 'small')
|
||||
.attr('data-align', 'right')
|
||||
.attr('data-href', resource.url))))
|
||||
.appendTo(this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/* Simple jquery function to create dom for a resource section card (menu) */
|
||||
$.fn.decorateResourceSection = function(section) {
|
||||
var resource = section.resource;
|
||||
//keep url clean for matching and offline mode handling
|
||||
var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot;
|
||||
var $base = $('<a>')
|
||||
.addClass('card-bg')
|
||||
.attr('href', resource.url)
|
||||
.append($('<div>').addClass('card-section-icon')
|
||||
.append($('<div>').addClass('icon'))
|
||||
.append($('<div>').addClass('section').html(resource.title)))
|
||||
.appendTo(this);
|
||||
|
||||
var $cardInfo = $('<div>').addClass('card-info').appendTo(this);
|
||||
|
||||
if (section.sections && section.sections.length) {
|
||||
// Recurse the section sub-tree to find a resource image.
|
||||
var stack = [section];
|
||||
|
||||
while (stack.length) {
|
||||
if (stack[0].resource.image) {
|
||||
$base.css('background-image', 'url(' + urlPrefix + stack[0].resource.image + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
if (stack[0].sections) {
|
||||
stack = stack.concat(stack[0].sections);
|
||||
}
|
||||
|
||||
stack.shift();
|
||||
}
|
||||
|
||||
var $ul = $('<ul>')
|
||||
.appendTo($cardInfo);
|
||||
|
||||
var max = section.sections.length > 3 ? 3 : section.sections.length;
|
||||
|
||||
for (var i = 0; i < max; ++i) {
|
||||
|
||||
var subResource = section.sections[i];
|
||||
$('<li>')
|
||||
.append($('<a>').attr('href', subResource.url)
|
||||
.append($('<div>').addClass('title').html(subResource.title))
|
||||
.append($('<div>').addClass('description')
|
||||
.append($('<div>').addClass('text').html(subResource.summary))
|
||||
.append($('<div>').addClass('util')
|
||||
.append($('<div>').addClass('g-plusone')
|
||||
.attr('data-size', 'small')
|
||||
.attr('data-align', 'right')
|
||||
.attr('data-href', resource.url)))))
|
||||
.appendTo($ul);
|
||||
}
|
||||
|
||||
// Add a more row
|
||||
if (max < section.sections.length) {
|
||||
$('<li>')
|
||||
.append($('<a>').attr('href', resource.url)
|
||||
.append($('<div>')
|
||||
.addClass('title')
|
||||
.text('More')))
|
||||
.appendTo($ul);
|
||||
}
|
||||
} else {
|
||||
// No sub-resources, just render description?
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
|
||||
(function($) {
|
||||
$.fn.ellipsis = function(options) {
|
||||
|
||||
// default option
|
||||
var defaults = {
|
||||
'row' : 1, // show rows
|
||||
'onlyFullWords': true, // set to true to avoid cutting the text in the middle of a word
|
||||
'char' : '...', // ellipsis
|
||||
'callback': function() {},
|
||||
'position': 'tail' // middle, tail
|
||||
};
|
||||
|
||||
options = $.extend(defaults, options);
|
||||
|
||||
this.each(function() {
|
||||
// get element text
|
||||
var $this = $(this);
|
||||
|
||||
var targetHeight = $this.height();
|
||||
$this.css({'height': 'auto'});
|
||||
var text = $this.text();
|
||||
var origText = text;
|
||||
var origLength = origText.length;
|
||||
var origHeight = $this.height();
|
||||
|
||||
if (origHeight <= targetHeight) {
|
||||
$this.text(text);
|
||||
options.callback.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
var start = 1, length = 0;
|
||||
var end = text.length;
|
||||
|
||||
if(options.position === 'tail') {
|
||||
while (start < end) { // Binary search for max length
|
||||
length = Math.ceil((start + end) / 2);
|
||||
|
||||
$this.text(text.slice(0, length) + options['char']);
|
||||
|
||||
if ($this.height() <= targetHeight) {
|
||||
start = length;
|
||||
} else {
|
||||
end = length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
text = text.slice(0, start);
|
||||
|
||||
if (options.onlyFullWords) {
|
||||
// remove fragment of the last word together with possible soft-hyphen chars
|
||||
text = text.replace(/[\u00AD\w\uac00-\ud7af]+$/, '');
|
||||
}
|
||||
text += options['char'];
|
||||
|
||||
}else if(options.position === 'middle') {
|
||||
|
||||
var sliceLength = 0;
|
||||
while (start < end) { // Binary search for max length
|
||||
length = Math.ceil((start + end) / 2);
|
||||
sliceLength = Math.max(origLength - length, 0);
|
||||
|
||||
$this.text(
|
||||
origText.slice(0, Math.floor((origLength - sliceLength) / 2)) +
|
||||
options['char'] +
|
||||
origText.slice(Math.floor((origLength + sliceLength) / 2), origLength)
|
||||
);
|
||||
|
||||
if ($this.height() <= targetHeight) {
|
||||
start = length;
|
||||
} else {
|
||||
end = length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
sliceLength = Math.max(origLength - start, 0);
|
||||
var head = origText.slice(0, Math.floor((origLength - sliceLength) / 2));
|
||||
var tail = origText.slice(Math.floor((origLength + sliceLength) / 2), origLength);
|
||||
|
||||
if (options.onlyFullWords) {
|
||||
// remove fragment of the last or first word together with possible soft-hyphen characters
|
||||
head = head.replace(/[\u00AD\w\uac00-\ud7af]+$/, '');
|
||||
}
|
||||
|
||||
text = head + options['char'] + tail;
|
||||
}
|
||||
|
||||
$this.text(text);
|
||||
options.callback.call(this);
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
}) (jQuery);
|
Reference in New Issue
Block a user