예제 #1
0
    public function __construct($sTitle)
    {
        parent::__construct($sTitle);
        $this->m_oTabs = new TabManager();
        ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
        $this->m_sMenu = "";
        $this->m_sMessage = '';
        $this->SetRootUrl(utils::GetAbsoluteUrlAppRoot());
        $this->add_header("Content-type: text/html; charset=utf-8");
        $this->add_header("Cache-control: no-cache");
        $this->add_linked_stylesheet("../css/jquery.treeview.css");
        $this->add_linked_stylesheet("../css/jquery.autocomplete.css");
        $this->add_linked_stylesheet("../css/fg.menu.css");
        $this->add_linked_stylesheet("../css/jquery.multiselect.css");
        $this->add_linked_script('../js/jquery.layout.min.js');
        $this->add_linked_script('../js/jquery.ba-bbq.min.js');
        $this->add_linked_script("../js/jquery.treeview.js");
        $this->add_linked_script("../js/jquery.autocomplete.js");
        $this->add_linked_script("../js/date.js");
        $this->add_linked_script("../js/jquery.blockUI.js");
        $this->add_linked_script("../js/utils.js");
        $this->add_linked_script("../js/swfobject.js");
        $this->add_linked_script("../js/ckeditor/ckeditor.js");
        $this->add_linked_script("../js/ckeditor/adapters/jquery.js");
        $this->add_linked_script("../js/jquery.qtip-1.0.min.js");
        $this->add_linked_script('../js/property_field.js');
        $this->add_linked_script('../js/fg.menu.js');
        $this->add_linked_script('../js/icon_select.js');
        $this->add_linked_script('../js/raphael-min.js');
        $this->add_linked_script('../js/g.raphael.js');
        $this->add_linked_script('../js/g.pie.js');
        $this->add_linked_script('../js/g.dot.js');
        $this->add_linked_script('../js/charts.js');
        $this->add_linked_script('../js/jquery.multiselect.min.js');
        $this->add_linked_script('../js/ajaxfileupload.js');
        $sSearchAny = addslashes(Dict::S('UI:SearchValue:Any'));
        $sSearchNbSelected = addslashes(Dict::S('UI:SearchValue:NbSelected'));
        $this->add_dict_entry('UI:FillAllMandatoryFields');
        $this->add_dict_entry('UI:Button:Cancel');
        $this->add_dict_entry('UI:Button:Done');
        $bForceMenuPane = utils::ReadParam('force_menu_pane', null);
        $sInitClosed = '';
        if ($bForceMenuPane !== null && $bForceMenuPane == 0) {
            $sInitClosed = 'initClosed: true,';
        }
        $this->add_script(<<<EOF
function ShowAboutBox()
{
\t\$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'about_box'}, function(data){
\t\t\$('body').append(data);
\t});
\treturn false;
}
EOF
);
        if (MetaModel::GetConfig()->Get('demo_mode')) {
            // Leave the pane opened
            $sConfigureWestPane = '';
        } else {
            $sConfigureWestPane = <<<EOF
\t\t\t\tif (GetUserPreference('menu_pane', 'open') == 'closed')
\t\t\t\t{
\t\t\t\t\tmyLayout.close('west');
\t\t\t\t}
\t\t\t\tmyLayout.addPinBtn( "#tPinMenu", "west" );
EOF;
        }
        $sJSDisconnectedMessage = json_encode(Dict::S('UI:DisconnectedDlgMessage'));
        $sJSTitle = json_encode(Dict::S('UI:DisconnectedDlgTitle'));
        $sJSLoginAgain = json_encode(Dict::S('UI:LoginAgain'));
        $sJSStayOnThePage = json_encode(Dict::S('UI:StayOnThePage'));
        $sJSDaysMin = json_encode(array(Dict::S('DayOfWeek-Sunday-Min'), Dict::S('DayOfWeek-Monday-Min'), Dict::S('DayOfWeek-Tuesday-Min'), Dict::S('DayOfWeek-Wednesday-Min'), Dict::S('DayOfWeek-Thursday-Min'), Dict::S('DayOfWeek-Friday-Min'), Dict::S('DayOfWeek-Saturday-Min')));
        $sJSMonthsShort = json_encode(array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'), Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short')));
        $iFirstDayOfWeek = (int) Dict::S('Calendar-FirstDayOfWeek');
        $this->m_sInitScript = <<<EOF
