Source: js/lib/gui/ui.js

/**
 * Responsible class to manage all things related with GUI
 * @constructor
 */
function UI(){
}

/**
 * Initialize wizard that show open or create new project
 */
UI.prototype.showIntro = function showIntro() {
	this.initializeWizardDiv();
	this.showNewOpenProject({data:{that:this}});
};

UI.prototype.initializeWizardDiv = function() {
  var container = $(document.createElement('div')).attr('id','wizard');
  container.dialog({modal:true,dialogClass: "no-close",closeOnEscape: false});
};

/**
 * Show wizard with recent projects to open, create new project or open other project
 * @param {event} e to send this object reference
 */
UI.prototype.showNewOpenProject = function showNewOpenProject(e) {
    var that = e.data.that;
    var userconfig = application.config.user.getInstance();
    var backend = application.backend.getInstance();
    var fs = require('fs');
    var wizarddiv = $("#wizard") ;
    wizarddiv.empty();

    var datainfo = userconfig.getLastProjects();
    var template = fs.readFileSync('./templates/initialwizard.step1.hbs',{encoding:'utf8'});
    var templatecompiled = application.util.template.compile(template);
    var data = {
        projects : datainfo.slice(-5)
    };
    wizarddiv.append(templatecompiled(data));
    $('#newproject').click({that:that},that.showTypeProject);
    $('#listProjects button').click({that:that},that.launcherloadProject);
};

/**
 * Load dialog on #wizard div to create new project.
 * @param  {event} e to send this object reference
 */
UI.prototype.showTypeProject = function(e) {
	var that = e.data.that;
	var fs = require('fs');
	$("#wizard").empty();
	var template = fs.readFileSync('./templates/initialwizard.step2.hbs',{encoding:'utf8'});
	var templatecompiled = application.util.template.compile(template);
	$("#wizard").append(templatecompiled());

	$("#advprojbtn").click(function(){
		var controller = application.controller.getInstance();
		controller.createProProject($("#projectname").val());
		$('#wizard').dialog('close');
		$('#wizard').remove();
	});
	$("#smplprojbtn").click(function(){
		var controller = application.controller.getInstance();
		controller.createSimpleProject($("#projectname").val());
		$('#wizard').dialog('close');
		$('#wizard').remove();
	});
	$("#wzrdgoback").click({that:that},that.showNewOpenProject);

	$("#projectname").keyup(function(e){
		var backend = application.backend.getInstance();
		if(backend.checkProjectExists(this.value)){
			$("#projectnamecontainer").removeClass("has-success").addClass("has-error");
			$("#validateindicator").removeClass("glyphicon-ok").addClass("glyphicon-remove");
			$("#advprojbtn").attr("disabled","disabled");
			$("#smplprojbtn").attr("disabled","disabled");

		}
		else{
			$("#projectnamecontainer").addClass("has-success").removeClass("has-error");
			$("#validateindicator").addClass("glyphicon-ok").removeClass("glyphicon-remove");
			$("#advprojbtn").removeAttr("disabled");
			$("#smplprojbtn").removeAttr("disabled");
		}
	})
	.focus();

};


/**
 * Load theme to apply all aplication. This function look for css/js folders and load all find.
 */
UI.prototype.loadTheme = function loadTheme(){
  var fs = require('fs');
  var path = require('path');
  Cloudbook.UI.themeeditorpath = path.join('themes','editor','default');

  var cssbasepath = path.join(Cloudbook.UI.themeeditorpath,'css');
  if(fs.existsSync(cssbasepath)){
    fs.readdirSync(cssbasepath).forEach(function(csspath){
      var css = document.createElement('link');
      css.rel = 'stylesheet';
      css.href = path.join(cssbasepath,csspath);
      document.head.appendChild(css);
    });
  }
  var scriptsbasepath = path.join(Cloudbook.UI.themeeditorpath,'js');
  if(fs.existsSync(scriptsbasepath)){
    fs.readdirSync(scriptsbasepath).forEach(function(jspath){
      CBUtil.include(path.join(scriptsbasepath,jspath))
    });
  }
}

