Beispiel #1
0
/**
 * Used to create a new stream
 *
 * @param {array} $_REQUEST 
 * @param {String} [$_REQUEST.title] Required. The title of the interest.
 * @param {String} [$_REQUEST.publisherId] Optional. Defaults to the app name.
 * @return {void}
 */
function Streams_interest_delete()
{
    $user = Users::loggedInUser(true);
    $title = Q::ifset($_REQUEST, 'title', null);
    if (!isset($title)) {
        throw new Q_Exception_RequiredField(array('field' => 'title'));
    }
    $app = Q_Config::expect('Q', 'app');
    $publisherId = Q::ifset($_REQUEST, 'publisherId', $app);
    $name = 'Streams/interest/' . Q_Utils::normalize($title);
    $stream = Streams::fetchOne(null, $publisherId, $name);
    if (!$stream) {
        throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => Q::json_encode(compact('publisherId', 'name'))));
    }
    $miPublisherId = $user->id;
    $miName = 'Streams/user/interests';
    $myInterests = Streams::fetchOne($user->id, $miPublisherId, $miName);
    if (!$myInterests) {
        throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => Q::json_encode(array('publisherId' => $miPublisherId, 'name' => $miName))));
    }
    $stream->leave();
    Streams::unrelate($user->id, $user->id, 'Streams/user/interests', 'Streams/interest', $publisherId, $name, array('adjustWeights' => true));
    Q_Response::setSlot('publisherId', $publisherId);
    Q_Response::setSlot('streamName', $name);
    /**
     * Occurs when the logged-in user has successfully removed an interest via HTTP
     * @event Streams/interest/delete {after}
     * @param {string} publisherId The publisher of the interest stream
     * @param {string} title The title of the interest
     * @param {Users_User} user The logged-in user
     * @param {Streams_Stream} stream The interest stream
     * @param {Streams_Stream} myInterests The user's "Streams/user/interests" stream
     */
    Q::event("Streams/interest/remove", compact('publisherId', 'title', 'subscribe', 'user', 'stream', 'myInterests'), 'after');
}
Beispiel #2
0
/**
 * Adds a label to the system. Fills the "label" (and possibly "icon") slot.
 * @param {array} $_REQUEST
 * @param {string} $_REQUEST.title The title of the label
 * @param {string} [$_REQUEST.label] You can override the label to use
 * @param {string} [$_REQUEST.icon] Optional path to an icon
 * @param {string} [$_REQUEST.userId=Users::loggedInUser(true)->id] You can override the user id, if another plugin adds a hook that allows you to do this
 */
function Users_label_post($params = array())
{
    $req = array_merge($_REQUEST, $params);
    Q_Request::requireFields(array('title'), $req, true);
    $loggedInUserId = Users::loggedInUser(true)->id;
    $userId = Q::ifset($req, 'userId', $loggedInUserId);
    $icon = Q::ifset($req, 'icon', null);
    $title = $req['title'];
    $l = Q::ifset($req, 'label', 'Users/' . Q_Utils::normalize($title));
    Users::canManageLabels($loggedInUserId, $userId, $l, true);
    $label = new Users_Label();
    $label->userId = $userId;
    $label->label = $l;
    if ($label->retrieve()) {
        throw new Users_Exception_LabelExists();
    }
    $label->title = $title;
    if (is_array($icon)) {
        // Process any icon that was posted
        $icon['path'] = 'uploads/Users';
        $icon['subpath'] = "{$userId}/label/{$label}/icon";
        $data = Q::event("Q/image/post", $icon);
        Q_Response::setSlot('icon', $data);
        $label->icon = Q_Request::baseUrl() . '/' . $data[''];
    } else {
        $label->icon = 'default';
    }
    $label->save();
    Q_Response::setSlot('label', $label->exportArray());
}
Beispiel #3
0
 static function _create($params, $options)
 {
     $title = Q_Utils::normalize($options['title']);
     $info = $params['info'];
     $options['name'] = "Places/interest/{$info['geohash']}/{$info['miles']}/{$title}";
     return Streams::create(null, $params['publisherId'], 'Places/interest', $options);
 }
