123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163 |
- <?php
- /**
- * @file
- * Core functionality for the Panels engine.
- */
- define('PANELS_REQUIRED_CTOOLS_API', '2.0.9');
- /**
- * The current working panels version.
- *
- * In a release, it should be 7.x-3.x, which should match what drush make will
- * create. In a dev format, it should be 7.x-3.(x+1)-dev, which will allow
- * modules depending on new features in panels to depend on panels > 7.x-3.x.
- *
- * To define a specific version of Panels as a dependency for another module,
- * simply include a dependency line in that module's info file, e.g.:
- * ; Requires Panels v7.x-3.4 or newer.
- * dependencies[] = panels (>=3.4)
- */
- define('PANELS_VERSION', '7.x-3.8');
- // Hide title use to be TRUE/FALSE. So FALSE remains old behavior.
- define('PANELS_TITLE_FIXED', 0);
- // And TRUE meant no title.
- define('PANELS_TITLE_NONE', 1);
- // And this is the new behavior, where the title field will pick from a pane.
- define('PANELS_TITLE_PANE', 2);
- /**
- * Returns the API version of Panels. This didn't exist in 1.
- *
- * @todo -- this should work more like the CTools API version.
- *
- * @return array
- * An array with the major and minor versions
- */
- function panels_api_version() {
- return array(3, 1);
- }
- /**
- * Implements hook_theme().
- */
- function panels_theme() {
- // Safety: go away if CTools is not at an appropriate version.
- if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
- return array();
- }
- $theme = array();
- $theme['panels_layout_link'] = array(
- 'variables' => array(
- 'title' => NULL,
- 'id' => NULL,
- 'image' => NULL,
- 'link' => NULL,
- 'class' => NULL,
- ),
- );
- $theme['panels_layout_icon'] = array(
- 'variables' => array(
- 'id' => NULL,
- 'image' => NULL,
- 'title' => NULL,
- ),
- );
- $theme['panels_pane'] = array(
- 'variables' => array(
- 'content' => array(),
- 'pane' => array(),
- 'display' => array(),
- ),
- 'path' => drupal_get_path('module', 'panels') . '/templates',
- 'template' => 'panels-pane',
- );
- $theme['panels_common_content_list'] = array(
- 'variables' => array('display' => NULL),
- 'file' => 'includes/common.inc',
- );
- $theme['panels_render_display_form'] = array(
- 'render element' => 'element',
- );
- $theme['panels_dashboard'] = array(
- 'variables' => array(),
- 'path' => drupal_get_path('module', 'panels') . '/templates',
- 'file' => '../includes/callbacks.inc',
- 'template' => 'panels-dashboard',
- );
- $theme['panels_dashboard_link'] = array(
- 'variables' => array('link' => array()),
- 'path' => drupal_get_path('module', 'panels') . '/templates',
- 'file' => '../includes/callbacks.inc',
- 'template' => 'panels-dashboard-link',
- );
- $theme['panels_dashboard_block'] = array(
- 'variables' => array('block' => array()),
- 'path' => drupal_get_path('module', 'panels') . '/templates',
- 'file' => '../includes/callbacks.inc',
- 'template' => 'panels-dashboard-block',
- );
- $theme['panels_add_content_modal'] = array(
- 'variables' => array(
- 'renderer' => NULL,
- 'categories' => array(),
- 'region' => NULL,
- 'category' => NULL,
- 'column_count' => 2,
- ),
- 'path' => drupal_get_path('module', 'panels') . '/templates',
- 'file' => '../includes/add-content.inc',
- 'template' => 'panels-add-content-modal',
- );
- $theme['panels_add_content_link'] = array(
- 'variables' => array(
- 'renderer' => NULL,
- 'region' => NULL,
- 'content_type' => NULL,
- ),
- 'path' => drupal_get_path('module', 'panels') . '/templates',
- 'file' => '../includes/add-content.inc',
- 'template' => 'panels-add-content-link',
- );
- // Register layout and style themes on behalf of all of these items.
- ctools_include('plugins', 'panels');
- // No need to worry about files; the plugin has to already be loaded for us
- // to even know what the theme function is, so files will be auto included.
- $layouts = panels_get_layouts();
- foreach ($layouts as $name => $data) {
- foreach (array('theme', 'admin theme') as $callback) {
- if (!empty($data[$callback])) {
- $theme[$data[$callback]] = array(
- 'variables' => array(
- 'css_id' => NULL,
- 'content' => NULL,
- 'settings' => NULL,
- 'display' => NULL,
- 'layout' => NULL,
- 'renderer' => NULL,
- ),
- 'path' => $data['path'],
- 'file' => $data['file'],
- );
- // If no theme function exists, assume template.
- if (!function_exists("theme_$data[theme]")) {
- $theme[$data[$callback]]['template'] = str_replace('_', '-', $data[$callback]);
- // For preprocess.
- $theme[$data[$callback]]['file'] = $data['file'];
- }
- }
- }
- }
- $styles = panels_get_styles();
- foreach ($styles as $name => $data) {
- if (!empty($data['render pane'])) {
- $theme[$data['render pane']] = array(
- 'variables' => array(
- 'content' => NULL,
- 'pane' => NULL,
- 'display' => NULL,
- 'style' => NULL,
- 'settings' => NULL,
- ),
- 'path' => $data['path'],
- 'file' => $data['file'],
- );
- }
- if (!empty($data['render region'])) {
- $theme[$data['render region']] = array(
- 'variables' => array(
- 'display' => NULL,
- 'owner_id' => NULL,
- 'panes' => NULL,
- 'settings' => NULL,
- 'region_id' => NULL,
- 'style' => NULL,
- ),
- 'path' => $data['path'],
- 'file' => $data['file'],
- );
- }
- if (!empty($data['hook theme'])) {
- if (is_array($data['hook theme'])) {
- $theme += $data['hook theme'];
- }
- elseif (function_exists($data['hook theme'])) {
- $data['hook theme']($theme, $data);
- }
- }
- }
- return $theme;
- }
- /**
- * Implements hook_menu().
- */
- function panels_menu() {
- // Safety: go away if CTools is not at an appropriate version.
- if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
- return array();
- }
- $items = array();
- // Base AJAX router callback.
- $items['panels/ajax'] = array(
- 'access arguments' => array('access content'),
- 'page callback' => 'panels_ajax_router',
- 'theme callback' => 'ajax_base_page_theme',
- 'delivery callback' => 'ajax_deliver',
- 'type' => MENU_CALLBACK,
- );
- $admin_base = array(
- 'file' => 'includes/callbacks.inc',
- 'access arguments' => array('use panels dashboard'),
- );
- // Provide a nice location for a panels admin panel.
- $items['admin/structure/panels'] = array(
- 'title' => 'Panels',
- 'page callback' => 'panels_admin_page',
- 'description' => 'Get a bird\'s eye view of items related to Panels.',
- ) + $admin_base;
- $items['admin/structure/panels/dashboard'] = array(
- 'title' => 'Dashboard',
- 'page callback' => 'panels_admin_page',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- ) + $admin_base;
- $items['admin/structure/panels/settings'] = array(
- 'title' => 'Settings',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('panels_admin_settings_page'),
- 'type' => MENU_LOCAL_TASK,
- ) + $admin_base;
- $items['admin/structure/panels/settings/general'] = array(
- 'title' => 'General',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('panels_admin_settings_page'),
- 'access arguments' => array('administer page manager'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- ) + $admin_base;
- if (module_exists('page_manager')) {
- $items['admin/structure/panels/settings/panel-page'] = array(
- 'title' => 'Panel pages',
- 'page callback' => 'panels_admin_panel_context_page',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => -10,
- ) + $admin_base;
- }
- ctools_include('plugins', 'panels');
- $layouts = panels_get_layouts();
- foreach ($layouts as $name => $data) {
- if (!empty($data['hook menu'])) {
- if (is_array($data['hook menu'])) {
- $items += $data['hook menu'];
- }
- elseif (function_exists($data['hook menu'])) {
- $data['hook menu']($items, $data);
- }
- }
- }
- return $items;
- }
- /**
- * Menu loader function to load a cache item for Panels AJAX.
- *
- * This load all of the includes needed to perform AJAX, and loads the
- * cache object and makes sure it is valid.
- */
- function panels_edit_cache_load($cache_key) {
- ctools_include('display-edit', 'panels');
- ctools_include('plugins', 'panels');
- ctools_include('ajax');
- ctools_include('modal');
- ctools_include('context');
- return panels_edit_cache_get($cache_key);
- }
- /**
- * Implements hook_init().
- */
- function panels_init() {
- // Safety: go away if CTools is not at an appropriate version.
- if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
- if (user_access('administer site configuration')) {
- drupal_set_message(t('Panels is enabled but CTools is out of date. All Panels modules are disabled until CTools is updated. See the status page for more information.'), 'error');
- }
- return;
- }
- ctools_add_css('panels', 'panels');
- }
- /**
- * Implements hook_permission().
- *
- * @todo Almost all of these need to be moved into pipelines.
- */
- function panels_permission() {
- return array(
- 'use panels dashboard' => array(
- 'title' => t("Use Panels Dashboard"),
- 'description' => t('Allows a user to access the <a href="@url">Panels Dashboard</a>.', array('@url' => url('admin/structure/panels'))),
- ),
- // @todo
- 'view pane admin links' => array(
- 'title' => t("View administrative links on Panel panes"),
- 'description' => "",
- ),
- // @todo should we really have a global perm for this, or should it be moved into a pipeline question?
- 'administer pane access' => array(
- 'title' => t("Configure access settings on Panel panes"),
- 'description' => t("Access rules (often also called visibility rules) can be configured on a per-pane basis. This permission allows users to configure those settings."),
- ),
- 'use panels in place editing' => array(
- 'title' => t("Use the Panels In-Place Editor"),
- 'description' => t("Allows a user to utilize Panels' In-Place Editor."),
- ),
- 'change layouts in place editing' => array(
- 'title' => t("Change layouts with the Panels In-Place Editor"),
- 'description' => t("Allows a user to change layouts with the IPE."),
- ),
- 'bypass access in place editing' => array(
- 'title' => t("Bypass access checks when using Panels In-Place Editor"),
- 'description' => t("Allows using IPE even if user does not have additional permissions granted by other modules."),
- 'restrict access' => TRUE,
- ),
- 'administer advanced pane settings' => array(
- 'title' => t("Configure advanced settings on Panel panes"),
- 'description' => "",
- ),
- 'administer panels layouts' => array(
- 'title' => t("Administer Panels layouts"),
- 'description' => t("Allows a user to administer exported Panels layout plugins & instances."),
- ),
- 'administer panels styles' => array(
- 'title' => t("Administer Panels styles"),
- 'description' => t("DEPRECATED: Modules using this permission should use specific style permissions. See Issue #2329419 for more info."),
- ),
- 'administer panels display styles' => array(
- 'title' => t("Administer Panels display styles"),
- 'description' => t("Allows a user to administer the styles of Panel displays."),
- ),
- 'administer panels pane styles' => array(
- 'title' => t("Administer Panels pane styles"),
- 'description' => t("Allows a user to administer the styles of Panel panes."),
- ),
- 'administer panels region styles' => array(
- 'title' => t("Administer Panels region styles"),
- 'description' => t("Allows a user to administer the styles of Panel regions."),
- ),
- 'use panels caching features' => array(
- 'title' => t("Configure caching settings on Panels"),
- 'description' => t("Allows a user to configure caching on Panels displays and panes."),
- ),
- 'use panels locks' => array(
- 'title' => t('Use panel locks'),
- 'description' => t('Allows a user to lock and unlock panes in a panel display.'),
- ),
- 'use ipe with page manager' => array(
- 'title' => t("Use the Panels In-Place Editor with Page Manager"),
- 'description' => t('Allows users with access to the In-Place editor to administer page manager pages. This permission is only needed for users without "use page manager" access.'),
- ),
- );
- }
- /**
- * Implements hook_flush_caches().
- */
- function panels_flush_caches() {
- if (db_table_exists('cache_panels')) {
- return array('cache_panels');
- }
- }
- /**
- * CTools hook implementations.
- *
- * These aren't core Drupal hooks but they are just as important.
- */
- /**
- * Implements hook_ctools_plugin_directory().
- */
- function panels_ctools_plugin_directory($module, $plugin) {
- // To let the system know we implement task and task_handler plugins.
- // Safety: go away if CTools is not at an appropriate version.
- if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
- return;
- }
- // We don't support the 'ctools' 'cache' plugin and pretending to causes
- // errors when they're in use.
- if ($module == 'ctools' && $plugin == 'cache') {
- // If we did we'd make a plugin/ctools_cache or something.
- return;
- }
- if ($module == 'page_manager' || $module == 'panels' || $module == 'ctools' || $module == 'stylizer') {
- // Panels and CTools both implement a 'cache' plugin but we don't implement
- // the CTools version.
- if ($module == 'ctools' && $plugin == 'cache') {
- return;
- }
- return 'plugins/' . $plugin;
- }
- }
- /**
- * Implements hook_ctools_plugin_type().
- *
- * Register layout, style, cache, and display_renderer plugin types, declaring
- * relevant plugin type information as necessary.
- */
- function panels_ctools_plugin_type() {
- return array(
- 'layouts' => array(
- // We can define layouts in themes.
- 'load themes' => TRUE,
- 'process' => 'panels_layout_process',
- 'child plugins' => TRUE,
- ),
- 'styles' => array(
- 'load themes' => TRUE,
- 'process' => 'panels_plugin_styles_process',
- 'child plugins' => TRUE,
- ),
- 'cache' => array(),
- 'display_renderers' => array(
- 'classes' => array('renderer'),
- ),
- 'panels_storage' => array(),
- );
- }
- /**
- * Ensure a layout has a minimal set of data.
- */
- function panels_layout_process(&$plugin) {
- $plugin += array(
- 'category' => t('Miscellaneous'),
- 'description' => '',
- );
- }
- /**
- * Implements hook_ctools_plugin_api().
- */
- function panels_ctools_plugin_api($owner, $api) {
- // Inform CTools about version information for various plugins implemented by
- // panels.
- if ($owner == 'panels' && $api == 'styles') {
- // As of 6.x-3.6, Panels has a slightly new system for style plugins.
- return array('version' => 2.0);
- }
- if ($owner == 'panels' && $api == 'pipelines') {
- return array(
- 'version' => 1,
- 'path' => drupal_get_path('module', 'panels') . '/includes',
- );
- }
- }
- /**
- * Implements hook_views_api().
- */
- function panels_views_api() {
- return array(
- 'api' => 2,
- 'path' => drupal_get_path('module', 'panels') . '/plugins/views',
- );
- }
- /**
- * Perform additional processing on a style plugin.
- *
- * Currently this is only being used to apply versioning information to style
- * plugins in order to ensure the legacy renderer passes the right type of
- * parameters to a style plugin in a hybrid environment of both new and old
- * plugins.
- *
- * @param array $plugin
- * The style plugin that is being processed.
- * @param array $info
- * The style plugin type info array.
- *
- * @see _ctools_process_data()
- */
- function panels_plugin_styles_process(&$plugin, $info) {
- $plugin += array(
- 'weight' => 0,
- );
- $compliant_modules = ctools_plugin_api_info('panels', 'styles', 2.0, 2.0);
- $plugin['version'] = empty($compliant_modules[$plugin['module']]) ? 1.0 : $compliant_modules[$plugin['module']]['version'];
- }
- /**
- * Declare what style types Panels uses.
- */
- function panels_ctools_style_base_types() {
- return array(
- 'region' => array(
- 'title' => t('Panel region'),
- 'preview' => 'panels_stylizer_region_preview',
- 'theme variables' => array(
- 'settings' => NULL,
- 'class' => NULL,
- 'content' => NULL,
- ),
- ),
- 'pane' => array(
- 'title' => t('Panel pane'),
- 'preview' => 'panels_stylizer_pane_preview',
- 'theme variables' => array(
- 'settings' => NULL,
- 'content' => NULL,
- 'pane' => NULL,
- 'display' => NULL,
- ),
- ),
- );
- }
- /**
- * Generates Lorem Ipsum.
- *
- * @return string
- * Lorem ipsum string.
- */
- function panels_stylizer_lipsum() {
- return <<<LIPSUM
- <p>
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at
- velit dolor. Donec egestas tellus sit amet urna rhoncus adipiscing. Proin
- nec porttitor sem. Maecenas aliquam, purus nec tempus dignissim, nulla arcu
- aliquam diam, non tincidunt massa ante vel dolor. Aliquam sapien sapien,
- tincidunt id tristique at, pretium sagittis libero.
- </p>
- <p>
- Nulla facilisi. Curabitur lacinia, tellus sed tristique consequat, diam
- lorem scelerisque felis, at dictum purus augue facilisis lorem. Duis
- pharetra dignissim rutrum. Curabitur ac elit id dui dapibus tincidunt.
- Nulla eget sem quam, non eleifend eros. Cras porttitor tempus lectus ac
- scelerisque. Curabitur vehicula bibendum lorem, vitae ornare ligula
- venenatis ut.
- </p>
- LIPSUM;
- }
- /**
- * Generate a preview given the current settings.
- */
- function panels_stylizer_region_preview($plugin, $settings) {
- ctools_stylizer_add_css($plugin, $settings);
- return theme(
- $plugin['theme'],
- array(
- 'settings' => $settings,
- 'class' => ctools_stylizer_get_css_class($plugin, $settings),
- 'content' => panels_stylizer_lipsum(),
- )
- );
- }
- /**
- * Generate a preview given the current settings.
- */
- function panels_stylizer_pane_preview($plugin, $settings) {
- ctools_stylizer_add_css($plugin, $settings);
- $pane = new stdClass();
- $content = new stdClass();
- $content->title = t('Lorem ipsum');
- $content->content = panels_stylizer_lipsum();
- $content->type = 'dummy';
- $content->subtype = 'dummy';
- $content->css_class = ctools_stylizer_get_css_class($plugin, $settings);
- $display = new panels_display();
- if (!empty($plugin['theme'])) {
- return theme(
- $plugin['theme'],
- array(
- 'settings' => $settings,
- 'content' => $content,
- 'pane' => $pane,
- 'display' => $display,
- )
- );
- }
- else {
- return theme(
- 'panels_pane',
- array(
- 'content' => $content,
- 'pane' => $pane,
- 'display' => $display,
- )
- );
- }
- }
- /**
- * Panels display editing.
- */
- /**
- * @defgroup mainapi Functions comprising the main panels API.
- */
- /**
- * Main API entry point to edit a panel display.
- *
- * Sample implementations utiltizing the the complex $destination behavior can
- * be found in panels_page_edit_content() and, in a separate contrib module,
- * OG Blueprints (http://drupal.org/project/og_blueprints),
- * og_blueprints_blueprint_edit().
- *
- * @param object $display
- * Instanceof panels_display.
- *
- * A fully loaded panels $display object, as returned from
- * panels_load_display(). Merely passing a did is NOT sufficient.
- * Note that 'fully loaded' means the $display must already be loaded with
- * any contexts the caller wishes to have set for the display.
- * @param mixed $destination
- * The redirect destination that the user should be taken to on form
- * submission or cancellation. With panels_edit, $destination has complex
- * effects on the return values of panels_edit() once the form has been
- * submitted. See the explanation of the return value below to understand the
- * different types of values returned by panels_edit() at different stages of
- * FAPI. Under most circumstances, simply passing in drupal_get_destination()
- * is all that's necessary.
- * @param array $content_types
- * An associative array of allowed content types, typically as returned from
- * panels_common_get_allowed_types(). Note that context partially governs
- * available content types, so you will want to create any relevant contexts
- * using panels_create_context() or panels_create_context_empty() to make sure
- * all the appropriate content types are available.
- *
- * @return mixed
- * Because the functions called by panels_edit() invoke the form API,
- * this function returns different values depending on the stage of form
- * submission we're at. In Drupal 5, the phase of form submission is indicated
- * by the contents of $_POST['op']. Here is what you'll get at different
- * stages:
- * - If !$_POST['op']: then we're on on the initial passthrough and the
- * form is being rendered, so it's the $form itself that's being
- * returned. Because negative margins, a common CSS technique, bork the
- * display editor's ajax drag-and-drop, it's important that the $output
- * be printed, not returned. Use this syntax in the caller function:
- * print theme('page', panels_edit($display, $destination, $content_types), FALSE);
- * - If $_POST['op'] == t('Cancel'): form submission has been cancelled.
- * If empty($destination) == FALSE, then there is no return value and the
- * panels API takes care of redirecting to $destination.
- * If empty($destination) == TRUE, then there's still no return value,
- * but the caller function has to take care of form redirection.
- * - If $_POST['op'] == ('Save'): the form has been submitted successfully
- * and has run through panels_edit_display_submit().
- * $output depends on the value of $destination:
- * - If empty($destination) == TRUE: $output contains the modified $display
- * object, and no redirection will occur. This option is useful if the
- * caller needs to perform additional operations on or with the modified
- * $display before the page request is complete. Using hook_form_alter()
- * to add an additional submit handler is typically the preferred method
- * for something like this, but there are certain use cases where that is
- * infeasible and $destination = NULL should be used instead. If this
- * method is employed, the caller will need to handle form redirection.
- * Note that having $_REQUEST['destination'] set, whether via
- * drupal_get_destination() or some other method, will NOT interfere with
- * this functionality; consequently, you can use drupal_get_destination()
- * to safely store your desired redirect in the caller function, then
- * simply use drupal_goto() once panels_edit() has done its business.
- * - If empty($destination) == FALSE: the form will redirect to the URL
- * string given in $destination and NO value will be returned.
- *
- * @ingroup mainapi
- */
- function panels_edit($display, $destination = NULL, $content_types = NULL, $title = FALSE) {
- ctools_include('display-edit', 'panels');
- ctools_include('ajax');
- ctools_include('plugins', 'panels');
- return _panels_edit($display, $destination, $content_types, $title);
- }
- /**
- * API entry point for selecting a layout for a given display.
- *
- * Layout selection is nothing more than a list of radio items encompassing the
- * available layouts for this display, as defined by .inc files in the
- * panels/layouts subdirectory. The only real complexity occurs when a user
- * attempts to change the layout of a display that has some content in it.
- *
- * @param object $display
- * A fully loaded panels $display object, as returned from
- * panels_load_display(). Merely passing a did is NOT sufficient.
- * @param string $finish
- * A string that will be used for the text of the form submission button. If
- * no value is provided, then the form submission button will default to
- * t('Save').
- * @param mixed $destination
- * Basic usage is a string containing the URL that the form should redirect to
- * upon submission. For a discussion of advanced usages, see panels_edit().
- * @param mixed $allowed_layouts
- * Allowed layouts has three different behaviors that depend on which of three
- * value types are passed in by the caller:
- * #- if $allowed_layouts instanceof panels_allowed_layouts
- * (includes subclasses): the most complex use of the API. The caller is
- * passing in a loaded panels_allowed_layouts object that the client
- * module previously created and stored somewhere using a custom storage
- * mechanism.
- * #- if is_string($allowed_layouts): the string will be used in a call to
- * variable_get() which will call the
- * $allowed_layouts . '_allowed_layouts' var. If the data was stored
- * properly in the system var, the $allowed_layouts object will be
- * unserialized and recreated.
- * #- if is_null($allowed_layouts): the default behavior, which also
- * provides backwards compatibility for implementations of the Panels2
- * API written before beta4. In this case, a dummy panels_allowed_layouts
- * object is created which does not restrict any layouts. Subsequent
- * behavior is indistinguishable from pre-beta4 behavior.
- *
- * @return mixed
- * Can return nothing, or a modified $display object, or a redirection string;
- * return values for the panels_edit* family of functions are quite complex.
- * See panels_edit() for detailed discussion.
- *
- * @see panels_edit()
- * @see panels_common_set_allowed_layouts()
- */
- function panels_edit_layout($display, $finish, $destination = NULL, $allowed_layouts = NULL) {
- ctools_include('display-layout', 'panels');
- ctools_include('plugins', 'panels');
- return _panels_edit_layout($display, $finish, $destination, $allowed_layouts);
- }
- /**
- * Panels database functions.
- */
- /**
- * Forms the basis of a panel display.
- */
- class panels_display {
- public $args = array();
- public $content = array();
- public $panels = array();
- public $incoming_content = NULL;
- public $css_id = NULL;
- public $context = array();
- public $did = 'new';
- public $renderer = 'standard';
- /**
- * Add a pane.
- */
- public function add_pane(&$pane, $location = NULL) {
- // If no location specified, use what's set in the pane.
- if (empty($location)) {
- $location = $pane->panel;
- }
- else {
- $pane->panel = $location;
- }
- // Generate a permanent uuid for this pane, and use
- // it as a temporary pid.
- $pane->uuid = ctools_uuid_generate();
- $pane->pid = 'new-' . $pane->uuid;
- // Add the pane to the appropriate spots.
- $this->content[$pane->pid] = &$pane;
- $this->panels[$location][] = $pane->pid;
- }
- /**
- * Duplicate a pane.
- */
- public function duplicate_pane($pid, $location = FALSE) {
- $pane = $this->clone_pane($pid);
- $this->add_pane($pane, $location);
- }
- /**
- * Get the title from a display.
- *
- * The display must have already been rendered, or the setting to set the
- * display's title from a pane's title will not have worked.
- *
- * @return mixed
- * The title to use. If NULL, this means to let any default title that may
- * be in use pass through. i.e, do not actually set the title.
- */
- public function get_title() {
- switch ($this->hide_title) {
- case PANELS_TITLE_NONE:
- return '';
- case PANELS_TITLE_PANE:
- return isset($this->stored_pane_title) ? $this->stored_pane_title : '';
- case PANELS_TITLE_FIXED:
- case FALSE;
- // For old exported panels that are not in the database.
- if (!empty($this->title)) {
- return filter_xss_admin(ctools_context_keyword_substitute($this->title, array(), $this->context));
- }
- return NULL;
- }
- }
- /**
- * Render this panels display.
- *
- * After checking to ensure the designated layout plugin is valid, a
- * display renderer object is spawned and runs its rendering logic.
- *
- * @param mixed $renderer
- * An instantiated display renderer object, or the name of a display
- * renderer plugin+class to be fetched. Defaults to NULL. When NULL, the
- * predesignated display renderer will be used.
- *
- * @return mixed
- * NULL or output of render function.
- */
- public function render($renderer = NULL) {
- $layout = panels_get_layout($this->layout);
- if (!$layout) {
- return NULL;
- }
- // If we were not given a renderer object, load it.
- if (!is_object($renderer)) {
- // If the renderer was not specified, default to $this->renderer
- // which is either standard or was already set for us.
- $renderer = panels_get_renderer_handler(!empty($renderer) ? $renderer : $this->renderer, $this);
- if (!$renderer) {
- return NULL;
- }
- }
- $output = '';
- // Let modules act just prior to render.
- foreach (module_implements('panels_pre_render') as $module) {
- $function = $module . '_panels_pre_render';
- $output .= $function($this, $renderer);
- }
- $output .= $renderer->render();
- // Let modules act just after render.
- foreach (module_implements('panels_post_render') as $module) {
- $function = $module . '_panels_post_render';
- $output .= $function($this, $renderer);
- }
- return $output;
- }
- /**
- * Determine if the given user can perform the requested operation.
- *
- * @param string $op
- * An operation like: create, read, update, or delete.
- * @param object $account
- * (optional) The account to check access for.
- *
- * @return bool
- * TRUE if access is granted; otherwise FALSE.
- */
- public function access($op, $account = NULL) {
- global $user;
- if (!$account) {
- $account = $user;
- }
- // Even administrators need to go through the access system. However, to
- // support legacy plugins, user 1 gets full access no matter what.
- if ($account->uid == 1) {
- return TRUE;
- }
- if (!in_array($op, array('create', 'read', 'update', 'delete', 'change layout'))) {
- return FALSE;
- }
- if (empty($this->storage_type) || empty($this->storage_id)) {
- return FALSE;
- }
- if ($this->storage_type == 'unknown') {
- return FALSE;
- }
- $storage_plugin = panels_get_panels_storage_plugin($this->storage_type);
- if (!$storage_plugin) {
- return FALSE;
- }
- $access_callback = panels_plugin_get_function('panels_storage', $storage_plugin, 'access callback');
- if (!$access_callback) {
- return FALSE;
- }
- return $access_callback($this->storage_type, $this->storage_id, $op, $account);
- }
- }
- /**
- * End of 'defgroup mainapi', although other functions are specifically added later.
- */
- /**
- * Creates a new display, setting the ID to our magic new id.
- */
- function panels_new_display() {
- ctools_include('export');
- $display = ctools_export_new_object('panels_display', FALSE);
- $display->did = 'new';
- return $display;
- }
- /**
- * Create a new pane.
- *
- * @todo -- use schema API for some of this?
- */
- function panels_new_pane($type, $subtype, $set_defaults = FALSE) {
- ctools_include('export');
- $pane = ctools_export_new_object('panels_pane', FALSE);
- $pane->pid = 'new';
- $pane->type = $type;
- $pane->subtype = $subtype;
- if ($set_defaults) {
- ctools_include('content');
- $content_type = ctools_get_content_type($type);
- $content_subtype = ctools_content_get_subtype($content_type, $subtype);
- $pane->configuration = ctools_content_get_defaults($content_type, $content_subtype);
- }
- drupal_alter('panels_new_pane', $pane);
- return $pane;
- }
- /**
- * Load and fill the requested $display object(s).
- *
- * Helper function primarily for for panels_load_display().
- *
- * @param array $dids
- * An indexed array of dids to be loaded from the database.
- *
- * @return array
- * An array of displays, keyed by their display dids.
- *
- * @todo schema API can drasticly simplify this code.
- */
- function panels_load_displays($dids) {
- $displays = array();
- if (empty($dids) || !is_array($dids)) {
- return $displays;
- }
- $result = db_query(
- "SELECT * FROM {panels_display} WHERE did IN (:dids)",
- array(':dids' => $dids)
- );
- ctools_include('export');
- foreach ($result as $obj) {
- $displays[$obj->did] = ctools_export_unpack_object('panels_display', $obj);
- // Modify the hide_title field to go from a bool to an int if necessary.
- }
- $result = db_query(
- "SELECT * FROM {panels_pane} WHERE did IN (:dids) ORDER BY did, panel, position",
- array(':dids' => $dids)
- );
- foreach ($result as $obj) {
- $pane = ctools_export_unpack_object('panels_pane', $obj);
- $displays[$pane->did]->panels[$pane->panel][] = $pane->pid;
- $displays[$pane->did]->content[$pane->pid] = $pane;
- }
- return $displays;
- }
- /**
- * Load a single display.
- *
- * @param int $did
- * The display id (did) of the display to be loaded.
- *
- * @return object $display
- * Returns a partially-loaded panels_display object. $display objects returned
- * from this function have only the following data:
- * - $display->did (the display id)
- * - $display->name (the 'name' of the display, where applicable - it often isn't)
- * - $display->layout (a string with the system name of the display's layout)
- * - $display->panel_settings (custom layout style settings contained in an associative array; NULL if none)
- * - $display->layout_settings (panel size and configuration settings for Flexible layouts; NULL if none)
- * - $display->css_id (the special css_id that has been assigned to this display, if any; NULL if none)
- * - $display->content (an array of pane objects, keyed by pane id (pid))
- * - $display->panels (an associative array of panel regions, each an indexed array of pids in the order they appear in that region)
- * - $display->cache (any relevant data from panels_simple_cache)
- * - $display->args
- * - $display->incoming_content
- * While all of these members are defined, $display->context is NEVER defined in the returned $display;
- * it must be set using one of the ctools_context_create() functions.
- *
- * @ingroup mainapi
- */
- function panels_load_display($did) {
- $displays = panels_load_displays(array($did));
- if (!empty($displays)) {
- return array_shift($displays);
- }
- }
- /**
- * Save a display object.
- *
- * Note that a new $display only receives a real did once it is run through
- * this function, and likewise for the pid of any new pane.
- *
- * Until then, a new display uses a string placeholder, 'new', in place of
- * a real did, and a new pane (whether on a new $display or not) appends a
- * universally-unique identifier (which is stored permanently in the 'uuid'
- * field). This format is also used in place of the real pid for exports.
- *
- * @param object $display
- * The display object to be saved. Passed by reference so the caller need not
- * use the return value for any reason except convenience.
- *
- * @return object $display
- * This display panel display object to return.
- *
- * @ingroup mainapi
- */
- function panels_save_display(&$display) {
- $update = (isset($display->did) && is_numeric($display->did)) ? array('did') : array();
- if (empty($display->uuid) || !ctools_uuid_is_valid($display->uuid)) {
- $display->uuid = ctools_uuid_generate();
- }
- drupal_write_record('panels_display', $display, $update);
- $pids = array();
- if ($update) {
- // Get a list of all panes currently in the database for this display so we
- // can know if there are panes that need to be deleted. (i.e, aren't
- // currently in our list of panes).
- $result = db_query(
- "SELECT pid FROM {panels_pane} WHERE did = :did",
- array(':did' => $display->did)
- );
- foreach ($result as $pane) {
- $pids[$pane->pid] = $pane->pid;
- }
- }
- // Update all the panes.
- ctools_include('plugins', 'panels');
- ctools_include('content');
- foreach ($display->panels as $id => $panes) {
- $position = 0;
- $new_panes = array();
- foreach ((array) $panes as $pid) {
- if (!isset($display->content[$pid])) {
- continue;
- }
- $pane = $display->content[$pid];
- $type = ctools_get_content_type($pane->type);
- $pane->position = $position++;
- $pane->did = $display->did;
- $old_pid = $pane->pid;
- if (empty($pane->uuid) || !ctools_uuid_is_valid($pane->uuid)) {
- $pane->uuid = ctools_uuid_generate();
- }
- drupal_write_record('panels_pane', $pane, is_numeric($pid) ? array('pid') : array());
- // Allow other modules to take action after a pane is saved.
- if ($pane->pid == $old_pid) {
- module_invoke_all('panels_pane_update', $pane);
- }
- else {
- module_invoke_all('panels_pane_insert', $pane);
- }
- if ($pane->pid != $old_pid) {
- // Remove the old new-* entry from the displays content.
- unset($display->content[$pid]);
- // Put it back so our pids and positions can be used.
- $display->content[$pane->pid] = $pane;
- // If the title pane was one of our panes that just got its ID changed,
- // we need to change it in the database, too.
- if (isset($display->title_pane) && $display->title_pane == $old_pid) {
- $display->title_pane = $pane->pid;
- // Do a simple update query to write it so we don't have to rewrite
- // the whole record. We can't just save writing the whole record here
- // because it was needed to get the did. Chicken, egg, more chicken.
- db_update('panels_display')
- ->fields(array(
- 'title_pane' => $pane->pid,
- ))
- ->condition('did', $display->did)
- ->execute();
- }
- }
- // re-add this to the list of content for this panel.
- $new_panes[] = $pane->pid;
- // Remove this from the list of panes scheduled for deletion.
- if (isset($pids[$pane->pid])) {
- unset($pids[$pane->pid]);
- }
- }
- $display->panels[$id] = $new_panes;
- }
- if (!empty($pids)) {
- // Allow other modules to take action before a panes are deleted.
- module_invoke_all('panels_pane_delete', $pids);
- db_delete('panels_pane')->condition('pid', $pids)->execute();
- }
- // Clear any cached content for this display.
- panels_clear_cached_content($display);
- // Allow other modules to take action when a display is saved.
- module_invoke_all('panels_display_save', $display);
- // Log the change to watchdog, using the same style as node.module.
- $watchdog_args = array('%did' => $display->did);
- if (!empty($display->title)) {
- $watchdog_args['%title'] = $display->title;
- watchdog('content', 'Panels: saved display "%title" with display id %did', $watchdog_args, WATCHDOG_NOTICE);
- }
- else {
- watchdog('content', 'Panels: saved display with id %did', $watchdog_args, WATCHDOG_NOTICE);
- }
- // To be nice, even though we have a reference.
- return $display;
- }
- /**
- * Delete a display.
- */
- function panels_delete_display($display) {
- if (is_object($display)) {
- $did = $display->did;
- }
- else {
- $did = $display;
- }
- module_invoke_all('panels_delete_display', $did);
- db_delete('panels_display')->condition('did', $did)->execute();
- db_delete('panels_pane')->condition('did', $did)->execute();
- }
- /**
- * Exports the provided display into portable code.
- *
- * This function is primarily intended as a mechanism for cloning displays.
- * It generates an exact replica (in code) of the provided $display, with
- * the exception that it replaces all ids (dids and pids) with place-holder
- * values (consisting of the display or pane's uuid, with a 'new-' prefix).
- *
- * Only once panels_save_display() is called on the code version of $display
- * will the exported display be written to the database and permanently saved.
- *
- * @param object $display
- * This export function does no loading of additional data about the provided
- * display. Consequently, the caller should make sure that all the desired
- * data has been loaded into the $display before calling this function.
- * @param string $prefix
- * A string prefix that is prepended to each line of exported code. This is
- * primarily used for prepending a double space when exporting so that the
- * code indents and lines up nicely.
- *
- * @return string $output
- * The passed-in $display expressed as code, ready to be imported. Import by
- * running eval($output) in the caller function; doing so will create a new
- * $display variable with all the exported values. Note that if you have
- * already defined a $display variable in the same scope as where you eval(),
- * your existing $display variable WILL be overwritten.
- *
- * @see panels_page_export() or _panels_page_fetch_display() for samples.
- *
- * @ingroup mainapi
- */
- function panels_export_display($display, $prefix = '') {
- ctools_include('export');
- if (empty($display->uuid) || !ctools_uuid_is_valid($display->uuid)) {
- $display->uuid = ctools_uuid_generate();
- }
- $display->did = 'new-' . $display->uuid;
- $output = ctools_export_object('panels_display', $display, $prefix);
- // Initialize empty properties.
- $output .= $prefix . '$display->content = array()' . ";\n";
- $output .= $prefix . '$display->panels = array()' . ";\n";
- $panels = array();
- $title_pid = 0;
- if (!empty($display->content)) {
- $region_counters = array();
- foreach ($display->content as $pane) {
- if (!isset($pane->uuid) || !ctools_uuid_is_valid($pane->uuid)) {
- $pane->uuid = ctools_uuid_generate();
- }
- $pid = 'new-' . $pane->uuid;
- if ($pane->pid == $display->title_pane) {
- $title_pid = $pid;
- }
- $pane->pid = $pid;
- $output .= ctools_export_object('panels_pane', $pane, $prefix);
- $output .= $prefix . '$display->content[\'' . $pane->pid . '\'] = $pane' . ";\n";
- if (!isset($region_counters[$pane->panel])) {
- $region_counters[$pane->panel] = 0;
- }
- $output .= $prefix . '$display->panels[\'' . $pane->panel . '\'][' . $region_counters[$pane->panel]++ . '] = \'' . $pane->pid . "';\n";
- }
- }
- $output .= $prefix . '$display->hide_title = ';
- switch ($display->hide_title) {
- case PANELS_TITLE_FIXED:
- $output .= 'PANELS_TITLE_FIXED';
- break;
- case PANELS_TITLE_NONE:
- $output .= 'PANELS_TITLE_NONE';
- break;
- case PANELS_TITLE_PANE:
- $output .= 'PANELS_TITLE_PANE';
- break;
- }
- $output .= ";\n";
- $output .= $prefix . '$display->title_pane =' . " '$title_pid';\n";
- return $output;
- }
- /**
- * Panels Render Display.
- *
- * Render a display by loading the content into an appropriate
- * array and then passing through to panels_render_layout.
- *
- * if $incoming_content is NULL, default content will be applied. Use
- * an empty string to indicate no content.
- *
- * @ingroup hook_invocations
- */
- function panels_render_display(&$display, $renderer = NULL) {
- ctools_include('plugins', 'panels');
- ctools_include('context');
- if (!empty($display->context)) {
- if ($form_context = ctools_context_get_form($display->context)) {
- $form_context->form['#theme'] = 'panels_render_display_form';
- if (empty($form_context->form['#theme_wrappers']) || !in_array('form', $form_context->form['#theme_wrappers'])) {
- $form_context->form['#theme_wrappers'][] = 'form';
- }
- $form_context->form['#display'] = &$display;
- return $form_context->form;
- }
- }
- return $display->render($renderer);
- }
- /**
- * Theme function to render our panel as a form.
- *
- * When rendering a display as a form, the entire display needs to be
- * inside the <form> tag so that the form can be spread across the
- * panes. This sets up the form system to be the main caller and we
- * then operate as a theme function of the form.
- */
- function theme_panels_render_display_form($vars) {
- return $vars['element']['#display']->render();
- }
- /**
- * Panels layout icon function.
- */
- function panels_print_layout_icon($id, $layout, $title = NULL) {
- ctools_add_css('panels_admin', 'panels');
- $file = $layout['path'] . '/' . $layout['icon'];
- return theme(
- 'panels_layout_icon',
- array(
- 'id' => $id,
- 'image' => theme(
- 'image',
- array(
- 'path' => $file,
- 'alt' => strip_tags($layout['title']),
- 'title' => strip_tags($layout['description']),
- )
- ),
- 'title' => $title,
- )
- );
- }
- /**
- * Theme the layout icon image.
- *
- * @todo move to theme.inc
- */
- function theme_panels_layout_icon($vars) {
- $id = $vars['id'];
- $image = $vars['image'];
- $title = $vars['title'];
- $output = '<div class="layout-icon">';
- $output .= $image;
- if ($title) {
- $output .= '<div class="caption">' . $title . '</div>';
- }
- $output .= '</div>';
- return $output;
- }
- /**
- * Theme the layout link image.
- *
- * @layout
- *
- * @todo Why isn't this a template at this point?
- * @todo Why does this take 4 arguments but only makes use of two?
- */
- function theme_panels_layout_link($vars) {
- $output = '<div class="' . implode(' ', $vars['class']) . '">';
- $output .= $vars['image'];
- $output .= '<div>' . $vars['title'] . '</div>';
- $output .= '</div>';
- return $output;
- }
- /**
- * Print the layout link. Sends out to a theme function.
- *
- * @layout
- */
- function panels_print_layout_link($id, $layout, $link, $options = array(), $current_layout = FALSE) {
- if (isset($options['query']['q'])) {
- unset($options['query']['q']);
- }
- // Setup classes for layout link, including current-layout information.
- $class = array('layout-link');
- if ($current_layout == $id) {
- $options['attributes']['class'][] = 'current-layout-link';
- $class[] = 'current-layout';
- }
- ctools_add_css('panels_admin', 'panels');
- $file = $layout['path'] . '/' . $layout['icon'];
- $image = l(
- theme('image', array('path' => $file)),
- $link,
- array('html' => TRUE) + $options
- );
- $title = l($layout['title'], $link, $options);
- return theme(
- 'panels_layout_link',
- array(
- 'title' => $title,
- 'image' => $image,
- 'class' => $class,
- )
- );
- }
- /**
- * Panels Get legacy state.
- *
- * Gateway to the PanelsLegacyState class/object, which does all legacy state
- * checks and provides information about the cause of legacy states as needed.
- *
- * @return PanelsLegacyState $legacy
- * Returns a legacy panels state.
- */
- function panels_get_legacy_state() {
- static $legacy = NULL;
- if (!isset($legacy)) {
- ctools_include('legacy', 'panels');
- $legacy = new PanelsLegacyState();
- }
- return $legacy;
- }
- /**
- * Get the display that is currently being rendered as a page.
- *
- * Unlike in previous versions of this, this only returns the display,
- * not the page itself, because there are a number of different ways
- * to get to this point. It is hoped that the page data isn't needed
- * at this point. If it turns out there is, we will do something else to
- * get that functionality.
- */
- function panels_get_current_page_display($change = NULL) {
- static $display = NULL;
- if ($change) {
- $display = $change;
- }
- return $display;
- }
- /**
- * Clean up the panel pane variables for the template.
- */
- function template_preprocess_panels_pane(&$vars) {
- $content = &$vars['content'];
- $vars['contextual_links'] = array();
- $vars['classes_array'] = array();
- $vars['admin_links'] = '';
- if (module_exists('contextual') && user_access('access contextual links')) {
- $links = array();
- // These are specified by the content.
- if (!empty($content->admin_links)) {
- $links += $content->admin_links;
- }
- // Take any that may have been in the render array we were given and
- // move them up so they appear outside the pane properly.
- if (is_array($content->content) && isset($content->content['#contextual_links'])) {
- $element = array(
- '#type' => 'contextual_links',
- '#contextual_links' => $content->content['#contextual_links'],
- );
- unset($content->content['#contextual_links']);
- // Add content to $element array.
- if (is_array($content->content)) {
- $element['#element'] = $content->content;
- }
- $element = contextual_pre_render_links($element);
- if (!empty($element['#links'])) {
- $links += $element['#links'];
- }
- }
- if ($links) {
- $build = array(
- '#prefix' => '<div class="contextual-links-wrapper">',
- '#suffix' => '</div>',
- '#theme' => 'links__contextual',
- '#links' => $links,
- '#attributes' => array('class' => array('contextual-links')),
- '#attached' => array(
- 'library' => array(array('contextual', 'contextual-links')),
- ),
- );
- $vars['classes_array'][] = 'contextual-links-region';
- $vars['admin_links'] = drupal_render($build);
- }
- }
- // Basic classes.
- $vars['classes_array'][] = 'panel-pane';
- $vars['id'] = '';
- // Add some usable classes based on type/subtype.
- ctools_include('cleanstring');
- $type_class = $content->type ? 'pane-' . ctools_cleanstring($content->type, array('lower case' => TRUE)) : '';
- $subtype_class = $content->subtype ? 'pane-' . ctools_cleanstring($content->subtype, array('lower case' => TRUE)) : '';
- // Sometimes type and subtype are the same. Avoid redundant classes.
- $vars['classes_array'][] = $type_class;
- if ($type_class != $subtype_class) {
- $vars['classes_array'][] = $subtype_class;
- }
- // Add id and custom class if sent in.
- if (!empty($content->content)) {
- if (!empty($content->css_id)) {
- $vars['id'] = ' id="' . $content->css_id . '"';
- }
- if (!empty($content->css_class)) {
- $vars['classes_array'][] = $content->css_class;
- }
- }
- // Set up some placeholders for constructing template file names.
- $base = 'panels_pane';
- $delimiter = '__';
- // Add template file suggestion for content type and sub-type.
- $vars['theme_hook_suggestions'][] = $base . $delimiter . $content->type;
- $vars['theme_hook_suggestions'][] = $base . $delimiter . strtr(ctools_cleanstring($content->type, array('lower case' => TRUE)), '-', '_') . $delimiter . strtr(ctools_cleanstring($content->subtype, array('lower case' => TRUE)), '-', '_');
- $vars['pane_prefix'] = !empty($content->pane_prefix) ? $content->pane_prefix : '';
- $vars['pane_suffix'] = !empty($content->pane_suffix) ? $content->pane_suffix : '';
- $vars['title'] = !empty($content->title) ? $content->title : '';
- $vars['title_heading'] = !empty($content->title_heading) ? $content->title_heading : variable_get('override_title_heading', 'h2');
- $vars['title_attributes_array']['class'][] = 'pane-title';
- $vars['feeds'] = !empty($content->feeds) ? implode(' ', $content->feeds) : '';
- $vars['links'] = !empty($content->links) ? theme('links', array('links' => $content->links)) : '';
- $vars['more'] = '';
- if (!empty($content->more)) {
- if (empty($content->more['title'])) {
- $content->more['title'] = t('more');
- }
- $vars['more'] = l($content->more['title'], $content->more['href'], $content->more);
- }
- if (!empty($content->attributes)) {
- $vars['attributes_array'] = array_merge($vars['attributes_array'], $content->attributes);
- }
- $vars['content'] = !empty($content->content) ? $content->content : '';
- }
- /**
- * Route Panels' AJAX calls to the correct object.
- *
- * Panels' AJAX is controlled mostly by renderer objects. This menu callback
- * accepts the incoming request, figures out which object should handle the
- * request, and attempts to route it. If no object can be found, the default
- * Panels editor object is used.
- *
- * Calls are routed via the ajax_* method space. For example, if visiting
- * panels/ajax/add-pane then $renderer::ajax_add_pane() will be called.
- * This means commands can be added without having to create new callbacks.
- *
- * The first argument *must always* be the cache key so that a cache object
- * can be passed through. Other arguments will be passed through untouched
- * so that the method can do whatever it needs to do.
- */
- function panels_ajax_router() {
- $args = func_get_args();
- if (count($args) < 3) {
- return MENU_NOT_FOUND;
- }
- ctools_include('display-edit', 'panels');
- ctools_include('plugins', 'panels');
- ctools_include('ajax');
- ctools_include('modal');
- ctools_include('context');
- ctools_include('content');
- $plugin_name = array_shift($args);
- $method = array_shift($args);
- $cache_key = array_shift($args);
- $plugin = panels_get_display_renderer($plugin_name);
- if (!$plugin) {
- // This is the default renderer for handling AJAX commands.
- $plugin = panels_get_display_renderer('editor');
- }
- $cache = panels_edit_cache_get($cache_key);
- if (empty($cache)) {
- return MENU_ACCESS_DENIED;
- }
- $renderer = panels_get_renderer_handler($plugin, $cache->display);
- if (!$renderer) {
- return MENU_ACCESS_DENIED;
- }
- $method = 'ajax_' . str_replace('-', '_', $method);
- if (!method_exists($renderer, $method)) {
- return MENU_NOT_FOUND;
- }
- $renderer->cache = &$cache;
- ctools_include('cleanstring');
- $renderer->clean_key = ctools_cleanstring($cache_key);
- $op = $renderer->get_panels_storage_op_for_ajax($method);
- if (!$cache->display->access($op)) {
- return MENU_ACCESS_DENIED;
- }
- $output = call_user_func_array(array($renderer, $method), $args);
- if (empty($output) && !empty($renderer->commands)) {
- return array(
- '#type' => 'ajax',
- '#commands' => $renderer->commands,
- );
- }
- else {
- return $output;
- }
- }
- /**
- * Panels caching functions and callbacks.
- *
- * When editing displays and the like, Panels has a caching system that relies
- * on a callback to determine where to get the actual cache.
- *
- * @todo This system needs to be better documented so that it can be better used.
- */
- /**
- * Get an object from cache.
- */
- function panels_cache_get($obj, $did, $skip_cache = FALSE) {
- ctools_include('object-cache');
- // We often store contexts in cache, so let's just make sure we can load them.
- ctools_include('context');
- return ctools_object_cache_get($obj, 'panels_display:' . $did, $skip_cache);
- }
- /**
- * Save the edited object into the cache.
- */
- function panels_cache_set($obj, $did, $cache) {
- ctools_include('object-cache');
- return ctools_object_cache_set($obj, 'panels_display:' . $did, $cache);
- }
- /**
- * Clear a object from the cache; used if the editing is aborted.
- */
- function panels_cache_clear($obj, $did) {
- ctools_include('object-cache');
- return ctools_object_cache_clear($obj, 'panels_display:' . $did);
- }
- /**
- * Create the default cache for editing panel displays.
- *
- * If an application is using the Panels display editor without having
- * specified a cache key, this method can be used to create the default
- * cache.
- */
- function panels_edit_cache_get_default(&$display, $content_types = NULL, $title = FALSE) {
- if (empty($content_types)) {
- $content_types = ctools_content_get_available_types();
- }
- $display->cache_key = $display->did;
- panels_cache_clear('display', $display->did);
- $cache = new stdClass();
- $cache->display = &$display;
- $cache->content_types = $content_types;
- $cache->display_title = $title;
- panels_edit_cache_set($cache);
- return $cache;
- }
- /**
- * Panels Editor Cache Get.
- *
- * Method to allow modules to provide their own caching mechanism for the
- * display editor.
- */
- function panels_edit_cache_get($cache_key) {
- if (strpos($cache_key, ':') !== FALSE) {
- list($module, $argument) = explode(':', $cache_key, 2);
- return module_invoke($module, 'panels_cache_get', $argument);
- }
- // Fall back to our normal method.
- return panels_cache_get('display', $cache_key);
- }
- /**
- * Panels Editor Cache Set.
- *
- * Method to allow modules to provide their own caching mechanism for the
- * display editor.
- */
- function panels_edit_cache_set($cache) {
- $cache_key = $cache->display->cache_key;
- if (strpos($cache_key, ':') !== FALSE) {
- list($module, $argument) = explode(':', $cache_key, 2);
- return module_invoke($module, 'panels_cache_set', $argument, $cache);
- }
- // Fall back to our normal method.
- return panels_cache_set('display', $cache_key, $cache);
- }
- /**
- * Panels Editor Cache Save.
- *
- * Method to allow modules to provide their own mechanism to write the
- * cache used in the display editor.
- */
- function panels_edit_cache_save($cache) {
- $cache_key = $cache->display->cache_key;
- if (strpos($cache_key, ':') !== FALSE) {
- list($module, $argument) = explode(':', $cache_key, 2);
- if (function_exists($module . '_panels_cache_save')) {
- return module_invoke($module, 'panels_cache_save', $argument, $cache);
- }
- }
- // Fall back to our normal method.
- return panels_save_display($cache->display);
- }
- /**
- * Panels Editor Cache Clear.
- *
- * Method to allow modules to provide their own mechanism to clear the
- * cache used in the display editor.
- */
- function panels_edit_cache_clear($cache) {
- $cache_key = $cache->display->cache_key;
- if (strpos($cache_key, ':') !== FALSE) {
- list($module, $argument) = explode(':', $cache_key, 2);
- if (function_exists($module . '_panels_cache_clear')) {
- return module_invoke($module, 'panels_cache_clear', $argument, $cache);
- }
- }
- // Fall back to our normal method.
- return panels_cache_clear('display', $cache_key);
- }
- /**
- * Method to allow modules to provide a mechanism to break locks.
- */
- function panels_edit_cache_break_lock($cache) {
- if (empty($cache->locked)) {
- return;
- }
- $cache_key = $cache->display->cache_key;
- if (strpos($cache_key, ':') !== FALSE) {
- list($module, $argument) = explode(':', $cache_key, 2);
- if (function_exists($module . '_panels_cache_break_lock')) {
- return module_invoke($module, 'panels_cache_break_lock', $argument, $cache);
- }
- }
- // Normal panel display editing has no locks, so we do nothing if there is
- // no fallback.
- }
- /**
- * Callbacks on behalf of the panel_context plugin.
- *
- * The panel_context plugin lets Panels be used in page manager. These
- * callbacks allow the display editing system to use the page manager
- * cache rather than the default display cache. They are routed by the cache
- * key via panels_edit_cache_* functions.
- */
- /**
- * Get display edit cache on behalf of panel context.
- *
- * The key is the second half of the key in this form:
- * panel_context:TASK_NAME::HANDLER_NAME::args::url;
- */
- function panel_context_panels_cache_get($key) {
- ctools_include('common', 'panels');
- ctools_include('context');
- ctools_include('context-task-handler');
- // This loads the panel context inc even if we don't use the plugin.
- $plugin = page_manager_get_task_handler('panel_context');
- list($task_name, $handler_name, $args, $q) = explode('::', $key, 4);
- $page = page_manager_get_page_cache($task_name);
- if (isset($page->display_cache[$handler_name])) {
- return $page->display_cache[$handler_name];
- }
- if ($handler_name) {
- $handler = &$page->handlers[$handler_name];
- }
- else {
- $handler = &$page->new_handler;
- }
- $cache = new stdClass();
- $task = page_manager_get_task($page->task_id);
- $arguments = array();
- if ($args) {
- $arguments = explode('\\', $args);
- $contexts = ctools_context_handler_get_task_contexts($task, $page->subtask, $arguments);
- $contexts = ctools_context_handler_get_handler_contexts($contexts, $handler);
- }
- else {
- $contexts = ctools_context_handler_get_all_contexts($page->task, $page->subtask, $handler);
- }
- $cache->display = &panels_panel_context_get_display($handler);
- $cache->display->context = $contexts;
- $cache->display->cache_key = 'panel_context:' . $key;
- $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
- $cache->display_title = TRUE;
- $cache->locked = $page->locked;
- return $cache;
- }
- /**
- * Get the Page Manager cache for the panel_context plugin.
- */
- function _panel_context_panels_cache_get_page_cache($key, $cache) {
- list($task_name, $handler_name, $args, $q) = explode('::', $key, 4);
- $page = page_manager_get_page_cache($task_name);
- $page->display_cache[$handler_name] = $cache;
- if ($handler_name) {
- $page->handlers[$handler_name]->conf['display'] = $cache->display;
- $page->handler_info[$handler_name]['changed'] |= PAGE_MANAGER_CHANGED_CACHED;
- }
- else {
- $page->new_handler->conf['display'] = $cache->display;
- }
- return $page;
- }
- /**
- * Store a display edit in progress in the page cache.
- */
- function panel_context_panels_cache_set($key, $cache) {
- $page = _panel_context_panels_cache_get_page_cache($key, $cache);
- page_manager_set_page_cache($page);
- }
- /**
- * Save all changes made to a display using the Page Manager page cache.
- */
- function panel_context_panels_cache_clear($key, $cache) {
- $page = _panel_context_panels_cache_get_page_cache($key, $cache);
- page_manager_clear_page_cache($page->task_name);
- }
- /**
- * Save all changes made to a display using the Page Manager page cache.
- */
- function panel_context_panels_cache_save($key, $cache) {
- $page = _panel_context_panels_cache_get_page_cache($key, $cache);
- page_manager_save_page_cache($page);
- }
- /**
- * Break the lock on a page manager page.
- */
- function panel_context_panels_cache_break_lock($key, $cache) {
- $page = _panel_context_panels_cache_get_page_cache($key, $cache);
- ctools_object_cache_clear_all('page_manager_page', $page->task_name);
- }
- /**
- * Callbacks on behalf of the panels page wizards.
- *
- * The page wizards are a pluggable set of 'wizards' to make it easy to create
- * specific types of pages based upon whatever someone felt like putting
- * together. Since they will very often have content editing, we provide
- * a generic mechanism to allow them to store their editing cache in the
- * wizard cache.
- *
- * For them to use this mechanism, they just need to use:
- * $cache = panels_edit_cache_get('panels_page_wizard:' . $plugin['name']);.
- */
- /**
- * Get display edit cache for the panels mini export UI.
- *
- * The key is the second half of the key in this form:
- * panels_page_wizard:TASK_NAME:HANDLER_NAME;
- */
- function panels_page_wizard_panels_cache_get($key) {
- ctools_include('page-wizard');
- ctools_include('context');
- $wizard_cache = page_manager_get_wizard_cache($key);
- if (isset($wizard_cache->display_cache)) {
- return $wizard_cache->display_cache;
- }
- ctools_include('common', 'panels');
- $cache = new stdClass();
- $cache->display = $wizard_cache->display;
- $cache->display->context = !empty($wizard_cache->context) ? $wizard_cache->context : array();
- $cache->display->cache_key = 'panels_page_wizard:' . $key;
- $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
- $cache->display_title = TRUE;
- return $cache;
- }
- /**
- * Store a display edit in progress in the page cache.
- */
- function panels_page_wizard_panels_cache_set($key, $cache) {
- ctools_include('page-wizard');
- $wizard_cache = page_manager_get_wizard_cache($key);
- $wizard_cache->display_cache = $cache;
- page_manager_set_wizard_cache($wizard_cache);
- }
- /**
- * Implements hook_default_page_manager_handlers_alter().
- *
- * If a default Panels display has no storage type, set it.
- */
- function panels_default_page_manager_handlers_alter(&$handlers) {
- foreach ($handlers as &$handler) {
- if ($handler->handler == 'panel_context') {
- $display =& $handler->conf['display'];
- if (empty($display->storage_type)) {
- $display->storage_type = 'page_manager';
- $display->storage_id = $handler->name;
- }
- }
- }
- }
- /**
- * Implements hook_default_page_manager_pages_alter().
- */
- function panels_default_page_manager_pages_alter(&$pages) {
- foreach ($pages as &$page) {
- panels_default_page_manager_handlers_alter($page->default_handlers);
- }
- }
- /**
- * General utility functions.
- */
- /**
- * Perform a drupal_goto on a destination that may be an array like url().
- */
- function panels_goto($destination) {
- if (!is_array($destination)) {
- return drupal_goto($destination);
- }
- else {
- // Prevent notices by adding defaults.
- $destination += array(
- 'query' => NULL,
- 'fragment' => NULL,
- 'http_response_code' => NULL,
- );
- return drupal_goto(
- $destination['path'],
- $destination['query'],
- $destination['fragment'],
- $destination['http_response_code']
- );
- }
- }
- /**
- * For external use: Given a layout ID and $content array, return panel display.
- *
- * The content array is filled in based upon the content available in the
- * layout. If it's a two column with a content array defined like.
- * @code
- * array(
- * 'left' => t('Left side'),
- * 'right' => t('Right side')
- * ),
- *
- * Then the $content array should be
- * @code
- * array(
- * 'left' => $output_left,
- * 'right' => $output_right,
- * )
- *
- * The output within each panel region can be either a single rendered
- * HTML string or an array of rendered HTML strings as though they were
- * panes. They will simply be concatenated together without separators.
- */
- function panels_print_layout($layout, $content, $meta = 'standard') {
- ctools_include('plugins', 'panels');
- // Create a temporary display for this.
- $display = panels_new_display();
- $display->layout = is_array($layout) ? $layout['name'] : $layout;
- $display->content = $content;
- // Get our simple renderer.
- $renderer = panels_get_renderer_handler('simple', $display);
- $renderer->meta_location = $meta;
- return $renderer->render();
- }
- /**
- * Filter callback for array_filter to remove builders from a list of layouts.
- */
- function _panels_builder_filter($layout) {
- return empty($layout['builder']);
- }
- /**
- * Implements hook_get_pane_links_alter().
- */
- function panels_get_pane_links_alter(&$links, $pane, $content_type) {
- // Add links to the Panels pane dropdown menu.
- if ($pane->type === "block") {
- $prefixed_name = $pane->subtype;
- // Breakup the subtype string into parts.
- $exploded_subtype = explode('-', $pane->subtype);
- // Get the first part of the string.
- $subtype_prefix = $exploded_subtype[0];
- // Get the first part of the string and add a hyphen.
- $subtype_prefix_hyphen = $exploded_subtype[0] . '-';
- // Remove the prefix block- to get the name.
- $name_of_block = ltrim($prefixed_name, $subtype_prefix_hyphen);
- // Check for user added menus created at /admin/structure/menu/add
- // menus of that type have a subtype that is prefixed with menu-menu-.
- if (substr($prefixed_name, 0, 10) === "menu-menu-") {
- // Remove the first prefix menu- from menu-menu- to get the name.
- $name_of_block = substr($prefixed_name, 5);
- $links['top'][] = array(
- 'title' => t('Edit block'),
- 'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
- 'attributes' => array('target' => array('_blank')),
- );
- $links['top'][] = array(
- 'title' => t('Edit menu links'),
- 'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
- 'attributes' => array('target' => array('_blank')),
- );
- }
- // Check for module provided menu blocks like Devels or Features
- // menus of that type have a subtype that is prefixed with menu-.
- elseif (substr($prefixed_name, 0, 5) === "menu-") {
- // Remove the first prefix menu- to get the name.
- $name_of_block = substr($prefixed_name, 5);
- $links['top'][] = array(
- 'title' => t('Edit block'),
- 'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
- 'attributes' => array('target' => array('_blank')),
- );
- $links['top'][] = array(
- 'title' => t('Edit menu links'),
- 'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
- 'attributes' => array('target' => array('_blank')),
- );
- }
- // Check for system blocks with menu links.
- elseif (substr($prefixed_name, 0, 7) === "system-") {
- // Remove the first prefix system- to get the name.
- $name_of_block = substr($prefixed_name, 7);
- $names_of_system_menus = menu_list_system_menus();
- $links['top'][] = array(
- 'title' => t('Edit block'),
- 'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
- 'attributes' => array('target' => array('_blank')),
- );
- if (array_key_exists($name_of_block, $names_of_system_menus)) {
- $links['top'][] = array(
- 'title' => t('Edit menu links'),
- 'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
- 'attributes' => array('target' => array('_blank')),
- );
- }
- }
- // For all other blocks without menus.
- else {
- $links['top'][] = array(
- 'title' => t('Edit block'),
- 'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
- 'attributes' => array('target' => array('_blank')),
- );
- }
- }
- }
- /**
- * Deprecated functions.
- *
- * Everything below this line will eventually go away.
- */
- /**
- * Panels path helper function.
- */
- function panels_get_path($file, $base_path = FALSE, $module = 'panels') {
- $output = $base_path ? base_path() : '';
- return $output . drupal_get_path('module', $module) . '/' . $file;
- }
- /**
- * Remove default sidebar related body classes and provide own css classes.
- */
- function panels_preprocess_html(&$vars) {
- $panel_body_css = &drupal_static('panel_body_css');
- if (!empty($panel_body_css['body_classes_to_remove'])) {
- $classes_to_remove = array_filter(explode(' ', $panel_body_css['body_classes_to_remove']), 'strlen');
- foreach ($vars['classes_array'] as $key => $css_class) {
- if (in_array($css_class, $classes_to_remove)) {
- unset($vars['classes_array'][$key]);
- }
- }
- }
- if (!empty($panel_body_css['body_classes_to_add'])) {
- $vars['classes_array'][] = check_plain($panel_body_css['body_classes_to_add']);
- }
- }
|