/**
 * Create components buttons to append elements into selected section.
 * Here method call editorView and add_callback methods of CBObjects.
 * See
 * {@link CBObject#editorView} and
 * {@link CBObject.add_callback}
 */
 UI.prototype.renderActionsButtons = function renderActionsButtons(){
  if(!Cloudbook.UI.renderedActionsButtons){

  var that = this;
  var backend = application.backend.getInstance();
  var path = require('path');
  Object.keys(Cloudbook.Actions).forEach(function (component) {
    var componentpath = Cloudbook.Actions[component]['path'];
    var description = require("./" + path.join(componentpath,"metadata.json"));
    backend.loadComponentExtraCss(componentpath,description);
    $(Cloudbook.UI.navactions).append($(document.createElement('button'))
      .bind('click', function () {that.getCBObjectFromButton(component)})
      .addClass('btn').addClass('btn-default')
      .html(that.calculeButtonContent(componentpath, description)));
  });
  /**
   * Flag to detect if actions were rendered
   * @type {boolean}
   */
  Cloudbook.UI.renderedActionsButtons = true;
  }
}

/**
 * Create element from component. This include cbobject and rendered view on targetcontent.
 * When append rendered view on targetcontent then trigger add_callback function related with component
 * @param  {String} component Component idtype indicated on metadata file.
 */
 UI.prototype.getCBObjectFromButton = function getCBObjectFromButton(component) {
  var CBStorage = application.storagemanager.getInstance();
  var fullobject = new Cloudbook.Actions[component]['component']();
  var viewobject = $(fullobject.editorView());
  $(Cloudbook.UI.targetcontent).append(viewobject);
  fullobject.add_callback(viewobject,fullobject);
  var sectionWhereAppend = CBStorage.getSectionById(Cloudbook.UI.selected.attr('data-cbsectionid'));
  sectionWhereAppend.content.push(fullobject);
};

/**
 * On component metadata file may be field "icon" and "label". This fields are used to create action component button.
 * When user click this button, on targetcontent to been added an element.
 * @param  {String} pluginpath relative path to root component
 * @param  {Object} infobutton JSON created from metadata file.
 * @param  {String} infobutton.icon relative icon path
 * @param  {String} infobutton.label Label button.
 * @result {String} Html code to be included on button tag
 */
 UI.prototype.calculeButtonContent = function calculeButtonContent(pluginpath, infobutton) {
  var result = "";
  var fs = require('fs');
  var path = require('path');
  if (infobutton.hasOwnProperty('icon')) {
    var iconpath = path.join(pluginpath,infobutton.icon);
    if (fs.existsSync(iconpath)) {
      result = '<img src="' + iconpath + '" />';
    }
  }
  if (infobutton.hasOwnProperty('label')) {
    result += "<div>"+infobutton.label+"</div>";
  }
  return result;
};


UI.prototype.initSectionsPro = function initSectionsPro() {
  var list = $(document.createElement('ul')).addClass("connectedSortable");
  $(Cloudbook.UI.navsections).html(list).attr('data-cbsectionid','root');
};

UI.prototype.createFirstPage = function createFirstPage() {
  var backend = application.backend.getInstance();
  var cbsecid = backend.initSections();
  var son = this.createSectionProView(cbsecid);
  var list = $("[data-cbsectionid='root'] > ul");
  list.append(son);
  $($(son.children('.displaysection')).children('.divselector')).click();
  this.reloadSortable();
};


UI.prototype.reloadSortable = function reloadSortable(element){
  var that = this;
  var backend = application.backend.getInstance();
  $(".connectedSortable").sortable({
    placeholder: "ui-state-highlight",
    opacity:0.5,
    axis:"y",
    start:function(ev,ui){that.oldparent = ui.item.parent().parent().attr('data-cbsectionid');},
    stop:function(ev,ui){
      that.newparent = ui.item.parent().parent().attr('data-cbsectionid');
      if (that.oldparent !== that.newparent ){
        listoldparent = $("[data-cbsectionid=" + that.oldparent + "] > ul > li").map(function(element){return this.dataset.cbsectionid});
        listnewparent = $("[data-cbsectionid=" + that.newparent + "] > ul > li").map(function(element){return this.dataset.cbsectionid});
        backend.regenerateSubsection(that.oldparent,listoldparent.toArray());
        backend.regenerateSubsection(that.newparent,listnewparent.toArray());
      }
    },
    connectWith:".connectedSortable"}).disableSelection();
}