Beispiel #4
0
/**
 * This tool contains functionality to show things in columns
 * @class Q columns
 * @constructor
 * @param {array}   [options] Provide options for this tool
 *  @param {array}  [options.animation] For customizing animated transitions
 *  @param {integer}  [options.animation.duration] The duration of the transition in milliseconds, defaults to 500
 *  @param {array}  [options.animation.hide] The css properties in "hide" state of animation
 *  @param {array}  [options.animation.show] The css properties in "show" state of animation
 *  @param {array}  [options.back] For customizing the back button on mobile
 *  @param {string}  [options.back.src] The src of the image to use for the back button
 *  @param {boolean} [options.back.triggerFromTitle] Whether the whole title would be a trigger for the back button. Defaults to true.
 *  @param {boolean} [options.back.hide] Whether to hide the back button. Defaults to false, but you can pass true on android, for example.
 *  @param {array}  [options.close] For customizing the back button on desktop and tablet
 *  @param {string}  [options.close.src] The src of the image to use for the close button
 *  @param {string}  [options.title] You can put a default title for all columns here (which is shown as they are loading)
 *  @param {string}  [options.column] You can put a default content for all columns here (which is shown as they are loading)
 *  @param {array}  [options.clickable] If not null, enables the Q/clickable tool with options from here. Defaults to null.
 *  @param {array}  [options.scrollbarsAutoHide] If not null, enables Q/scrollbarsAutoHide functionality with options from here. Enabled by default.
 *  @param {boolean} [options.fullscreen] Whether to use fullscreen mode on mobile phones, using document to scroll instead of relying on possibly buggy "overflow" CSS implementation. Defaults to true on Android, false everywhere else.
 *  @param {array}   [options.columns] In PHP only, an array of $name => $column pairs, where $column is in the form array('title' => $html, 'content' => $html, 'close' => true)
 * @return {string}
 */
function Q_columns_tool($options)
{
    $jsOptions = array('animation', 'back', 'close', 'title', 'scrollbarsAutoHide', 'fullscreen');
    Q_Response::setToolOptions(Q::take($options, $jsOptions));
    if (!isset($options['columns'])) {
        return '';
    }
    Q_Response::addScript('plugins/Q/js/tools/columns.js');
    Q_Response::addStylesheet('plugins/Q/css/columns.css');
    $result = '<div class="Q_columns_container Q_clearfix">';
    $columns = array();
    $i = 0;
    $closeSrc = Q::ifset($options, 'close', 'src', 'plugins/Q/img/x.png');
    $backSrc = Q::ifset($options, 'back', 'src', 'plugins/Q/img/back-v.png');
    foreach ($options['columns'] as $name => $column) {
        $close = Q::ifset($column, 'close', $i > 0);
        $Q_close = Q_Request::isMobile() ? 'Q_close' : 'Q_close Q_back';
        $closeHtml = !$close ? '' : (Q_Request::isMobile() ? '<div class="Q_close Q_back">' . Q_Html::img($backSrc, 'Back') . '</div>' : '<div class="Q_close">' . Q_Html::img($closeSrc, 'Close') . '</div>');
        $n = Q_Html::text($name);
        $columnClass = 'Q_column_' . Q_Utils::normalize($name) . ' Q_column_' . $i;
        if (isset($column['html'])) {
            $html = $column['html'];
            $columns[] = <<<EOT
\t<div class="Q_columns_column {$columnClass}" data-index="{$i}" data-name="{$n}">
\t\t{$html}
\t</div>
EOT;
        } else {
            $titleHtml = Q::ifset($column, 'title', '[title]');
            $columnHtml = Q::ifset($column, 'column', '[column]');
            $classes = $columnClass . ' ' . Q::ifset($column, 'class', '');
            $attrs = '';
            if (isset($column['data'])) {
                $json = Q::json_encode($column['data']);
                $attrs = 'data-more="' . Q_Html::text($json) . '"';
                foreach ($column['data'] as $k => $v) {
                    $attrs .= 'data-' . Q_Html::text($k) . '="' . Q_Html::text($v) . '" ';
                }
            }
            $data = Q::ifset($column, 'data', '');
            $columns[] = <<<EOT
\t<div class="Q_columns_column {$classes}" data-index="{$i}" data-name="{$n}" {$attrs}>
\t\t<div class="Q_columns_title">
\t\t\t{$closeHtml}
\t\t\t<h2 class="Q_title_slot">{$titleHtml}</h2>
\t\t</div>
\t\t<div class="Q_column_slot">{$columnHtml}</div>
\t</div>
EOT;
        }
        ++$i;
    }
    $result .= "\n" . implode("\n", $columns) . "\n</div>";
    return $result;
}
Beispiel #5
0
/**
 * Adds a label to the system. Fills the "label" (and possibly "icon") slot.
 * @param {array} $_REQUEST
 * @param {string} $_REQUEST.title The title of the label
 * @param {string} [$_REQUEST.label] You can override the label to use
 * @param {string} [$_REQUEST.icon] Optional path to an icon
 * @param {string} [$_REQUEST.userId=Users::loggedInUser(true)->id] You can override the user id, if another plugin adds a hook that allows you to do this
 */