\ttry
\t{
\t\tvar myLayout; // a var is required because this page utilizes: myLayout.allowOverflow() method
\t
\t\t// Layout
\t\tpaneSize = GetUserPreference('menu_size', 300)
\t\tmyLayout = \$('body').layout({
\t\t\twest :\t{
\t\t\t\t\t\t{$sInitClosed} minSize: 200, size: paneSize, spacing_open: 16, spacing_close: 16, slideTrigger_open: "mouseover", hideTogglerOnSlide: true, enableCursorHotkey: false,
\t\t\t\t\t\tonclose_end: function(name, elt, state, options, layout)
\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tif (state.isSliding == false)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tSetUserPreference('menu_pane', 'closed', true);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\tonresize_end: function(name, elt, state, options, layout)
\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tif (state.isSliding == false)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tSetUserPreference('menu_size', state.size, true);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\tonopen_end: function(name, elt, state, options, layout)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (state.isSliding == false)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tSetUserPreference('menu_pane', 'open', true);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\tcenter: {
\t\t\t\t\t\tonresize_end: function(name, elt, state, options, layout)
\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\$('.v-resizable').each( function() {
\t\t\t\t\t\t\t\t\tvar fixedWidth = \$(this).parent().innerWidth() - 6;
\t\t\t\t\t\t\t\t\t\$(this).width(fixedWidth);
\t\t\t\t\t\t\t\t\t// Make sure it cannot be resized horizontally
\t\t\t\t\t\t\t\t\t\$(this).resizable('options', { minWidth: fixedWidth, maxWidth:\tfixedWidth });
\t\t\t\t\t\t\t\t\t// Now adjust all the child 'items'
\t\t\t\t\t\t\t\t\tvar innerWidth = \$(this).innerWidth() - 10;
\t\t\t\t\t\t\t\t\t\$(this).find('.item').width(innerWidth);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\$('.panel-resized').trigger('resized');
\t\t\t\t\t\t}
\t\t\t\t
\t\t\t\t\t}
\t\t});
\t\twindow.clearTimeout(iPaneVisWatchDog);
\t\t//myLayout.open( "west" );
\t\t\$('.ui-layout-resizer-west .ui-layout-toggler').css({background: 'transparent'});
\t\t{$sConfigureWestPane}
\t\t
\t\t\$('#left-pane').layout({ resizable: false, spacing_open: 0, south: { size: 94 }, enableCursorHotkey: false });
\t
\t\t// Accordion Menu
\t\t\$("#accordion").accordion({ header: "h3", navigation: true, heightStyle: "content", collapsible: false, icons: false }); // collapsible will be enabled once the item will be selected
\t
\t\t// Tabs, using JQuery BBQ to store the history
\t\t// The "tab widgets" to handle.
\t\tvar tabs = \$('div[id^=tabbedContent]');
\t\t\t
\t\t// This selector will be reused when selecting actual tab widget A elements.
\t\tvar tab_a_selector = 'ul.ui-tabs-nav a';
\t\t  
\t\t// Ugly patch for a change in the behavior of jQuery UI:
\t\t// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
\t\t// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
\t\t// is taken into account and causes "local" tabs to be considered as Ajax
\t\t// unless their URL is equal to the URL of the page...
\t\t\$('div[id^=tabbedContent] > ul > li > a').each(function() {
\t\t\tvar sHash = location.hash;
\t\t\tvar sHref = \$(this).attr("href");
\t\t\tif (sHref.match(/^#/))
\t\t\t{
\t\t\t\tvar sCleanLocation = location.href.toString().replace(sHash, '').replace(/#\$/, '');
\t\t\t\t\$(this).attr("href", sCleanLocation+\$(this).attr("href"));
\t\t\t}
\t\t});

\t\t// Enable tabs on all tab widgets. The `event` property must be overridden so
\t\t// that the tabs aren't changed on click, and any custom event name can be
\t\t// specified. Note that if you define a callback for the 'select' event, it
\t\t// will be executed for the selected tab whenever the hash changes.
\t\ttabs.tabs({
\t\t\tevent: 'change', 'show': function(event, ui) {
\t\t\t\t\$('.resizable', ui.panel).resizable(); // Make resizable everything that claims to be resizable !
\t\t\t},
\t\t\tbeforeLoad: function( event, ui ) {
\t\t\t\tif ( ui.tab.data('loaded') && (ui.tab.attr('data-cache') == 'true')) {
\t\t\t\t\tevent.preventDefault();
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tui.panel.html('<div><img src="../images/indicator.gif"></div>');
\t\t\t\tui.jqXHR.success(function() {
\t\t\t\t\tui.tab.data( "loaded", true );
\t\t\t\t});
\t\t\t}
\t\t});
\t\t\t\t\t
\t\t\$('.resizable').filter(':visible').resizable();
\t}
\tcatch(err)
\t{
\t\t// Do something with the error !
\t\talert(err);
\t}
EOF;
        $this->add_ready_script(<<<EOF
\t
\t// Adjust initial size
\t\$('.v-resizable').each( function()
\t\t{
\t\t\tvar parent_id = \$(this).parent().id;
\t\t\t// Restore the saved height
\t\t\tvar iHeight = GetUserPreference(parent_id+'_'+this.id+'_height', undefined);
\t\t\tif (iHeight != undefined)
\t\t\t{
\t\t\t\t\$(this).height(parseInt(iHeight, 10)); // Parse in base 10 !);
\t\t\t}
\t\t\t// Adjust the child 'item''s height and width to fit
\t\t\tvar container = \$(this);
\t\t\tvar fixedWidth = container.parent().innerWidth() - 6;
\t\t\t// Set the width to fit the parent
\t\t\t\$(this).width(fixedWidth);
\t\t\tvar headerHeight = \$(this).find('.drag_handle').height();
\t\t\t// Now adjust the width and height of the child 'item'
\t\t\tcontainer.find('.item').height(container.innerHeight() - headerHeight - 12).width(fixedWidth - 10);
\t\t}
\t);
\t// Make resizable, vertically only everything that claims to be v-resizable !
\t\$('.v-resizable').resizable( { handles: 's', minHeight: \$(this).find('.drag_handle').height(), minWidth: \$(this).parent().innerWidth() - 6, maxWidth: \$(this).parent().innerWidth() - 6, stop: function()
\t\t{
\t\t\t// Adjust the content
\t\t\tvar container = \$(this);
\t\t\tvar headerHeight = \$(this).find('.drag_handle').height();
\t\t\tcontainer.find('.item').height(container.innerHeight() - headerHeight - 12);//.width(container.innerWidth());
\t\t\tvar parent_id = \$(this).parent().id;
\t\t\tSetUserPreference(parent_id+'_'+this.id+'_height', \$(this).height(), true); // true => persistent
\t\t}
\t} );
\t\t
\t// Tabs, using JQuery BBQ to store the history
\t// The "tab widgets" to handle.
\tvar tabs = \$('div[id^=tabbedContent]');
\t\t
\t// This selector will be reused when selecting actual tab widget A elements.
\tvar tab_a_selector = 'ul.ui-tabs-nav a';
\t  
\t// Define our own click handler for the tabs, overriding the default.
\ttabs.find( tab_a_selector ).click(function()
\t{
\t\tvar state = {};
\t\t\t\t  
\t\t// Get the id of this tab widget.
\t\tvar id = \$(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
\t\t  
\t\t// Get the index of this tab.
\t\tvar idx = \$(this).parent().prevAll().length;
\t\t
\t\t// Set the state!
\t\tstate[ id ] = idx;
\t\t\$.bbq.pushState( state );
\t});
\t
\t// refresh the hash when the tab is changed (from a JS script)
\t\$('body').on( 'tabsactivate', '.ui-tabs', function(event, ui) {
\t\tvar state = {};
\t\t\t
\t\t// Get the id of this tab widget.
\t\tvar id = \$(ui.newTab).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
\t\t
\t\t// Get the index of this tab.
\t\tvar idx = \$(ui.newTab).prevAll().length;
\t\t\t
\t\t// Set the state!
\t\tstate[ id ] = idx;
\t\t\$.bbq.pushState( state );
\t});
\t
\t// Bind an event to window.onhashchange that, when the history state changes,
\t// iterates over all tab widgets, changing the current tab as necessary.
\t\$(window).bind( 'hashchange', function(e)
\t{
\t\t// Iterate over all tab widgets.
\t\ttabs.each(function()
\t\t{  
\t\t\t// Get the index for this tab widget from the hash, based on the
\t\t\t// appropriate id property. In jQuery 1.4, you should use e.getState()
\t\t\t// instead of \$.bbq.getState(). The second, 'true' argument coerces the
\t\t\t// string value to a number.
\t\t\tvar idx = \$.bbq.getState( this.id, true ) || 0;
\t\t\t  
\t\t\t// Select the appropriate tab for this tab widget by triggering the custom
\t\t\t// event specified in the .tabs() init above (you could keep track of what
\t\t\t// tab each widget is on using .data, and only select a tab if it has
\t\t\t// changed).
\t\t\t\$(this).find( tab_a_selector ).eq( idx ).triggerHandler( 'change' );
\t\t});

\t\t// Iterate over all truncated lists to find whether they are expanded or not
\t\t\$('a.truncated').each(function()
\t\t{
\t\t\tvar state = \$.bbq.getState( this.id, true ) || 'close';
\t\t\tif (state == 'open')
\t\t\t{
\t\t\t\t\$(this).trigger('open');
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t\$(this).trigger('close');\t
\t\t\t}
\t\t});
\t});
\t
\t// Shortcut menu actions
\t\$('.actions_button a').click( function() {
\t\taMatches = /#(.*)\$/.exec(window.location.href);
\t\tif (aMatches != null)
\t\t{
\t\t\tcurrentHash = aMatches[1];
\t\t\tif ( /#(.*)\$/.test(this.href))
\t\t\t{
\t\t\t\tthis.href = this.href.replace(/#(.*)\$/, '#'+currentHash);
\t\t\t}
\t\t}
\t});

\t// End of Tabs handling

\t\$(".date-pick").datepicker({
\t\t\tshowOn: 'button',
\t\t\tbuttonImage: '../images/calendar.png',
\t\t\tbuttonImageOnly: true,
\t\t\tdateFormat: 'yy-mm-dd',
\t\t\tconstrainInput: false,
\t\t\tchangeMonth: true,
\t\t\tchangeYear: true,
\t\t\tdayNamesMin: {$sJSDaysMin},
\t\t\tmonthNamesShort: {$sJSMonthsShort},
\t\t\tfirstDay: {$iFirstDayOfWeek}
\t\t});
\t\$(".datetime-pick").datepicker({
\t\t\tshowOn: 'button',
\t\t\tbuttonImage: '../images/calendar.png',
\t\t\tbuttonImageOnly: true,
\t\t\tdateFormat: 'yy-mm-dd 00:00:00',
\t\t\tconstrainInput: false,
\t\t\tchangeMonth: true,
\t\t\tchangeYear: true,
\t\t\tdayNamesMin: {$sJSDaysMin},
\t\t\tmonthNamesShort: {$sJSMonthsShort},
\t\t\tfirstDay: {$iFirstDayOfWeek}
\t\t});

\t// Make sortable, everything that claims to be sortable
\t\$('.sortable').sortable( {axis: 'y', cursor: 'move', handle: '.drag_handle', stop: function()
\t\t{
\t\t\tif (\$(this).hasClass('persistent'))
\t\t\t{
\t\t\t\t// remember the sort order for next time the page is loaded...
\t\t\t\tsSerialized = \$(this).sortable('serialize', {key: 'menu'});
\t\t\t\tvar sTemp = sSerialized.replace(/menu=/g, '');
\t\t\t\tSetUserPreference(this.id+'_order', sTemp.replace(/&/g, ','), true); // true => persistent !
\t\t\t}
\t\t}
\t});
\tdocWidth = \$(document).width();
\t\$('#ModalDlg').dialog({ autoOpen: false, modal: true, width: 0.8*docWidth }); // JQuery UI dialogs
\tShowDebug();
\t\$('#logOffBtn>ul').popupmenu();
\t
\t\$('.caselog_header').click( function () { \$(this).toggleClass('open').next('.caselog_entry').toggle(); });
\t
\t\$(document).ajaxSend(function(event, jqxhr, options) {
\t\tjqxhr.setRequestHeader('X-Combodo-Ajax', 'true');
\t});
\t\$(document).ajaxError(function(event, jqxhr, options) {
\t\tif (jqxhr.status == 401)
\t\t{
\t\t\t\$('<div>'+{$sJSDisconnectedMessage}+'</div>').dialog({
\t\t\t\tmodal:true,
\t\t\t\ttitle: {$sJSTitle},
\t\t\t\tclose: function() { \$(this).remove(); },
\t\t\t\tminWidth: 400,
\t\t\t\tbuttons: [
\t\t\t\t\t{ text: {$sJSLoginAgain}, click: function() { window.location.href= GetAbsoluteUrlAppRoot()+'pages/UI.php' } },
\t\t\t\t\t{ text: {$sJSStayOnThePage}, click: function() { \$(this).dialog('close'); } }
\t\t\t\t]
\t\t\t});
\t\t}
\t});
\t\t\t
EOF
);
        $sUserPrefs = appUserPreferences::GetAsJSON();
        $this->add_script(<<<EOF
//\t\t// for JQuery history
//\t\tfunction history_callback(hash)
//\t\t{
//\t\t\t// do stuff that loads page content based on hash variable
//\t\t\tvar aMatches = /^tab_(.*)\$/.exec(hash);
//\t\t\tif (aMatches != null)
//\t\t\t{
//\t\t\t\tvar tab = \$('#'+hash);
//\t\t\t\ttab.parents('div[id^=tabbedContent]:first').tabs('select', aMatches[1]);
//\t\t\t}
//\t\t}

\t\tfunction goBack()
\t\t{
\t\t\twindow.history.back();
\t\t}
\t\t
\t\tfunction BackToDetails(sClass, id, sDefaultUrl)
\t\t{
\t\t\twindow.bInCancel = true;
\t\t\tif (id > 0)
\t\t\t{
\t\t\t\twindow.location.href = AddAppContext(GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=release_lock_and_details&class='+sClass+'&id='+id);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\twindow.location.href = sDefaultUrl; // Already contains the context...\t\t\t\t
\t\t\t}
\t\t}

\t\tfunction BackToList(sClass)
\t\t{
\t\t\twindow.location.href = AddAppContext(GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=search_oql&oql_class='+sClass+'&oql_clause=WHERE id=0');
\t\t}
\t\t
\t\tfunction ShowDebug()
\t\t{
\t\t\tif (\$('#rawOutput > div').html() != '')
\t\t\t{
\t\t\t\t\$('#rawOutput').dialog( {autoOpen: true, modal:false, width: '80%'});
\t\t\t}
\t\t}
\t\t
\t\tvar oUserPreferences = {$sUserPrefs};

\t\t// For disabling the CKEditor at init time when the corresponding textarea is disabled !
\t\tCKEDITOR.plugins.add( 'disabler',
\t\t{
\t\t\tinit : function( editor )
\t\t\t{
\t\t\t\teditor.on( 'instanceReady', function(e)
\t\t\t\t{
\t\t\t\t\te.removeListener();
\t\t\t\t\t\$('#'+ editor.name).trigger('update');
\t\t\t\t});
\t\t\t}
\t\t\t
\t\t});

\t\t
\t\tfunction FixPaneVis()
\t\t{
\t\t\t\$('.ui-layout-center, .ui-layout-north, .ui-layout-south').css({display: 'block'});
\t\t}
EOF
);
    }