UI.prototype.createSectionProView = function createSectionProView(cbsecid) {

  var section = $(document.createElement('li')).addClass('cbsection');
  var CBStorage = application.storagemanager.getInstance();
  section.attr('data-cbsectionid',cbsecid);

  var displaysection = $(document.createElement('div')).addClass('displaysection');
  var textsection = $(document.createElement('div')).addClass('divselector');
  var actions = $(document.createElement('button')).html('+').attr('data-toggle','dropdown').attr('id',cbsecid);
  var subsections = $(document.createElement('ul')).addClass('subsections').addClass("connectedSortable");
  textsection.append($(document.createElement('div')).html(CBStorage.getSectionById(cbsecid).name).addClass('caption'));
  
  textsection.click({that:this},this.selectSection);
  actions.click({that:this},this.createMenu);
  displaysection.append([textsection,actions]);
  section.append([displaysection,subsections]);
  return section ;
};

UI.prototype.createMenu = function createMenu(e) {
	var that = e.data.that;
	var element = $(e.currentTarget);
	element.contextMenu([
	{
		name: CBI18n.gettext('Insert before'),
		fun:function(){that.appendBefore(e)}
	},
	{
		name:CBI18n.gettext('Insert after'),
		fun:function(){that.appendAfter(e)}
	},
	{
		name:CBI18n.gettext('Insert subsection'),
		fun:function(){that.appendSubsection(e)}
	},
	{
		name:CBI18n.gettext('Delete'),
		fun: function(){
			that.dialogDeleteSection($(element).closest('[data-cbsectionid]').attr('data-cbsectionid'));
		}
	},
	{
		name:CBI18n.gettext('Edit'),
		fun: function(){
			that.dialogUpdateSectionName($(element).closest('[data-cbsectionid]').attr('data-cbsectionid'));
		}
	}]);
	element.trigger('click.contextMenu',[e]);
};



UI.prototype.createSectionPageView = function createSectionPageView(cbsecid) {

  var section = $(document.createElement('li')).addClass('cbsection');
  section.attr('data-cbsectionid',cbsecid);

  var thumbnail = $(document.createElement('div')).addClass('displaysection');

  var appendbefore = $(document.createElement('div')).addClass('appendbefore');
  var sectionimage = $(document.createElement('div')).addClass('divselector');
  var appendsubsection = $(document.createElement('div')).addClass('appendsubsection');
  var appendafter = $(document.createElement('div')).addClass('appendafter');
  var subsections = $(document.createElement('ul')).addClass('subsections').addClass("connectedSortable");

  appendbefore.append($(document.createElement('img')).attr('src',Cloudbook.UI.themeeditorpath+"/img/add.png"));
  appendsubsection.append($(document.createElement('img')).attr('src',Cloudbook.UI.themeeditorpath+"/img/subsection.png"));
  appendafter.append($(document.createElement('img')).attr('src',Cloudbook.UI.themeeditorpath+"/img/add.png"));
  sectionimage.append($(document.createElement('img')).attr('src',Cloudbook.UI.themeeditorpath+"/img/white.png"));


  appendbefore.click({that:this},this.appendBefore);
  appendsubsection.click({that:this},this.appendSubsection);
  appendafter.click({that:this},this.appendAfter);
  sectionimage.click({that:this},this.selectSection);

  thumbnail.append([appendbefore,sectionimage,appendsubsection,appendafter]);

  section.append([thumbnail,subsections]);
  return section ;
};




UI.prototype.appendBefore = function appendBefore(e){
  var CBStorage = application.storagemanager.getInstance();
  var that = e.data.that;
  var listparents = $(e.currentTarget).parents('.cbsection');
  var backend = application.backend.getInstance();
  var parent = null;
  if (listparents.length <2){
    parent = "root";
  }
  else{
    parent = $(listparents[1]).attr('data-cbsectionid');
  }
  var cbsecid = backend.appendNewSectionObjectByUID(parent,'basic');
  var son = that.createSectionProView(cbsecid);
  $(listparents[0]).before(son);
  that.reloadSortable();
  that.dialogUpdateSectionName(cbsecid);
}


UI.prototype.appendSubsection = function appendSubsection(e){
  var that = e.data.that;
  var CBStorage = application.storagemanager.getInstance();
  var parent = $(e.currentTarget).parents('.cbsection');
  var backend = application.backend.getInstance();
  var parentObjectSection = $(parent[0]).attr('data-cbsectionid');
  var cbsecid = backend.appendNewSectionObjectByUID(parentObjectSection,'basic');
  var newsection = that.createSectionProView(cbsecid);
  $(parent[0]).children("ul").append(newsection);
  that.reloadSortable();
  that.dialogUpdateSectionName(cbsecid);
}