function Users_label_post($params = array())
{
    $req = array_merge($_REQUEST, $params);
    Q_Request::requireFields(array('title'), $req, true);
    $loggedInUserId = Users::loggedInUser(true)->id;
    $userId = Q::ifset($req, 'userId', $loggedInUserId);
    $icon = Q::ifset($req, 'icon', null);
    $title = Q::ifset($req, 'title', null);
    $l = Q::ifset($req, 'label', 'Users/' . Q_Utils::normalize($title));
    $label = Users_Label::addLabel($l, $userId, $title, $icon);
    Q_Response::setSlot('label', $label->exportArray());
}
Beispiel #6
0
/**
 * Generates a form with inputs that modify various streams
 * @class Streams form
 * @constructor
 * @param {array} $options
 *  An associative array of parameters, containing:
 * @param {array} [$options.fields] an associative array of $id => $fieldinfo pairs,
 *   where $id is the id to append to the tool's id, to generate the input's id,
 *   and fieldinfo is either an associative array with the following fields,
 *   or a regular array consisting of fields in the following order:
 *     "publisherId" => Required. The id of the user publishing the stream
 *     "streamName" => Required. The name of the stream
 *     "field" => The stream field to edit, or "attribute:$attributeName" for an attribute.
 *     "input" => The type of the input (@see Q_Html::smartTag())
 *     "attributes" => Additional attributes for the input
 *     "options" => options for the input (if type is "select", "checkboxes" or "radios")
 *     "params" => array of extra parameters to Q_Html::smartTag
 */
function Streams_form_tool($options)
{
    $fields = Q::ifset($options, 'fields', array());
    $defaults = array('publisherId' => null, 'streamName' => null, 'field' => null, 'type' => 'text', 'attributes' => array(), 'value' => array(), 'options' => array(), 'params' => array());
    $sections = array();
    $hidden = array();
    $contents = '';
    foreach ($fields as $id => $field) {
        if (Q::isAssociative($field)) {
            $r = Q::take($field, $defaults);
        } else {
            $c = count($field);
            if ($c < 4) {
                throw new Q_Exception("Streams/form tool: field needs at least 4 values");
            }
            $r = array('publisherId' => $field[0], 'streamName' => $field[1], 'field' => $field[2], 'type' => $field[3], 'attributes' => isset($field[4]) ? $field[4] : array(), 'value' => isset($field[5]) ? $field[5] : '', 'options' => isset($field[6]) ? $field[6] : null, 'params' => isset($field[7]) ? $field[7] : null);
        }
        $r['attributes']['name'] = "input_{$id}";
        if (!isset($r['type'])) {
            var_dump($r['type']);
            exit;
        }
        $stream = Streams::fetchOne(null, $r['publisherId'], $r['streamName']);
        if ($stream) {
            if (substr($r['field'], 0, 10) === 'attribute:') {
                $attribute = trim(substr($r['field'], 10));
                $value = $stream->get($attribute, $r['value']);
            } else {
                $field = $r['field'];
                $value = $stream->{$field};
            }
        } else {
            $value = $r['value'];
        }
        $tag = Q_Html::smartTag($r['type'], $r['attributes'], $value, $r['options'], $r['params']);
        $class1 = 'publisherId_' . Q_Utils::normalize($r['publisherId']);
        $class2 = 'streamName_' . Q_Utils::normalize($r['streamName']);
        $contents .= "<span class='Q_before {$class1} {$class2}'></span>" . Q_Html::tag('span', array('data-publisherId' => $r['publisherId'], 'data-streamName' => $r['streamName'], 'data-field' => $r['field'], 'data-type' => $r['type'], 'class' => "{$class1} {$class2}"), $tag);
        $hidden[$id] = array(!!$stream, $r['publisherId'], $r['streamName'], $r['field']);
    }
    $contents .= Q_Html::hidden(array('inputs' => Q::json_encode($hidden)));
    return Q_Html::form('Streams/form', 'post', array(), $contents);
    //
    // $fields = array('onSubmit', 'onResponse', 'onSuccess', 'slotsToRequest', 'loader', 'contentElements');
    // Q_Response::setToolOptions(Q::take($options, $fields));
    // Q_Response::addScript('plugins/Q/js/tools/form.js');
    // Q_Response::addStylesheet('plugins/Q/css/form.css');
    // return $result;
}
Beispiel #7
0
/**
 * Removes a label from the system.
 * @param {array} $_REQUEST
 * @param {string} [$_REQUEST.title] Find it by title
 * @param {string} [$_REQUEST.label] Find it by label
 * @param {string} [$_REQUEST.userId=Users::loggedInUser(true)->id] You can override the user id, if another plugin adds a hook that allows you to do this
 */
