jQuery(function($) {
var winURL = (window.URL || window.webkitURL);
var objectURLs = {};
var saved_results = {};
var currentLessVars = {};
var less_parser = new(less.Parser)({});
$.ajax({url: "../assets/css/less/ace-features.less"}).done(function(less_file_data) {
var sections = []
var regex = /\/\/~([\w\- \&]+)/gi;
var matches;
while ((matches = regex.exec(less_file_data)) !== null)
{
sections.push({'title' : matches[1] , 'index': matches.index})
}
sections.push({'title' : 'EOF' , 'index': less_file_data.length})
var depend_on = {}
var depend_off = {}
$(sections).each(function(i, info) {
if(info.title == 'EOF') return;
var next_info = sections[i + 1];
var sub = less_file_data.substring(info.index + info.title.length + 4 , next_info.index - 1);
sub = $.trim(sub);
if(sub.length == 0) return;
var vars = [];
var regex = /@([\w\-]+)\:\s+([\w\d\'\"\@\-]+);(?:\/\/(.*))?/gi;
var matches;
while ((matches = regex.exec(sub)) !== null) {
vars.push({'name': matches[1], 'value': matches[2], 'description': matches[3]})
}
var section_name = info.title.toLowerCase().replace(/\W/g, '');
$('
').appendTo('#page-content');
var group = $('').appendTo('#page-content');
$(vars).each(function(i, lessvar) {
//lessvar.name
//lessvar.value
//lessvar.description
var description = lessvar.description || '';
if(description == '!ignore') return;
var label = $('').appendTo(group);
label.wrap('');
if(lessvar.value.match(/true|false/i)) {
var check = $('').prependTo(label);
check.attr({'id' : 'id-'+lessvar.name , 'data-varname' : lessvar.name})
check.get(0).checked = lessvar.value == 'true';
if(lessvar.value == 'true') label.parent().addClass('active');
}
else {
var opts = description.match(/\{(?:[^\}]+)\}/);
if(opts) {
description = description.replace(/\{(?:[^\}]+)\}/ , '');
try {
var select = $(' ').appendTo(label);
select.attr({'id' : 'id-'+lessvar.name , 'data-varname' : lessvar.name})
opts = JSON.parse(opts[0]);
for(var o in opts) if(opts.hasOwnProperty(o)) {
var opt = $('').appendTo(select);
opt.attr('value', o).text(opts[o]);
}
select.val(lessvar.value);
}
catch(e) {}
}
else {
var input = $(' ').appendTo(label);
input.attr({'id' : 'id-'+lessvar.name , 'data-varname' : lessvar.name, value: lessvar.value})
}
}
var match
if(description.length > 0 && (match = description.match(/\+@enable\-([\w\-]+)/))) {
var depends = match[1];
//check if a variable (feature) depends on another one
//we should automatically enable that if so
if(!(lessvar.name in depend_on)) depend_on[lessvar.name] = []
depend_on[lessvar.name].push('enable-'+depends);//enable "'enable-'+depends" when lessvar.name is enabled
if(!('enable-'+depends in depend_off)) depend_off['enable-'+depends] = []
depend_off['enable-'+depends].push(lessvar.name);//disable "lessvar.name" when "'enable-'+depends" is disabled
//for example auto-disable switch elements when checkboxes are disabled/unselected
//or auto-enable checkboxes when switch elements are enabled/selected
description = description.replace(match[0], '');
}
label.append(description);
});
});
$(document).on('click', 'input[type=checkbox][name=less-var]', function(e){
$(this).closest('.list-group-item').toggleClass('active');
var varname = $(this).data('varname');
if(this.checked && varname in depend_on) {
//we need another part to be enabled as well
enable_depends(depend_on[varname]);
}
else if(!this.checked && varname in depend_off) {
//we need to disable dependent parts as well
//but we should do it recursively as `depend_off[varname]` is an array
disable_depends(depend_off[varname]);
}
});
$(document).on('click', 'input[type=checkbox].section', function(){
var name = this.name;
var checked = this.checked;
$('input[type=checkbox][name=less-var][data-section="'+name+'"]').each(function() {
this.checked = checked;
if(checked) $(this).closest('.list-group-item').addClass('active');
else $(this).closest('.list-group-item').removeClass('active');
});
});
//for example when we disable "checkboxes" , "switch elements" are disabled automatically
//and switch styles 4,5,6,7 are also dependent on "switch elements" so they get disabled as well
function disable_depends(depend_offs) {
$(depend_offs).each(function(i, varname) {
$('#id-'+varname).get(0).checked = false;
$('#id-'+varname).closest('.list-group-item').removeClass('active');
if(varname in depend_off) {
//if it contains another list of dependents
disable_depends(depend_off[varname]);
}
});
}
function enable_depends(depend_ons) {
$(depend_ons).each(function(i, varname) {
$('#id-'+varname).get(0).checked = true;
$('#id-'+varname).closest('.list-group-item').addClass('active');
if(varname in depend_on) {
//if it contains another list of dependents
enable_depends(depend_on[varname]);
}
});
}
});
function showModal() {
$('#btn-build-css').button('reset').removeClass('disabled');
$('#btn-launch-modal').removeClass('hide');
$('#modal-save-dialog').modal('show');
}
function renderLess(options) {
var updateVars = options.less_vars;
releaseUrlObjects(options.name);
function showResult() {
if(options.download === true) {
$('#btn-save-css').get(0).click();
return;
}
else if(typeof options.callback === 'function' && objectURLs[options.name] != null) {
options.callback.call(null);
return;
}
}
setTimeout(function() {
less_parser.parse(options.less_input, process_output, {modifyVars: updateVars});
} , 100);
function process_output (e, tree) {
if(e) {
console.log(e);
return;
}
var css_output = tree.toCSS({});
////////
var is_responsive = true;
if(updateVars['enable-no-responsive'] === 'true') {
try {
css_output = remove_media_queries(css_output, grid_break == 991 ? 900 : 700);
is_responsive = false;
//keep `min-width` media queries which are >= 900px
} catch(e){}
}
////////
$('#save-buttons .output-size').remove();
saveObjectUrl(options.name, css_output);
if(options.ie_fix !== true) {
showResult();
return;
}
$('#modal-ie-alert').addClass('hide');
//Here we try to count the output CSS's selector count for IE's limitations
//I'm not familiar with inner workings of LESS parser
//so to get a tree of the output CSS, let's parse it again!
//It may not be the correct approach though!
breakCSS(less_parser, css_output, function(css_part2){
if(typeof css_part2 == 'string' && css_part2.length > 10) {
$('#id-selector-limit').hide()//.html('Maximum CSS selectors allowed: 4096, Current CSS selectors: ' + num + '');
$('.ie-alert-min').text('');
$('#modal-ie-alert').removeClass('hide');
saveObjectUrl(options.name+'-part2', css_part2);
}
showResult();
});
}
}
function updateGridVars(updateVars) {
//grid breakpoint
var grid_break = parseInt($('select[name=less-var][data-varname="enable-mobile-width"]').val()) || 991;
updateVars['grid-float-breakpoint'] = (grid_break + 1)+'px';
updateVars['grid-float-breakpoint-max'] = (grid_break)+'px';
//gutter width
updateVars['grid-gutter-width'] = (parseInt($('select[name=less-var][data-varname="enable-gutter-width"]').val()) || 24)+'px';
}
////
$('#btn-build-css').on('click', function() {
$('#btn-build-css').button('loading').text('Please wait...').addClass('disabled');
$('a[id*="btn-save-"]').parent().addClass('hide disabled').find('.filesize').remove();
$('a[data-id*="btn-save-"]').parent().addClass('hide disabled').find('.filesize').remove();
var updateVars = {}
$('input[type=checkbox][name=less-var]').each(function() {
var varname = $(this).attr('data-varname');
updateVars[varname] = this.checked ? 'true' : 'false';
});
if(updateVars['enable-checkbox-asp'] === 'true') {
updateVars['lbl_selector'] = '~ .lbl';//asp.net friendly selector
}
//selected skin
var skin_less = '';
var skin = $('select[name=less-var][data-varname="enable-selected-skin"]').val();
updateVars['selected-skin-1'] = '~"skins/empty.less"';
if(skin == 'skin-3') {
//skin-3 requires no-skin as well
updateVars['selected-skin-1'] = '~"skins/no-skin.less"';
}
else {
updateVars['selected-skin-2'] = '~"skins/'+skin+'.less"';
}
updateGridVars(updateVars);
currentLessVars = updateVars;
var ace_less =
'@selected-skin-1: "skins/empty.less";\
@selected-skin-2: "skins/no-skin.less";\
@import "../assets/css/less/ace.less";';
//compile Main file
renderLess({less_input: ace_less, name: 'ace', less_vars: updateVars, ie_fix: true, callback: function() {
var gridVars = {};
updateGridVars(gridVars);
//compile Bootstrap
renderLess({less_input: ' @import "../assets/css/less/bootstrap/bootstrap.less"; ', name: 'bootstrap', less_vars: gridVars, callback: function() {
if(updateVars['enable-skin-file'] === 'true') {
renderLess({less_input: ' @import "../assets/css/less/skins/skins.less"; ', name: 'ace-skins', less_vars: updateVars, callback: function() {
if(updateVars['enable-rtl-file'] === 'true') {
renderRTL({less_input: ' @import "../assets/css/less/ace-rtl.less"; ', name: 'ace-rtl', less_vars: updateVars}, function() {
showModal()
})
}//compile RTL file
else {
showModal()
}
}})
}//compile skin file
else {
if(updateVars['enable-rtl-file'] === 'true') {
renderRTL({less_input: ' @import "../assets/css/less/ace-rtl.less"; ', name: 'ace-rtl', less_vars: updateVars}, function() {
showModal()
})
}//compile RTL file
else {
showModal()
}
}
}})
}})//renderLess
})
function renderRTL(options, callback) {
renderLess({less_input: ' @import "../assets/css/less/ace-rtl.less"; ', name: 'ace-rtl', less_vars: options.less_vars, callback: function() {
var content = saved_results['bootstrap'] || '';
content += saved_results['ace'] || '';
if(currentLessVars['enable-skin-file'] === 'true')
content += saved_results['ace-skins'] || '';
var rtl_output = makeRTL(content);
var grid_break = parseInt($('select[name=less-var][data-varname="enable-mobile-width"]').val()) || 991;
if(currentLessVars['enable-no-responsive'] === 'true') rtl_output = remove_media_queries(rtl_output, grid_break == 991 ? 900 : 700);//keep `min-width` media queries which are >= 900px
rtl_output = saved_results['ace-rtl'] = rtl_output + "\n" + saved_results['ace-rtl'];
saveObjectUrl('ace-rtl', rtl_output);
callback.call(null);
}//function
})//renderLess
}//renderRTL
$(window).on('unload' , function() {
releaseUrlObjects();
saved_result = {}
});
function saveObjectUrl(name, css_output) {
releaseUrlObjects(name);
objectURLs[name] = css_output.length == 0 ? 'javascript:void(0)' : winURL.createObjectURL(new Blob([css_output], {type : 'text/css'}))
saved_results[name] = css_output;
$('#btn-save-'+name).parent().removeClass('disabled hide')
$('#btn-save-'+name)
.attr({'download' : name+'.css'})
.find('.filesize').remove().end()
.append(' ('+readableSize(css_output.length)+')')
.get(0).href = objectURLs[name];
releaseUrlObjects(name+'.min');
var minimized = new CleanCSS().minify(css_output);
objectURLs[name+'.min'] = minimized.length == 0 ? 'javascript:void(0)' : winURL.createObjectURL(new Blob([minimized], {type : 'text/css'}))
$('a[data-id="btn-save-'+name+'"]').parent().removeClass('disabled hide')
$('a[data-id="btn-save-'+name+'"]')
.attr({'download' : name+'.min.css'})
.find('.filesize').remove().end()
.append(' ('+readableSize(minimized.length)+')')
.get(0).href = objectURLs[name+'.min'];
}
function releaseUrlObjects(name) {
for(var o in objectURLs) if(objectURLs.hasOwnProperty(o)) {
if(name && o !== name) continue;
if(objectURLs[o] !== null && typeof objectURLs[o] === "object") winURL.revokeObjectURL(objectURLs[o]);
objectURLs[o] = null;
var o2 = o+'-part2';
if(objectURLs[o2] !== null && typeof objectURLs[o2] === "object") winURL.revokeObjectURL(objectURLs[o2]);
}
}
function readableSize(size) {
var val = size, index = 0;
while(val > 1024) {
val = val / 1024;
index++;
}
var format = ['bytes', 'KB', 'MB', 'GB'];
val = val.toFixed(1).replace(/(\.0+)$/g, '');
//if(parseInt(val) > 100) val = parseInt(Math.round(val));
return val + ' ' + format[index];
}
$('#btn-save-selection')
.off('click')
.on('click', function() {
save_selection();
});
var storage_name = 'ace.css-selection';
function save_selection() {
var selection = {}
$('input[type=checkbox][name=less-var]').each(function() {
var name = $(this).attr('data-varname').replace(/^enable\-/, '');
selection[name] = this.checked ? 1 : 0;
});
$('input[type=text][name=less-var],select[name=less-var]').each(function() {
var name = $(this).attr('data-varname').replace(/^enable\-/, '');
selection[name] = this.value;
});
var title = $.trim($('#selection-name').val());
if(title.length == 0) return;
var selections = ace.storage.get(storage_name);
if(!selections) selections = {}
else if(typeof selections === 'string') selections = JSON.parse(selections);
var name = title.replace(/[^\d\w]/g , '-').replace(/\-\-/g, '-').toLowerCase();
selections[name] = {name: name, title: title, selection: selection};
ace.storage.set(storage_name, JSON.stringify(selections));
var opt = $('').appendTo('#selection-list');
opt.attr('value', name);
opt.text(title);
}
function display_selections() {
var selections = ace.storage.get(storage_name);
if(!selections) {
$('#selection-list').parent().addClass('hide');
return;
}
else if(typeof selections === 'string') selections = JSON.parse(selections);
var count = 0;
for(var s in selections) if(selections.hasOwnProperty(s)) {
count++;
var opt = $('').appendTo('#selection-list');
opt.attr('value', selections[s].name);
opt.text(selections[s].title);
}
/**
if(count == 0) {
$('#selection-list').parent().addClass('hide');
return;
}
*/
$('#selection-list')
.off('change.selection')
.on('change.selection', function() {
if(this.value == '') {
$(this).next().addClass('hide');//the remove button
return;
}
var selections = ace.storage.get(storage_name);
if(!selections) return;
else if(typeof selections === 'string') selections = JSON.parse(selections);
for(var s in selections) if(selections.hasOwnProperty(s)) {
if(selections[s].name == this.value) {
$('input[type=checkbox][name=less-var]').removeAttr('checked').closest('.list-group-item').removeClass('active');
var selection = selections[s]['selection'];
for(var i in selection) if(selection.hasOwnProperty(i)) {
var element = $('[name=less-var][data-varname="enable-'+i+'"]');
if( element.is('input[type=checkbox]') && parseInt(selection[i]) == 1) {
element.prop('checked', true).closest('.list-group-item').addClass('active');
}
else if( element.is('select') || element.is('input[type=text]') ){
element.val(selection[i]);
}
}
break;
}
}
$(this).next().removeClass('hide');//the remove button
})
.next().off('click').on('click', function() {
var sel = $('#selection-list');
if(sel.val() == '') return;
var val = sel.val();
var selections = ace.storage.get(storage_name);
if(!selections) return;
else if(typeof selections === 'string') selections = JSON.parse(selections);
for(var s in selections) if(selections.hasOwnProperty(s)) {
if(selections[s].name == val) {
delete selections[s];
ace.storage.set(storage_name, JSON.stringify(selections));
sel.find('option[value='+val+']').remove();
break;
}
}
})
.parent().removeClass('hide');
}
display_selections();
});