diff --git a/static/js/app/appv2.js b/static/js/app/appv2.js new file mode 100644 index 0000000..ff99bc6 --- /dev/null +++ b/static/js/app/appv2.js @@ -0,0 +1,139 @@ +// Generated by CoffeeScript 1.4.0 +(function() { + + this.DssApplication = (function(Backbone, Marionette) { + var App, sidebarView; + App = new Marionette.Application(); + App.vent.on("routing:started", function() { + var enablePushState, pushState; + console.log("App(vent): routing:started"); + enablePushState = true; + pushState = !!(enablePushState && window.history && window.history.pushState); + Backbone.history.start({ + pushState: pushState, + hashChange: true + }); + return true; + }); + App.addRegions({ + headerRegion: "#header", + fullContentRegion: "#full-content", + contentRegion: { + selector: "#content" + }, + footerRegion: "#footer", + sidebarRegion: "#sidebar" + }); + App.addInitializer(function() { + console.log("App: routing starting"); + App.Router = new DssRouter(); + return App.vent.trigger("routing:started"); + }); + App.addInitializer(function() { + $(document).on("click", "a[href]:not([data-bypass])", function(evt) { + var href, root; + href = { + prop: $(this).prop("href"), + attr: $(this).attr("href") + }; + root = location.protocol + "//" + location.host + (App.root || '/'); + if (href.prop.slice(0, root.length) === root) { + evt.preventDefault(); + App.Router.navigate(href.attr, true); + return true; + } + }); + return true; + }); + App.addInitializer(function() { + this.listenTo(vent, "app:login", function() { + console.log("App(vent): app:login"); + utils.modal("/dlg/LoginView"); + return true; + }); + this.listenTo(vent, "app:donate", function() { + console.log("App: donate"); + utils.modal("/dlg/Donate"); + return true; + }); + this.listenTo(vent, "mix:favourite", function(model) { + console.log("App(vent): mix:favourite"); + model.save('favourited', !model.get('favourited'), { + patch: true + }); + return true; + }); + this.listenTo(vent, "mix:like", function(model, id, success, favourite) { + console.log("App(vent): mix:like"); + model.save('liked', !model.get('liked'), { + patch: true + }); + return true; + }); + this.listenTo(vent, "mix:delete", function(model) { + console.log("App(vent): mix:like"); + return utils.messageBox("/dlg/DeleteMixConfirm", { + yes: function() { + console.log("Controller: mixDeleteYES!!"); + mix.destroy(); + return Backbone.history.navigate("/", { + trigger: true + }); + }, + no: function() { + return console.log("Controller: mixDeleteNO!!"); + } + }); + }); + this.listenTo(vent, "user:follow", function(model) { + var target, user, + _this = this; + console.log("App(vent): user:follow"); + user = new UserItem({ + id: com.podnoms.settings.currentUser + }); + target = com.podnoms.settings.urlRoot + "user/" + model.get("id") + "/"; + user.fetch({ + success: function() { + var f, newFollowers; + if (!model.get("is_following")) { + newFollowers = user.get("following").concat([target]); + user.save({ + "following": newFollowers, + "is_following": true, + patch: true + }); + model.set("is_following", true); + } else { + f = user.get("following"); + f.splice(f.indexOf(target), 1); + user.save({ + "following": f, + "is_following": false, + patch: true + }); + model.set("is_following", false); + } + } + }); + return true; + }); + return this.listenTo(vent, "mix:share", function(mode, model) { + console.log("App(vent): mix:share (" + mode + ")"); + if (mode === "facebook") { + social.sharePageToFacebook(model); + } else if (mode === "twitter") { + social.sharePageToTwitter(model); + } else if (mode === "embed") { + social.generateEmbedCode(model); + } + return true; + }); + }); + App.headerRegion.show(new HeaderView()); + sidebarView = new SidebarView(); + App.sidebarRegion.show(sidebarView); + return App; + })(Backbone, Marionette); + +}).call(this); diff --git a/static/js/lib/ace/ace/ace.auto-container.js b/static/js/lib/ace/ace/ace.auto-container.js new file mode 100644 index 0000000..4a2fa5b --- /dev/null +++ b/static/js/lib/ace/ace/ace.auto-container.js @@ -0,0 +1,17 @@ +/** + Auto Container Adds .container when window size is above 1140px. + In Bootstrap you should stick with fixed width breakpoints. + You can use this feature to enable fixed container only when window size is above 1140px +*/ +ace.auto_container = function($) { + $(window).on('resize.auto_container', function() { + var enable = ace.vars.window['width'] > 1140 ? true : false; + try { + ace.settings.main_container_fixed(enable, false, false); + } catch(e) { + if(enable) $('.main-container,.navbar-container').addClass('container'); + else $('.main-container,.navbar-container').removeClass('container'); + $(document).trigger('settings.ace', ['main_container_fixed' , enable]); + } + }).triggerHandler('resize.auto_container'); +} \ No newline at end of file diff --git a/static/js/lib/ace/ace/ace.auto-padding.js b/static/js/lib/ace/ace/ace.auto-padding.js new file mode 100644 index 0000000..6b013a9 --- /dev/null +++ b/static/js/lib/ace/ace/ace.auto-padding.js @@ -0,0 +1,80 @@ +/** + Auto content padding on fixed navbar & breadcrumbs. + Navbar's content and height is often predictable and when navbar is fixed we can add appropriate padding to content area using CSS. + + But when navbar is fixed and its content size and height is not predictable we may need to add the necessary padding to content area dynamically using Javascript. + + It's not often needed and you can have good results using CSS3 media queries to add necessary paddings based on window size. +*/ +ace.auto_padding = function($) { + var navbar = $('.navbar').eq(0); + var navbar_container = $('.navbar-container').eq(0); + + var sidebar = $('.sidebar').eq(0); + + var main_container = $('.main-container').get(0); + + var breadcrumbs = $('.breadcrumbs').eq(0); + var page_content = $('.page-content').get(0); + + var default_padding = 8 + + if(navbar.length > 0) { + $(window).on('resize.padding', function() { + if( navbar.css('position') == 'fixed' ) { + var padding1 = !ace.vars['nav_collapse'] ? navbar.outerHeight() : navbar_container.outerHeight(); + padding1 = parseInt(padding1); + main_container.style.paddingTop = padding1 + 'px'; + + if(ace.vars['non_auto_fixed'] && sidebar.length > 0) { + if(sidebar.css('position') == 'fixed') { + sidebar.get(0).style.top = padding1 + 'px'; + } + else sidebar.get(0).style.top = ''; + } + + if( breadcrumbs.length > 0 ) { + if(breadcrumbs.css('position') == 'fixed') { + var padding2 = default_padding + breadcrumbs.outerHeight() + parseInt(breadcrumbs.css('margin-top')); + padding2 = parseInt(padding2); + page_content.style['paddingTop'] = padding2 + 'px'; + + if(ace.vars['non_auto_fixed']) breadcrumbs.get(0).style.top = padding1 + 'px'; + } else { + page_content.style.paddingTop = ''; + if(ace.vars['non_auto_fixed']) breadcrumbs.get(0).style.top = ''; + } + } + } + else { + main_container.style.paddingTop = ''; + page_content.style.paddingTop = ''; + + if(ace.vars['non_auto_fixed']) { + if(sidebar.length > 0) { + sidebar.get(0).style.top = ''; + } + if(breadcrumbs.length > 0) { + breadcrumbs.get(0).style.top = ''; + } + } + } + }).triggerHandler('resize.padding'); + + $(document).on('settings.ace', function(ev, event_name, event_val) { + if(event_name == 'navbar_fixed' || event_name == 'breadcrumbs_fixed') { + if(ace.vars['webkit']) { + //force new 'css position' values to kick in + navbar.get(0).offsetHeight; + if(breadcrumbs.length > 0) breadcrumbs.get(0).offsetHeight; + } + $(window).triggerHandler('resize.padding'); + } + }); + + /**$('#skin-colorpicker').on('change', function() { + $(window).triggerHandler('resize.padding'); + });*/ + } + +} \ No newline at end of file diff --git a/static/js/lib/ace/ace/ace.autohide-sidebar.js b/static/js/lib/ace/ace/ace.autohide-sidebar.js new file mode 100644 index 0000000..e47fd35 --- /dev/null +++ b/static/js/lib/ace/ace/ace.autohide-sidebar.js @@ -0,0 +1,19 @@ +/** + Autohide mobile view menu. Automatically hide the sidebar in mobile view (default style) when clicked/tapped outside of it. +*/ +ace.auto_hide_sidebar = function($) { + $(document).on(ace.click_event+'.ace.hide', function(e) { + var toggler = $('#menu-toggler'); + if( toggler.length == 0 || toggler[0].scrollHeight == 0 || !toggler.hasClass('display') ) return; + //toggle button is not visible, so we are not in mobile view, or the sidebar is not displayed, so return + + var sidebar = $('#sidebar'); + if( $.contains(sidebar[0], e.target) ) { + e.stopPropagation(); + return; + } + + sidebar.removeClass('display'); + toggler.removeClass('display'); + }) +} \ No newline at end of file diff --git a/static/js/lib/ace/ace/ace.js b/static/js/lib/ace/ace/ace.js new file mode 100644 index 0000000..df40bf2 --- /dev/null +++ b/static/js/lib/ace/ace/ace.js @@ -0,0 +1,301 @@ +/** + Required. Ace's Basic File to Initiliaze Different Parts & Some Variables. +*/ +if( !('ace' in window) ) window['ace'] = {} +if( !('helper' in window['ace']) ) window['ace'].helper = {} +if( !('vars' in window['ace']) ) { + window['ace'].vars = { + 'icon' : ' ace-icon ', + '.icon' : '.ace-icon' + } +} +ace.vars['touch'] = 'ontouchstart' in document.documentElement; + + +jQuery(function($) { + //sometimes we try to use 'tap' event instead of 'click' if jquery mobile plugin is available + ace.click_event = ace.vars['touch'] && $.fn.tap ? 'tap' : 'click'; + + //sometimes the only good way to work around browser's pecularities is to detect them using user-agents + //though it's not accurate + var agent = navigator.userAgent + ace.vars['webkit'] = !!agent.match(/AppleWebKit/i) + ace.vars['safari'] = !!agent.match(/Safari/i) && !agent.match(/Chrome/i); + ace.vars['android'] = ace.vars['safari'] && !!agent.match(/Android/i) + ace.vars['ios_safari'] = !!agent.match(/OS ([4-8])(_\d)+ like Mac OS X/i) && !agent.match(/CriOS/i) + + ace.vars['non_auto_fixed'] = ace.vars['android'] || ace.vars['ios_safari']; + // for android and ios we don't use "top:auto" when breadcrumbs is fixed + if(ace.vars['non_auto_fixed']) { + $('body').addClass('mob-safari'); + } + + ace.vars['transition'] = 'transition' in document.body.style || 'WebkitTransition' in document.body.style || 'MozTransition' in document.body.style || 'OTransition' in document.body.style + + ///////////////////////////// + + //a list of available functions with their arguments + // >>> null means enable + // >>> false means disable + // >>> array means function arguments + var available_functions = { + 'general_vars' : null,//general_vars should come first + + 'handle_side_menu' : null, + 'add_touch_drag' : null, + + 'sidebar_scrollable' : [ + //true, //enable only if sidebar is fixed , for 2nd approach only + true //scroll to selected item? (one time only on page load) + ,true //true = include shortcut buttons in the scrollbars + ,false || ace.vars['safari'] || ace.vars['ios_safari'] //true = include toggle button in the scrollbars + ,200 //> 0 means smooth_scroll, time in ms, used in first approach only, better to be almost the same amount as submenu transition time + ,false//true && ace.vars['touch'] //used in first approach only, true means the scrollbars should be outside of the sidebar + ], + + 'sidebar_hoverable' : null,//automatically move up a submenu, if some part of it goes out of window + + 'general_things' : null, + + 'widget_boxes' : null, + 'widget_reload_handler' : null, + + 'settings_box' : null,//settings box + 'settings_rtl' : null, + 'settings_skin' : null, + + 'enable_searchbox_autocomplete' : null, + + 'auto_hide_sidebar' : null,//disable? + 'auto_padding' : null,//disable + 'auto_container' : null//disable + }; + + //enable these functions with related params + for(var func_name in available_functions) { + if(!(func_name in ace)) continue; + + var args = available_functions[func_name]; + if(args === false) continue;//don't run this function + + else if(args == null) args = [jQuery]; + else if(args instanceof String) args = [jQuery, args]; + else if(args instanceof Array) args.unshift(jQuery);//prepend jQuery + + ace[func_name].apply(null, args); + } + +}) + + + +ace.general_vars = function($) { + var minimized_menu_class = 'menu-min'; + var responsive_min_class = 'responsive-min'; + var horizontal_menu_class = 'h-sidebar'; + + var sidebar = $('#sidebar').eq(0); + //differnet mobile menu styles + ace.vars['mobile_style'] = 1;//default responsive mode with toggle button inside navbar + if(sidebar.hasClass('responsive') && !$('#menu-toggler').hasClass('navbar-toggle')) ace.vars['mobile_style'] = 2;//toggle button behind sidebar + else if(sidebar.hasClass(responsive_min_class)) ace.vars['mobile_style'] = 3;//minimized menu + else if(sidebar.hasClass('navbar-collapse')) ace.vars['mobile_style'] = 4;//collapsible (bootstrap style) + + //update some basic variables + $(window).on('resize.ace.vars' , function(){ + ace.vars['window'] = {width: parseInt($(this).width()), height: parseInt($(this).height())} + ace.vars['mobile_view'] = ace.vars['mobile_style'] < 4 && ace.helper.mobile_view(); + ace.vars['collapsible'] = !ace.vars['mobile_view'] && ace.helper.collapsible(); + ace.vars['nav_collapse'] = (ace.vars['collapsible'] || ace.vars['mobile_view']) && $('#navbar').hasClass('navbar-collapse'); + + var sidebar = $(document.getElementById('sidebar')); + ace.vars['minimized'] = + (!ace.vars['collapsible'] && sidebar.hasClass(minimized_menu_class)) + || + (ace.vars['mobile_style'] == 3 && ace.vars['mobile_view'] && sidebar.hasClass(responsive_min_class)) + + ace.vars['horizontal'] = !(ace.vars['mobile_view'] || ace.vars['collapsible']) && sidebar.hasClass(horizontal_menu_class) + }).triggerHandler('resize.ace.vars'); +} + +// +ace.general_things = function($) { + //add scrollbars for user dropdowns + var has_scroll = !!$.fn.ace_scroll; + if(has_scroll) $('.dropdown-content').ace_scroll({reset: false, mouseWheelLock: true}) + /** + //add scrollbars to body + if(has_scroll) $('body').ace_scroll({size: ace.helper.winHeight()}) + $('body').css('position', 'static') + */ + + //reset scrolls bars on window resize + $(window).on('resize.reset_scroll', function() { + /** + //reset body scrollbars + if(has_scroll) $('body').ace_scroll('update', {size : ace.helper.winHeight()}) + */ + if(has_scroll) $('.ace-scroll').ace_scroll('reset'); + }); + $(document).on('settings.ace.reset_scroll', function(e, name) { + if(name == 'sidebar_collapsed' && has_scroll) $('.ace-scroll').ace_scroll('reset'); + }); + + + //change a dropdown to "dropup" depending on its position + $(document).on('click.dropdown.pos', '.dropdown-toggle[data-position="auto"]', function() { + var offset = $(this).offset(); + var parent = $(this.parentNode); + + if ( parseInt(offset.top + $(this).height()) + 50 + > + (ace.helper.scrollTop() + ace.helper.winHeight() - parent.find('.dropdown-menu').eq(0).height()) + ) parent.addClass('dropup'); + else parent.removeClass('dropup'); + }); + + + //prevent dropdowns from hiding when a tab is selected + $(document).on('click', '.dropdown-navbar .nav-tabs', function(e){ + e.stopPropagation(); + var $this , href + var that = e.target + if( ($this = $(e.target).closest('[data-toggle=tab]')) && $this.length > 0) { + $this.tab('show'); + e.preventDefault(); + } + }); + + //prevent dropdowns from hiding when a from is clicked + /**$(document).on('click', '.dropdown-navbar form', function(e){ + e.stopPropagation(); + });*/ + + + //disable navbar icon animation upon click + $('.ace-nav [class*="icon-animated-"]').closest('a').one('click', function(){ + var icon = $(this).find('[class*="icon-animated-"]').eq(0); + var $match = icon.attr('class').match(/icon\-animated\-([\d\w]+)/); + icon.removeClass($match[0]); + }); + + + //tooltip in sidebar items + $('.sidebar .nav-list .badge[title],.sidebar .nav-list .badge[title]').each(function() { + var tooltip_class = $(this).attr('class').match(/tooltip\-(?:\w+)/); + tooltip_class = tooltip_class ? tooltip_class[0] : 'tooltip-error'; + $(this).tooltip({ + 'placement': function (context, source) { + var offset = $(source).offset(); + + if( parseInt(offset.left) < parseInt(document.body.scrollWidth / 2) ) return 'right'; + return 'left'; + }, + container: 'body', + template: '
' + }); + }); + + //or something like this if items are dynamically inserted + /**$('.sidebar').tooltip({ + 'placement': function (context, source) { + var offset = $(source).offset(); + + if( parseInt(offset.left) < parseInt(document.body.scrollWidth / 2) ) return 'right'; + return 'left'; + }, + selector: '.nav-list .badge[title],.nav-list .label[title]', + container: 'body', + template: '
' + });*/ + + + + + //the scroll to top button + var scroll_btn = $('.btn-scroll-up'); + if(scroll_btn.length > 0) { + var is_visible = false; + $(window).on('scroll.scroll_btn', function() { + if(ace.helper.scrollTop() > parseInt(ace.helper.winHeight() / 4)) { + if(!is_visible) { + scroll_btn.addClass('display'); + is_visible = true; + } + } else { + if(is_visible) { + scroll_btn.removeClass('display'); + is_visible = false; + } + } + }).triggerHandler('scroll.scroll_btn'); + + scroll_btn.on(ace.click_event, function(){ + var duration = Math.min(500, Math.max(100, parseInt(ace.helper.scrollTop() / 3))); + $('html,body').animate({scrollTop: 0}, duration); + return false; + }); + } + + + //chrome and webkit have a problem here when resizing from 460px to more + //we should force them redraw the navbar! + if( ace.vars['webkit'] ) { + var ace_nav = $('.ace-nav').get(0); + if( ace_nav ) $(window).on('resize.webkit' , function(){ + ace.helper.redraw(ace_nav); + }); + } + +} + + + + +//some functions +ace.helper.collapsible = function() { + var toggle + return (document.querySelector('#sidebar.navbar-collapse') != null) + && ((toggle = document.querySelector('.navbar-toggle[data-target*=".sidebar"]')) != null) + && toggle.scrollHeight > 0 + //sidebar is collapsible and collapse button is visible? +} +ace.helper.mobile_view = function() { + var toggle + return ((toggle = document.getElementById('menu-toggler')) != null && toggle.scrollHeight > 0) +} + +ace.helper.redraw = function(elem) { + var saved_val = elem.style['display']; + elem.style.display = 'none'; + elem.offsetHeight; + elem.style.display = saved_val; +} + +ace.helper.scrollTop = function() { + return document.scrollTop || document.documentElement.scrollTop || document.body.scrollTop + //return $(window).scrollTop(); +} +ace.helper.winHeight = function() { + return window.innerHeight || document.documentElement.clientHeight; + //return $(window).innerHeight(); +} +ace.helper.camelCase = function(str) { + return str.replace(/-([\da-z])/gi, function(match, chr) { + return chr ? chr.toUpperCase() : ''; + }); +} +ace.helper.removeStyle = + 'removeProperty' in document.body.style + ? + function(elem, prop) { elem.style.removeProperty(prop) } + : + function(elem, prop) { elem.style[ace.helper.camelCase(prop)] = '' } + + +ace.helper.hasClass = + 'classList' in document.documentElement + ? + function(elem, className) { return elem.classList.contains(className); } + : + function(elem, className) { return elem.className.indexOf(className) > -1; } \ No newline at end of file diff --git a/static/js/lib/ace/ace/ace.onpage-help.js b/static/js/lib/ace/ace/ace.onpage-help.js new file mode 100644 index 0000000..e4a43b4 --- /dev/null +++ b/static/js/lib/ace/ace/ace.onpage-help.js @@ -0,0 +1,592 @@ +jQuery(function($) { + var help = null; + $(window).on('hashchange.start_help', function(e) { + if(help == null && window.location.hash == '#help') { + help = new ace.Onpage_Help($) + help.init() + help.disable(); + + //add #help tag to links to enable help + $(document).on('click.start_help', '.sidebar .nav-list a', function() { + var href = $(this).attr('href'); + if( !href.match(/\#help$/) ) $(this).attr('href', href+'#help'); + }); + } + }).triggerHandler('hashchange.start_help'); + + + //some buttons inside demo pages to launch help + $(document).on(ace.click_event, '.btn-display-help', function(e) { + e.preventDefault(); + + if(help == null) { + help = new ace.Onpage_Help($) + help.init() + help.disable(); + + // + $('#ace-toggle-onpage-help').trigger('click'); + } + + var section = $(this).attr('href'); + help.show_help(section); + }); +}); + +ace.Onpage_Help = function($) { + if( !window.Node ) window.Node = { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + COMMENT_NODE: 8 + }; + + var $base = ace.vars['base'] || '../..'; + + var section_start = {}; + var section_end = {}; + var rects = {}; + + var created = false; + var active = false; + + var self = this; + var settings = {} + var ovfx = ''; + var container = null; + + var body_h, body_w; + + var captureFocus = function() { + if(!container) return; + var scroll = -1; + //like bootstrap modal + $(document) + .off('focusin.ace.help') //remove any previously attached handler + .on('focusin.ace.help', function (e) { + if (!( container[0] == e.target || $.contains(container[0], e.target) )) { + container.focus(); + } + + if(e.target == document && scroll > -1) { + //when window regains focus and container is focused, it scrolls to bottom + //so we put it back to its place + $('body,html').scrollTop(scroll); + scroll = -1; + } + }) + + $(window).on('blur.ace.help', function(){ + scroll = $(window).scrollTop(); + }); + } + var releaseFocus = function() { + $(document).off('focusin.ace.help'); + $(window).off('blur.ace.help'); + } + + this.enable = function() { + if(active) return; + + active = true; + settings['navbar'] = ace.settings.is('navbar', 'fixed') + settings['sidebar'] = ace.settings.is('sidebar', 'fixed') + settings['breadcrumbs'] = ace.settings.is('breadcrumbs', 'fixed') + + ace.settings.navbar_fixed(false , false);//disable fixed navbar, sidebar, etc + + if( !created ) { + this.init(); + created = true; + } + $('.ace-onpage-help-backdrop, .ace-onpage-help').removeClass('hidden'); + + ovfx = document.body.style.overflowX; + document.body.style.overflowX = 'hidden';//hide body:overflow-x + $('#btn-scroll-up').css('z-index', 1000000); + + $(window).triggerHandler('resize.onpage_help'); + captureFocus(); + } + + this.disable = function() { + + active = false; + $('.ace-onpage-help-backdrop, .ace-onpage-help').addClass('hidden'); + + document.body.style.overflowX = ovfx;//restore body:overflow-x + $('#btn-scroll-up').css('z-index', ''); + + //restore fixed state of navbar, sidebar, etc + if( settings['breadcrumbs'] ) { + ace.settings.breadcrumbs_fixed(true, false, false); + } + if( settings['sidebar'] ) { + ace.settings.sidebar_fixed(true, false, false); + } + if( settings['navbar'] ) { + ace.settings.navbar_fixed(true, false, false); + } + + releaseFocus(); + } + + this.is_active = function() { + return active; + } + this.show_help = function(section) { + launch_help_modal(section, true); + } + + + this.init = function() { + container = $('
').appendTo('body'); + + container + .append('
') + .append('\
\ +
\ + \ +
\ +
'); + + $(document).on('settings.ace.help', function(ev, event_name, event_val) { + if(event_name == 'main_container_fixed') { + if(event_val) container.addClass('container'); + else container.removeClass('container'); + } + }).triggerHandler('settings.ace.help', ['main_container_fixed', $('.main-container').hasClass('container')]) + + + $('#ace-toggle-onpage-help').on('click', function(e) { + if(active) { + self.disable(); + } + else { + self.enable(); + } + $(this).find('.ace-toggle-help-text').removeClass('ace-toggle-help-text'); + $(this).toggleClass('btn-grey btn-info').parent().toggleClass('active'); + e.preventDefault(); + }) + + //find all comments + var comments = $('*').contents().filter(function(){ return this.nodeType == Node.COMMENT_NODE; }) + $(comments).each(function() { + var match + if( (match = $.trim(this.data).match(/#section\s*:\s*([\w\-\.\/]+)/i)) ) { + var section_name = match[1]; + if( !(section_name in section_start) ) section_start[ section_name ] = this; + } + if( (match = $.trim(this.data).match(/\/section\s*:\s*([\w\-\.\/]+)/i)) ) { + var section_name = match[1]; + if( !(section_name in section_end) ) section_end[ section_name ] = this; + } + }) + + + //update to correct position and size + $(window).on('resize.onpage_help', function() { + if(!active) return; + body_h = document.body.scrollHeight - 2; + body_w = document.body.scrollWidth - 2; + + //we first calculate all positions + //because if we calculate one position and then change DOM, + //next position calculation will become slow on Webkit, because it tries to re-calculate things + //i.e. batch call all and save offsets and scrollWidth, etc and then use them later in highlight_section + //Firefox doesn't have such issue + for(var name in section_start) { + if(section_start.hasOwnProperty(name)) { + save_section_position(name); + } + } + for(var name in section_start) { + if(section_start.hasOwnProperty(name)) { + highlight_section(name); + } + } + + }) + + //$('.alert').on('closed.bs.alert', function() { + //$(window).triggerHandler('resize.onpage_help'); + //}); + + created = true; + } + + + function save_section_position(name) { + if( !(name in section_start) || !(name in section_end) ) return; + + var node = section_start[name]; + var start = $(node).next().eq(0); + var end = $(section_end[name]).prev().eq(0); + + var start_hidden = start.is(':hidden'); + var end_hidden = end.is(':hidden'); + if( start_hidden && end_hidden ) { + rects[name] = {is_hidden: true} + return; + } + + if(start_hidden) start = end; + else if(end_hidden) end = start; + + //get the start and end position of our rectangle to be drawn! + var off1 = start.offset(); + var off2 = end.offset(); + if( !off1 || !off2 ) { + rects[name] = {is_hidden: true} + return; + } + + + var x1, y1, x2, y2, w2, h2; + if(off1.left < off2.left) { + x1 = parseInt(off1.left); + x2 = parseInt(off2.left); + w2 = parseInt(end.outerWidth()); + } else { + x1 = parseInt(off2.left); + x2 = parseInt(off1.left); + w2 = parseInt(start.outerWidth()); + } + + if(off1.top < off2.top) { + y1 = parseInt(off1.top); + y2 = parseInt(off2.top); + h2 = parseInt(end.outerHeight()); + } else { + y1 = parseInt(off2.top); + y2 = parseInt(off1.top); + h2 = parseInt(start.outerHeight()); + } + + x1 -= 1; + y1 -= 1; + x2 += 1; + y2 += 1; + + var width = x2 + w2 - x1, height = y2 + h2 - y1; + + //if out of window rect + if(x1 + width < 2 || x1 > body_w || y1 + height < 2 || y1 > body_h ) { + rects[name] = {is_hidden: true} + return; + } + + rects[name] = { + left: x1, + top: y1, + width: width, + height: height + } + } + + function highlight_section(name) { + if( !(name in rects) || !container ) return; + + var div = container.find('.ace-onpage-help[data-section="'+name+'"]').eq(0); + if(div.length == 0) { + div = $('').appendTo(container); + div.attr('data-section', name); + + div.on(ace.click_event, function(e) { + e.preventDefault(); + launch_help_modal(name); + }); + } + + var rect = rects[name]; + if(rect.is_hidden) { + div.addClass('hidden'); + return; + } + + div.css({ + left: rect.left, + top: rect.top, + width: rect.width, + height: rect.height + }); + + + div.removeClass('hidden'); + div.removeClass('smaller smallest'); + if(rect.height < 55 || rect.width < 55) { + div.addClass('smallest'); + } + else if(rect.height < 75 || rect.width < 75) { + div.addClass('smaller'); + } + + } + + + var nav_list = []; + var nav_pos = -1; + var mbody = null, mbody_scroll = null; + + function launch_help_modal(name, save_to_list) { + name = name.replace(/^#/g, ''); + + var modal = $('#onpage-help-modal'); + if(modal.length == 0) { + modal = $('').appendTo('body'); + + mbody = modal.find('.modal-body'); + modal.css({'overflow' : 'hidden'}) + + mbody.ace_scroll({hoverReset: false, size: $(window).innerHeight() - 150, lockAnyway: true, styleClass: 'scroll-margin scroll-dark'}) + + $('#onpage-help-modal') + .on('show.bs.modal', function() { + releaseFocus(); + }) + .on('hidden.bs.modal', function() { + captureFocus(); + }); + + $(document).on('shown.ace.widget hidden.ace.widget', '.help-content .widget-box', function() { + mbody.ace_scroll('reset'); + }); + } + + + + if( !modal.hasClass('in') ) { + if(document.body.lastChild != modal.get(0)) $(document.body).append(modal);//move it to become the last element of body + modal.modal('show'); + var diff = parseInt(modal.find('.modal-dialog').css('margin-top')); + diff = diff + 110 + parseInt(diff / 2); + mbody.ace_scroll('update', { size: $(window).innerHeight() - diff }); + } + + modal.find('.modal-title').wrapInner("
') + .parent().append('').closest('.widget-header'); + + $(this).wrap(''); + $(this).closest('.widget-box').prepend(header); + }); + + content.removeClass('hidden'); + + content.find('span.thumbnail img').each(function() { + var src = $(this).attr('src'); + $(this) + .attr('src', $base+"/docs/" + src) + .one('load', function() { + mbody.ace_scroll('reset'); + }); + }); + + Rainbow.color(content.get(0), function(){ + mbody.ace_scroll('reset'); + }); + + //save history list + add_to_nav_list(name, save_to_list); + + var pos = -1; + if((pos = name.lastIndexOf('.')) > -1) { + name = name.substr(0, pos); + modal.find('button[data-goup=modal]').removeClass('disabled').attr('data-url', name); + } + else { + modal.find('button[data-goup=modal]').addClass('disabled').blur(); + } + + }) + .fail(function() { + modal.find('.modal-title').find('.fa-spin').remove().end().find('.hidden').children().unwrap(); + mbody.ace_scroll('reset'); + }); + }//launch_help_modal + + $(document).on(ace.click_event, '.help-content > .widget-box > .widget-header > .info-title', function(e) { + var widget_box = $(this).closest('.widget-box').widget_box('toggle'); + }); + $(document).on(ace.click_event, '.help-more', function(e) { + e.preventDefault(); + var href = $(this).attr('href'); + launch_help_modal(href); + }); + + + function add_to_nav_list(name, save_to_list) { + if(save_to_list !== false) { + if(nav_list.length > 0) { + nav_list = nav_list.slice(0, nav_pos + 1); + } + if(nav_list[nav_list.length - 1] != name) { + nav_list.push(name); + nav_pos = nav_list.length - 1; + } + } + + var modal = $('#onpage-help-modal'); + if(nav_pos == 0){ + modal.find('button[data-goback=modal]').addClass('disabled').blur(); + } + else { + modal.find('button[data-goback=modal]').removeClass('disabled'); + } + + if(nav_pos == nav_list.length - 1){ + modal.find('button[data-goforward=modal]').addClass('disabled').blur(); + } + else { + modal.find('button[data-goforward=modal]').removeClass('disabled'); + } + } + + $(document).on(ace.click_event, 'button[data-goforward=modal]', function() { + if(nav_pos < nav_list.length - 1) { + nav_pos++; + launch_help_modal(nav_list[nav_pos], false); + } + }); + $(document).on(ace.click_event, 'button[data-goback=modal]', function() { + if(nav_pos > 0) { + nav_pos--; + launch_help_modal(nav_list[nav_pos], false); + } + }); + $(document).on(ace.click_event, 'button[data-goup=modal]', function() { + var $this = $(this), url; + if( $this.hasClass('disabled') || !(url = $this.attr('data-url')) ) return; + + launch_help_modal(url , true) + }); + + + $(document).on(ace.click_event, '.open-file[data-open-file]', function() { + $('#onpage-help-modal').find('.modal-title').wrapInner("