function Users_label_delete($params = array())
{
    $req = array_merge($_REQUEST, $params);
    $loggedInUserId = Users::loggedInUser(true)->id;
    $userId = Q::ifset($req, 'userId', $loggedInUserId);
    $l = Q::ifset($req, 'label', null);
    if (!$l) {
        if ($title = Q::ifset($req, 'title', null)) {
            $l = 'Users/' . Q_Utils::normalize($title);
        } else {
            throw new Q_Exception_RequiredField(array('field' => 'label'));
        }
    }
    return !!Users_Label::removeLabel($l, $userId);
}
Beispiel #8
0
function Q_after_Q_tool_render($params, &$result)
{
    $info = $params['info'];
    $extra = $params['extra'];
    if (!is_array($extra)) {
        $extra = array();
    }
    $id_prefix = Q_Html::getIdPrefix();
    $tool_ids = Q_Html::getToolIds();
    $tag = Q::ifset($extra, 'tag', 'div');
    if (empty($tag)) {
        Q_Html::popIdPrefix();
        return;
    }
    $classes = '';
    $data_options = '';
    $count = count($info);
    foreach ($info as $name => $opt) {
        $classes = ($classes ? "{$classes} " : $classes) . implode('_', explode('/', $name)) . '_tool';
        $options = Q_Response::getToolOptions($name);
        if (isset($options)) {
            $friendly_options = str_replace(array('&quot;', '\\/'), array('"', '/'), Q_Html::text(Q::json_encode($options)));
        } else {
            $friendly_options = '';
        }
        $normalized = Q_Utils::normalize($name, '-');
        if (isset($options) or $count > 1) {
            $id = $tool_ids[$name];
            $id_string = $count > 1 ? "{$id} " : '';
            $data_options .= " data-{$normalized}='{$id_string}{$friendly_options}'";
        }
        $names[] = $name;
    }
    if (isset($extra['classes'])) {
        $classes .= ' ' . $extra['classes'];
    }
    $attributes = isset($extra['attributes']) ? ' ' . Q_Html::attributes($extra['attributes']) : '';
    $data_retain = !empty($extra['retain']) || Q_Response::shouldRetainTool($id_prefix) ? " data-Q-retain=''" : '';
    $data_replace = !empty($extra['replace']) || Q_Response::shouldReplaceWithTool($id_prefix) ? " data-Q-replace=''" : '';
    $names = $count === 1 ? ' ' . key($info) : 's ' . implode(" ", $names);
    $ajax = Q_Request::isAjax();
    $result = "<{$tag} id='{$id_prefix}tool' " . "class='Q_tool {$classes}'{$data_options}{$data_retain}{$data_replace}{$attributes}>" . "{$result}</{$tag}>";
    if (!Q_Request::isAjax()) {
        $result = "<!--\nbegin tool{$names}\n-->{$result}<!--\nend tool{$names} \n-->";
    }
    Q_Html::popIdPrefix();
}
Beispiel #9
0
 /**
  * Saves a file, usually sent by the client
  * @method save
  * @static
  * @param {array} $params 
  * @param {string} [$params.data] the file data
  * @param {string} [$params.path="uploads"] parent path under web dir (see subpath)
  * @param {string} [$params.subpath=""] subpath that should follow the path, to save the image under
  * @param {string} [$params.name] override the name of the file, after the subpath
  * @param {string} [$params.skipAccess=false] if true, skips the check for authorization to write files there
  * @param {boolean} [$params.audio] set this to true if the file is an audio file
  * @return {array} Returns array containing ($name => $tailUrl) pair
  */
 static function save($params)
 {
     if (empty($params['data'])) {
         throw new Q_Exception(array('field' => 'file'), 'data');
     }
     // check whether we can write to this path, and create dirs if needed
     $data = $params['data'];
     $audio = $params['audio'];
     $path = isset($params['path']) ? $params['path'] : 'uploads';
     $subpath = isset($params['subpath']) ? $params['subpath'] : '';
     $realPath = Q::realPath(APP_WEB_DIR . DS . $path);
     if ($realPath === false) {
         throw new Q_Exception_MissingFile(array('filename' => APP_WEB_DIR . DS . $path));
     }
     $name = isset($params['name']) ? $params['name'] : 'file';
     if (!preg_match('/^[\\w.-]+$/', $name)) {
         $info = pathinfo($name);
         $name = Q_Utils::normalize($info['filename']) . '.' . $info['extension'];
     }
     // TODO: recognize some extensions maybe
     $writePath = $realPath . ($subpath ? DS . $subpath : '');
     $lastChar = substr($writePath, -1);
     if ($lastChar !== DS and $lastChar !== '/') {
         $writePath .= DS;
     }
     $skipAccess = !empty($params['skipAccess']);
     Q_Utils::canWriteToPath($writePath, $skipAccess ? null : true, true);
     file_put_contents($writePath . $name, $data);
     $size = filesize($writePath . $name);
     $tailUrl = $subpath ? "{$path}/{$subpath}/{$name}" : "{$path}/{$name}";
     /**
      * @event Q/file/save {after}
      * @param {string} user the user
      * @param {string} path the path in the url
      * @param {string} subpath the subpath in the url
      * @param {string} name the actual name of the file
      * @param {string} writePath the actual folder where the path is written
      * @param {string} data the data written to the file
      * @param {string} tailUrl consists of $path/[$subpath/]$name
      * @param {integer} size the size of the file that was written
      * @param {boolean} skipAccess whether we are skipping access checks
      * @param {boolean} audio whether the file is audio
      */
     Q::event('Q/file/save', compact('path', 'subpath', 'name', 'writePath', 'data', 'tailUrl', 'size', 'skipAccess', 'audio'), 'after');
     return array($name => $tailUrl);
 }