UI.prototype.appendAfter = function appendAfter(e){
  var that = e.data.that;
  var CBStorage = application.storagemanager.getInstance();
  var backend = application.backend.getInstance();
  var listparents = $(e.currentTarget).parents('.cbsection');
  var parentObjectSection = null;
  if (listparents.length <2){
    parentObjectSection = "root";
  }
  else{
    parentObjectSection = $(listparents[1]).attr('data-cbsectionid');
  }
  var cbsecid = backend.appendNewSectionObjectByUID(parentObjectSection,'basic');
  var son = that.createSectionProView(cbsecid);
  $(listparents[0]).after(son);
  that.reloadSortable();
  that.dialogUpdateSectionName(cbsecid);
}

UI.prototype.selectSection = function selectSection(e){
  var that = e.data.that;
  if (Cloudbook.UI.selected !== undefined){
    $(Cloudbook.UI.selected.children('.displaysection')).removeClass('sectionselected');
  }
  Cloudbook.UI.selected = $($(this).parents('.cbsection')[0]);
  Cloudbook.UI.selected.children('.displaysection').addClass('sectionselected');
  that.loadContent(Cloudbook.UI.selected.attr('data-cbsectionid'));
}

UI.prototype.loadContent = function loadContent(id){
  var CBStorage = application.storagemanager.getInstance();
  $(Cloudbook.UI.targetcontent).html("");
  var section = CBStorage.getSectionById(id);
  if (section !== undefined ){
    section.content.forEach(function (element){
      var x = element.editorView();
      $(Cloudbook.UI.targetcontent).append(x);
      element.add_callback(x,element);
    });
  }
}

UI.prototype.updateSectionName = function(name,cbsectionid) {
  $("li[data-cbsectionid='"+cbsectionid+"'] > div.displaysection > div.divselector").html("<div>"+name+"</div>");
};

UI.prototype.dialogUpdateSectionName = function dialogUpdateSectionName(cbsectionid) {
  var controller = application.controller.getInstance();
  var template = application.util.template.getTemplate('templates/updateSectionName.hbs');
  var dialog = $(template());
  dialog.find('button').click(function(){
  	var name = $('#sectionname').val();
  	controller.updateSectionName(name,cbsectionid);
  	dialog.dialog('close');
  	dialog.remove();
  });
  dialog.dialog({modal:true,dialogClass: "no-close",closeOnEscape: false});
}

UI.prototype.deleteSection = function deleteSection(cbsectionid) {
	$('[data-cbsectionid="'+cbsectionid+'"]').remove();
};


UI.prototype.dialogDeleteSection = function dialogDeleteSection(cbsectionid) {
	var controller = application.controller.getInstance();
	controller.deleteSection(cbsectionid);
};

UI.prototype.launcherloadProject = function launcherloadProject(e) {
  var that = e.data.that;
  var element = e.currentTarget;
  var path = element.dataset.path;
  var controller = application.controller.getInstance();
  controller.loadProject(path + "/project.cloudbook");
  $("#wizard").dialog('close');
  $("#wizard").remove();
};

UI.prototype.loadProject = function loadProject(path) {
  var CBStorage = application.storagemanager.getInstance();
  var root = CBStorage.getRoot();
  var that = this;
  this.initSectionsPro();
  var pool = [];
  pool = root.sections.map(function(el){return {parent:'root',identifier:el}});
  while(node = pool.shift()){
    var son = that.createSectionProView(node.identifier);
    $('[data-cbsectionid="'+node.parent+'"] > ul').append(son);
    var objraw = CBStorage.getSectionById(node.identifier);
    pool = pool.concat(objraw.sections.map(function(el){return {parent:node.identifier,identifier:el}}));
  }
};

UI.prototype.emptyTargetContent = function emptyTargetContent() {
  $(Cloudbook.UI.targetcontent).empty();
};

/**
 * This namespace has singleton instance of UI class
 * @namespace ui
 * @memberOf application
 */

CBUtil.createNameSpace('application.ui');
application.ui = CBUtil.singleton(UI);