Beispiel #10
0
 /**
  * Saves a file, usually sent by the client
  * @method save
  * @static
  * @param {array} $params 
  * @param {string} [$params.data] the file data
  * @param {string} [$params.path="uploads"] parent path under web dir (see subpath)
  * @param {string} [$params.subpath=""] subpath that should follow the path, to save the image under
  * @param {string} [$params.name] override the name of the file, after the subpath
  * @param {string} [$params.skipAccess=false] if true, skips the check for authorization to write files there
  * @return {array} Returns array containing ($name => $tailUrl) pair
  */
 static function save($params)
 {
     if (empty($params['data'])) {
         throw new Q_Exception(array('field' => 'file'), 'data');
     }
     // check whether we can write to this path, and create dirs if needed
     $data = $params['data'];
     $path = isset($params['path']) ? $params['path'] : 'uploads';
     $subpath = isset($params['subpath']) ? $params['subpath'] : '';
     $realPath = Q::realPath(APP_WEB_DIR . DS . $path);
     if ($realPath === false) {
         throw new Q_Exception_MissingFile(array('filename' => APP_WEB_DIR . DS . $path));
     }
     $name = isset($params['name']) ? $params['name'] : 'file';
     if (!preg_match('/^[\\w.-]+$/', $name)) {
         $info = pathinfo($name);
         $name = Q_Utils::normalize($info['filename']) . '.' . $info['extension'];
     }
     // TODO: recognize some extensions maybe
     $writePath = $realPath . ($subpath ? DS . $subpath : '');
     $lastChar = substr($writePath, -1);
     if ($lastChar !== DS and $lastChar !== '/') {
         $writePath .= DS;
     }
     $throwIfNotWritable = empty($params['skipAccess']) ? true : null;
     Q_Utils::canWriteToPath($writePath, $throwIfNotWritable, true);
     file_put_contents($writePath . DS . $name, $data);
     $tailUrl = $subpath ? "{$path}/{$subpath}/{$name}" : "{$path}/{$name}";
     /**
      * @event Q/file/save {after}
      * @param {string} user
      * @param {string} path
      * @param {string} subpath
      * @param {string} name
      * @param {string} writePath
      * @param {string} data
      */
     Q::event('Q/file/save', compact('path', 'subpath', 'name', 'writePath', 'data', 'tailUrl'), 'after');
     return array($name => $tailUrl);
 }
Beispiel #11
0
/**
 * Used to create a new stream
 *
 * @param {array} $_REQUEST 
 * @param {String} [$_REQUEST.title] Required. The title of the interest.
 * @param {String} [$_REQUEST.publisherId] Optional. Defaults to the app name.
 * @param {String} [$_REQUEST.subscribe] Optional. Defauls to false. Whether to subscribe rather than just join the interest stream.
 * @return {void}
 */
function Streams_interest_post()
{
    $user = Users::loggedInUser(true);
    $title = Q::ifset($_REQUEST, 'title', null);
    if (!isset($title)) {
        throw new Q_Exception_RequiredField(array('field' => 'title'));
    }
    $app = Q_Config::expect('Q', 'app');
    $publisherId = Q::ifset($_REQUEST, 'publisherId', $app);
    $name = 'Streams/interest/' . Q_Utils::normalize($title);
    $stream = Streams::fetchOne(null, $publisherId, $name);
    if (!$stream) {
        $stream = Streams::create($publisherId, $publisherId, 'Streams/interest', array('name' => $name, 'title' => $title));
        $parts = explode(': ', $title, 2);
        $keywords = implode(' ', $parts);
        try {
            $data = Q_Image::pixabay($keywords, array('orientation' => 'horizontal', 'min_width' => '500', 'safesearch' => 'true', 'image_type' => 'photo'), true);
        } catch (Exception $e) {
            Q::log("Exception during Streams/interest post: " . $e->getMessage());
            $data = null;
        }
        if (!empty($data)) {
            $sizes = Q_Config::expect('Streams', 'icons', 'sizes');
            ksort($sizes);
            $params = array('data' => $data, 'path' => "plugins/Streams/img/icons", 'subpath' => $name, 'save' => $sizes, 'skipAccess' => true);
            Q_Image::save($params);
            $stream->icon = $name;
        }
        $stream->save();
    }
    $subscribe = !!Q::ifset($_REQUEST, 'subscribe', false);
    if ($subscribe) {
        if (!$stream->subscription($user->id)) {
            $stream->subscribe();
        }
    } else {
        $stream->join();
    }
    $myInterestsName = 'Streams/user/interests';
    $myInterests = Streams::fetchOne($user->id, $user->id, $myInterestsName);
    if (!$myInterests) {
        $myInterests = new Streams_Stream();
        $myInterests->publisherId = $user->id;
        $myInterests->name = $myInterestsName;
        $myInterests->type = 'Streams/category';
        $myInterests->title = 'My Interests';
        $myInterests->save();
    }
    Streams::relate($user->id, $user->id, 'Streams/user/interests', 'Streams/interest', $publisherId, $name, array('weight' => '+1'));
    Q_Response::setSlot('publisherId', $publisherId);
    Q_Response::setSlot('streamName', $name);
    /**
     * Occurs when the logged-in user has successfully added an interest via HTTP
     * @event Streams/interest/post {after}
     * @param {string} publisherId The publisher of the interest stream
     * @param {string} title The title of the interest
     * @param {boolean} subscribe Whether the user subscribed to the interest stream
     * @param {Users_User} user The logged-in user
     * @param {Streams_Stream} stream The interest stream
     * @param {Streams_Stream} myInterests The user's "Streams/user/interests" stream
     */
    Q::event("Streams/interest/add", compact('publisherId', 'title', 'subscribe', 'user', 'stream', 'myInterests'), 'after');
}
Beispiel #12
0
 /**
  * Returns the HTML markup for referencing all the templates added so far
  * @method templates
  * @static
  * @param {string} [$slotName=null] If provided, returns only the templates added while filling this slot.
  * @param {string} [$between=''] Optional text to insert between the &lt;link&gt; tags.
  * @return {string} the HTML markup for referencing all the templates added so far
  */
 static function templates($slotName = null, $between = "\n")
 {
     $templates = self::templatesArray($slotName);
     if (empty($templates)) {
         return '';
     }
     $tags = array();
     foreach ($templates as $template) {
         $tags[] = Q_Html::script($template['content'], array('cdata' => false, 'raw' => true, 'type' => 'text/' . $template['type'], 'id' => Q_Utils::normalize($template['name']), 'data-slot' => $template['slot']));
     }
     return implode($between, $tags);
 }
Beispiel #13
0
/**
 * This tool renders tabs which behave appropriately in many different environments
 * @class Q tabs
 * @constructor
 * @param {array} [$options] options to pass to the tool
 *  @param {array} [$options.tabs] An associative array of name: title pairs.
 *  @param {array} [$options.urls] An associative array of name: url pairs to override the default urls.
 *  @param {string} [$options.field='tab'] Uses this field when urls doesn't contain the tab name.
 *  @param {boolean} [options.checkQueryString=false] Whether the default getCurrentTab should check the querystring when determining the current tab
 *  @param {boolean} [$options.vertical=false] Stack the tabs vertically instead of horizontally
 *  @param {boolean} [$options.compact=false] Display the tabs interface in a compact space with a contextual menu
 *  @param {Object} [$options.overflow]
 *  @param {String} [$options.overflow.content] The html that is displayed when the tabs overflow. You can interpolate {{count}}, {{text}} or {{html}} in the string. 
 *  @param {String} [$options.overflow.glyph] Override the glyph that appears next to the overflow text. You can interpolate {{count}} here
 *  @param {String} [$options.overflow.defaultText] The text to interpolate {{text}} in the content when no tab is selected
 *  @param {String} [$options.overflow.defaultHtml] The text to interpolate {{text}} in the content when no tab is selected
 *  @param {string} [$options.defaultTabName] Here you can specify the name of the tab to show by default
 *  @param {string} [$options.selectors] Array of (slotName => selector) pairs, where the values are CSS style selectors indicating the element to update with javascript, and can be a parent of the tabs. Set to null to reload the page.
 *  @param {string} [$options.slot] The name of the slot to request when changing tabs with javascript.
 *  @param {string} [$options.classes] An associative array of the form name => classes, for adding classes to tabs
 *  @param {string} [$options.titleClasses]  An associative array for adding classes to tab titles
 *  @param {string} [$options.after] Name of an event that will return HTML to place after the generated HTML in the tabs tool element
 *  @param {string} [$options.loader] Name of a function which takes url, slot, callback. It should call the callback and pass it an object with the response info. Can be used to implement caching, etc. instead of the default HTTP request. This function shall be Q.batcher getter
 *  @param {string} [$options.onClick] Event when a tab was clicked, with arguments (name, element). Returning false cancels the tab switching.
 *  @param {string} [$options.beforeSwitch] Event when tab switching begins. Returning false cancels the switching.
 *  @param {string} [$options.beforeScripts] Name of the function to execute after tab is loaded but before its javascript is executed.
 *  @param {string} [$options.onCurrent] Name of the function to execute after a tab is shown to be selected.
 *  @param {string} [$options.onActivate] Name of the function to execute after a tab is activated.
 */
function Q_tabs_tool($options)
{
    $field = 'tab';
    $slot = 'content,title';
    $selectors = array('content' => '#content_slot');
    $urls = array();
    extract($options);
    if (!isset($tabs)) {
        return '';
    }
    if (isset($overflow) and is_string($overflow)) {
        $overflow = array('content' => $overflow);
    }
    /**
     * @var array $tabs
     * @var boolean $vertical
     * @var boolean $compact
     */
    $sel = isset($_REQUEST[$field]) ? $_REQUEST[$field] : null;
    $result = '';
    $i = 0;
    $selectedName = null;
    $uri_string = (string) Q_Dispatcher::uri();
    foreach ($tabs as $name => $title) {
        if ($name === $sel or $name === $uri_string or $urls[$name] === $uri_string or $urls[$name] === Q_Request::url()) {
            $selectedName = $name;
            break;
        }
    }
    foreach ($tabs as $name => $title) {
        if (isset($urls[$name])) {
            $urls[$name] = Q_Uri::url($urls[$name]);
        } else {
            $urls[$name] = Q_Uri::url(Q_Request::url(array($field => $name, "/Q\\.(.*)/" => null)));
        }
        $selected_class = $name === $selectedName ? ' Q_current' : '';
        $classes_string = " Q_tab_" . Q_Utils::normalize($name);
        if (isset($classes[$name])) {
            if (is_string($classes[$name])) {
                $classes_string .= ' ' . $classes[$name];
            } else {
                if (is_array($classes[$name])) {
                    $classes_string .= ' ' . implode(' ', $classes[$name]);
                }
            }
        }
        $titleClasses_string = '';
        if (isset($titleClasses[$name])) {
            if (is_string($titleClasses[$name])) {
                $titleClasses_string = $titleClasses[$name];
            } else {
                if (is_array($titleClasses[$name])) {
                    $titleClasses_string = implode(' ', $titleClasses[$name]);
                }
            }
        }
        $title_container = Q_Html::div(null, "Q_tabs_title {$titleClasses_string}", isset($title) ? $title : $name);
        $result .= Q_Html::tag('li', array('id' => 'tab_' . ++$i, 'class' => "Q_tabs_tab {$classes_string}{$selected_class}", 'data-name' => $name), Q_Html::a($urls[$name], $title_container));
    }
    Q_Response::setToolOptions(compact('selectors', 'slot', 'urls', 'defaultTabName', 'vertical', 'compact', 'overflow', 'field', 'loader', 'beforeSwitch', 'beforeScripts', 'onActivate'));
    Q_Response::addScript('plugins/Q/js/tools/tabs.js');
    Q_Response::addStylesheet('plugins/Q/css/tabs.css');
    $classes = empty($vertical) ? ' Q_tabs_horizontal' : ' Q_tabs_vertical';
    if (!empty($compact)) {
        $classes .= " Q_tabs_compact";
    }
    $after = isset($options['after']) ? Q::event($options['after'], $options) : '';
    return "<ul class='Q_tabs_tabs Q_clearfix{$classes}'>{$result}{$after}</ul>";
}
Beispiel #14
0
 /**
  * Adds a stream to represent an area within a location.
  * Also may add streams to represent the floor and column.
  * @method addArea
  * @static
  * @param {Streams_Stream} $location The location stream
  * @param {string} $title The title of the area 
  * @param {string} [$floor] The number of the floor on which the area is located
  * @param {string} [$column] The name of the column on which the area is located
  * @param {array} [$options=array()] Any options to pass to Streams::create. Also can include:
  * @param {array} [$options.asUserId=null] Override the first parameter to Streams::create
  * @return {array} An array of ($area, $floor, $column)
  */
 static function addArea($location, $title, $floor = null, $column = null, $options = array())
 {
     $locationName = $location->name;
     $parts = explode('/', $locationName);
     $placeId = $parts[2];
     $asUserId = Q::ifset($options, 'asUserId', null);
     $publisherId = $location->publisherId;
     $skipAccess = Q::ifset($options, 'skipAccess', true);
     $floorName = isset($floor) ? "Places/floor/{$placeId}/" . Q_Utils::normalize($floor) : null;
     $columnName = isset($column) ? "Places/column/{$placeId}/" . Q_Utils::normalize($column) : null;
     $name = "Places/area/{$placeId}/" . Q_Utils::normalize($title);
     $area = Streams::fetchOne($asUserId, $publisherId, $name, $options);
     if (!$area) {
         $attributes = array('locationName' => $locationName, 'locationTitle' => $location->title, 'locationAddress' => $location->getAttribute('address'), 'floorName' => $floorName, 'columnName' => $columnName);
         $area = Streams::create($asUserId, $publisherId, 'Places/area', compact('name', 'title', 'skipAccess', 'attributes'));
         $area->relateTo($location, 'location', $asUserId, $options);
         if ($floorName) {
             $name = $floorName;
             $title = $location->title . " floor {$floor}";
             if (!($floor = Streams::fetchOne($asUserId, $publisherId, $name))) {
                 $floor = Streams::create($asUserId, $publisherId, 'Places/floor', compact('name', 'title', 'skipAccess'));
             }
             $area->relateTo($floor, 'floor', $asUserId, $options);
         }
         if ($columnName) {
             $name = $columnName;
             $title = $location->title . " column {$column}";
             if (!($column = Streams::fetchOne($asUserId, $publisherId, $name))) {
                 $column = Streams::create($asUserId, $publisherId, 'Places/column', compact('name', 'title', 'skipAccess'));
             }
             $area->relateTo($column, 'column', $asUserId, $options);
         }
     } else {
         $column = $columnName ? Streams::fetchOne($asUserId, $publisherId, $columnName) : null;
         $floor = $floorName ? Streams::fetchOne($asUserId, $publisherId, $floorName) : null;
     }
     return array($area, $floor, $column);
 }